From 2ec69955556bf92f49355659b6126e08fa2c3298 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Fri, 23 Mar 2018 11:23:22 -0700 Subject: perf_hooks: simplify perf_hooks Remove the `performance.getEntries()` and `performance.clear*()` variants and eliminate the accumulation of the global timeline entries. The design of this particular bit of the API is a memory leak and performance footgun. The `PerformanceObserver` API is a better approach to consuming the data in a more transient way. PR-URL: https://github.com/nodejs/node/pull/19563 Reviewed-By: Anna Henningsen Reviewed-By: Matteo Collina --- lib/perf_hooks.js | 101 ++++-------------------------------------------------- 1 file changed, 7 insertions(+), 94 deletions(-) (limited to 'lib/perf_hooks.js') diff --git a/lib/perf_hooks.js b/lib/perf_hooks.js index 7fa5501b28..9080cc7f26 100644 --- a/lib/perf_hooks.js +++ b/lib/perf_hooks.js @@ -3,6 +3,7 @@ const { PerformanceEntry, mark: _mark, + clearMark: _clearMark, measure: _measure, milestones, observerCounts, @@ -50,17 +51,11 @@ const kBuffering = Symbol('buffering'); const kQueued = Symbol('queued'); const kTimerified = Symbol('timerified'); const kInsertEntry = Symbol('insert-entry'); -const kIndexEntry = Symbol('index-entry'); -const kClearEntry = Symbol('clear-entry'); const kGetEntries = Symbol('get-entries'); const kIndex = Symbol('index'); const kMarks = Symbol('marks'); const kCount = Symbol('count'); -const kMaxCount = Symbol('max-count'); -const kDefaultMaxCount = 150; -observerCounts[NODE_PERFORMANCE_ENTRY_TYPE_MARK] = 1; -observerCounts[NODE_PERFORMANCE_ENTRY_TYPE_MEASURE] = 1; const observers = {}; const observerableTypes = [ 'node', @@ -286,17 +281,12 @@ class PerformanceObserverEntryList { const item = { entry }; L.append(this[kEntries], item); this[kCount]++; - this[kIndexEntry](item); } get length() { return this[kCount]; } - [kIndexEntry](entry) { - // Default implementation does nothing - } - [kGetEntries](name, type) { const ret = []; const list = this[kEntries]; @@ -407,72 +397,11 @@ class PerformanceObserver extends AsyncResource { } } -class Performance extends PerformanceObserverEntryList { +class Performance { constructor() { - super(); this[kIndex] = { [kMarks]: new Set() }; - this[kMaxCount] = kDefaultMaxCount; - this[kInsertEntry](nodeTiming); - } - - set maxEntries(val) { - if (typeof val !== 'number' || val >>> 0 !== val) { - const errors = lazyErrors(); - throw new errors.ERR_INVALID_ARG_TYPE('val', 'number', val); - } - this[kMaxCount] = Math.max(1, val >>> 0); - } - - get maxEntries() { - return this[kMaxCount]; - } - - [kIndexEntry](item) { - const index = this[kIndex]; - const type = item.entry.entryType; - let items = index[type]; - if (!items) { - items = index[type] = {}; - L.init(items); - } - const entry = item.entry; - L.append(items, { entry, item }); - const count = this[kCount]; - if (count > this[kMaxCount]) { - const text = count === 1 ? 'is 1 entry' : `are ${count} entries`; - process.emitWarning('Possible perf_hooks memory leak detected. ' + - `There ${text} in the ` + - 'Performance Timeline. Use the clear methods ' + - 'to remove entries that are no longer needed or ' + - 'set performance.maxEntries equal to a higher ' + - 'value (currently the maxEntries is ' + - `${this[kMaxCount]}).`); - } - } - - [kClearEntry](type, name) { - const index = this[kIndex]; - const items = index[type]; - if (!items) return; - let item = L.peek(items); - while (item && item !== items) { - const entry = item.entry; - const next = item._idlePrev; - if (name !== undefined) { - if (entry.name === `${name}`) { - L.remove(item); // remove from the index - L.remove(item.item); // remove from the master - this[kCount]--; - } - } else { - L.remove(item); // remove from the index - L.remove(item.item); // remove from the master - this[kCount]--; - } - item = next; - } } get nodeTiming() { @@ -507,27 +436,13 @@ class Performance extends PerformanceObserverEntryList { clearMarks(name) { name = name !== undefined ? `${name}` : name; - this[kClearEntry]('mark', name); - if (name !== undefined) + if (name !== undefined) { this[kIndex][kMarks].delete(name); - else + _clearMark(name); + } else { this[kIndex][kMarks].clear(); - } - - clearMeasures(name) { - this[kClearEntry]('measure', name); - } - - clearGC() { - this[kClearEntry]('gc'); - } - - clearFunctions(name) { - this[kClearEntry]('function', name); - } - - clearEntries(name) { - this[kClearEntry](name); + _clearMark(); + } } timerify(fn) { @@ -563,7 +478,6 @@ class Performance extends PerformanceObserverEntryList { [kInspect]() { return { - maxEntries: this.maxEntries, nodeTiming: this.nodeTiming, timeOrigin: this.timeOrigin }; @@ -595,7 +509,6 @@ function observersCallback(entry) { if (type === NODE_PERFORMANCE_ENTRY_TYPE_HTTP2) collectHttp2Stats(entry); - performance[kInsertEntry](entry); const list = getObserversList(type); let current = L.peek(list); -- cgit v1.2.3