perf_hooks: add warning when too many entries in the timeline
PR-URL: https://github.com/nodejs/node/pull/18087 Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
parent
6e312c5cc7
commit
6bcd31f2f4
@ -125,6 +125,20 @@ Creates a new `PerformanceMark` entry in the Performance Timeline. A
|
||||
`performanceEntry.duration` is always `0`. Performance marks are used
|
||||
to mark specific significant moments in the Performance Timeline.
|
||||
|
||||
### performance.maxEntries
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
Value: {number}
|
||||
|
||||
The maximum number of Performance Entry items that should be added to the
|
||||
Performance Timeline. This limit is not strictly enforced, but a process
|
||||
warning will be emitted if the number of entries in the timeline exceeds
|
||||
this limit.
|
||||
|
||||
Defaults to 150.
|
||||
|
||||
### performance.measure(name, startMark, endMark)
|
||||
<!-- YAML
|
||||
added: v8.5.0
|
||||
|
@ -53,6 +53,9 @@ 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;
|
||||
@ -250,10 +253,17 @@ const nodeTiming = new PerformanceNodeTiming();
|
||||
// Maintains a list of entries as a linked list stored in insertion order.
|
||||
class PerformanceObserverEntryList {
|
||||
constructor() {
|
||||
Object.defineProperty(this, kEntries, {
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
value: {}
|
||||
Object.defineProperties(this, {
|
||||
[kEntries]: {
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
value: {}
|
||||
},
|
||||
[kCount]: {
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
value: 0
|
||||
}
|
||||
});
|
||||
L.init(this[kEntries]);
|
||||
}
|
||||
@ -261,9 +271,14 @@ class PerformanceObserverEntryList {
|
||||
[kInsertEntry](entry) {
|
||||
const item = { entry };
|
||||
L.append(this[kEntries], item);
|
||||
this[kCount]++;
|
||||
this[kIndexEntry](item);
|
||||
}
|
||||
|
||||
get length() {
|
||||
return this[kCount];
|
||||
}
|
||||
|
||||
[kIndexEntry](entry) {
|
||||
// Default implementation does nothing
|
||||
}
|
||||
@ -384,9 +399,22 @@ class Performance extends PerformanceObserverEntryList {
|
||||
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.TypeError('ERR_INVALID_ARG_TYPE', 'val', 'number');
|
||||
}
|
||||
this[kMaxCount] = Math.max(1, val >>> 0);
|
||||
}
|
||||
|
||||
get maxEntries() {
|
||||
return this[kMaxCount];
|
||||
}
|
||||
|
||||
[kIndexEntry](item) {
|
||||
const index = this[kIndex];
|
||||
const type = item.entry.entryType;
|
||||
@ -397,6 +425,17 @@ class Performance extends PerformanceObserverEntryList {
|
||||
}
|
||||
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) {
|
||||
@ -411,10 +450,12 @@ class Performance extends PerformanceObserverEntryList {
|
||||
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;
|
||||
}
|
||||
|
29
test/parallel/test-performance-warning.js
Normal file
29
test/parallel/test-performance-warning.js
Normal file
@ -0,0 +1,29 @@
|
||||
// Flags: --no-warnings
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const { performance } = require('perf_hooks');
|
||||
const assert = require('assert');
|
||||
|
||||
assert.strictEqual(performance.length, 1);
|
||||
assert.strictEqual(performance.maxEntries, 150);
|
||||
|
||||
performance.maxEntries = 1;
|
||||
|
||||
[-1, 0xffffffff + 1, '', null, undefined, Infinity].forEach((i) => {
|
||||
common.expectsError(
|
||||
() => performance.maxEntries = i,
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
type: TypeError
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
common.expectWarning('Warning', [
|
||||
'Possible perf_hooks memory leak detected. There are 2 entries 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 1).']);
|
||||
|
||||
performance.mark('test');
|
Loading…
x
Reference in New Issue
Block a user