Skip to content

Commit b4192b0

Browse files
jasnellrvagg
authored andcommitted
perf_hooks: add warning when too many entries in the timeline
PR-URL: #18087 Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent 531cb62 commit b4192b0

3 files changed

Lines changed: 88 additions & 4 deletions

File tree

‎doc/api/perf_hooks.md‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,20 @@ Creates a new `PerformanceMark` entry in the Performance Timeline. A
125125
`performanceEntry.duration` is always `0`. Performance marks are used
126126
to mark specific significant moments in the Performance Timeline.
127127

128+
### performance.maxEntries
129+
<!-- YAML
130+
added: REPLACEME
131+
-->
132+
133+
Value: {number}
134+
135+
The maximum number of Performance Entry items that should be added to the
136+
Performance Timeline. This limit is not strictly enforced, but a process
137+
warning will be emitted if the number of entries in the timeline exceeds
138+
this limit.
139+
140+
Defaults to 150.
141+
128142
### performance.measure(name, startMark, endMark)
129143
<!-- YAML
130144
added: v8.5.0

‎lib/perf_hooks.js‎

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ const kClearEntry = Symbol('clear-entry');
5353
constkGetEntries=Symbol('get-entries');
5454
constkIndex=Symbol('index');
5555
constkMarks=Symbol('marks');
56+
constkCount=Symbol('count');
57+
constkMaxCount=Symbol('max-count');
58+
constkDefaultMaxCount=150;
5659

5760
observerCounts[NODE_PERFORMANCE_ENTRY_TYPE_MARK]=1;
5861
observerCounts[NODE_PERFORMANCE_ENTRY_TYPE_MEASURE]=1;
@@ -250,20 +253,32 @@ const nodeTiming = new PerformanceNodeTiming();
250253
// Maintains a list of entries as a linked list stored in insertion order.
251254
classPerformanceObserverEntryList{
252255
constructor(){
253-
Object.defineProperty(this,kEntries,{
254-
writable: true,
255-
enumerable: false,
256-
value: {}
256+
Object.defineProperties(this,{
257+
[kEntries]: {
258+
writable: true,
259+
enumerable: false,
260+
value: {}
261+
},
262+
[kCount]: {
263+
writable: true,
264+
enumerable: false,
265+
value: 0
266+
}
257267
});
258268
L.init(this[kEntries]);
259269
}
260270

261271
[kInsertEntry](entry){
262272
constitem={ entry };
263273
L.append(this[kEntries],item);
274+
this[kCount]++;
264275
this[kIndexEntry](item);
265276
}
266277

278+
getlength(){
279+
returnthis[kCount];
280+
}
281+
267282
[kIndexEntry](entry){
268283
// Default implementation does nothing
269284
}
@@ -384,9 +399,22 @@ class Performance extends PerformanceObserverEntryList {
384399
this[kIndex]={
385400
[kMarks]: newSet()
386401
};
402+
this[kMaxCount]=kDefaultMaxCount;
387403
this[kInsertEntry](nodeTiming);
388404
}
389405

406+
setmaxEntries(val){
407+
if(typeofval!=='number'||val>>>0!==val){
408+
consterrors=lazyErrors();
409+
thrownewerrors.TypeError('ERR_INVALID_ARG_TYPE','val','number');
410+
}
411+
this[kMaxCount]=Math.max(1,val>>>0);
412+
}
413+
414+
getmaxEntries(){
415+
returnthis[kMaxCount];
416+
}
417+
390418
[kIndexEntry](item){
391419
constindex=this[kIndex];
392420
consttype=item.entry.entryType;
@@ -397,6 +425,17 @@ class Performance extends PerformanceObserverEntryList {
397425
}
398426
constentry=item.entry;
399427
L.append(items,{ entry, item });
428+
constcount=this[kCount];
429+
if(count>this[kMaxCount]){
430+
consttext=count===1 ? 'is 1 entry' : `are ${count} entries`;
431+
process.emitWarning('Possible perf_hooks memory leak detected. '+
432+
`There ${text} in the `+
433+
'Performance Timeline. Use the clear methods '+
434+
'to remove entries that are no longer needed or '+
435+
'set performance.maxEntries equal to a higher '+
436+
'value (currently the maxEntries is '+
437+
`${this[kMaxCount]}).`);
438+
}
400439
}
401440

402441
[kClearEntry](type,name){
@@ -411,10 +450,12 @@ class Performance extends PerformanceObserverEntryList {
411450
if(entry.name===`${name}`){
412451
L.remove(item);// remove from the index
413452
L.remove(item.item);// remove from the master
453+
this[kCount]--;
414454
}
415455
}else{
416456
L.remove(item);// remove from the index
417457
L.remove(item.item);// remove from the master
458+
this[kCount]--;
418459
}
419460
item=next;
420461
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Flags: --no-warnings
2+
'use strict';
3+
4+
constcommon=require('../common');
5+
const{ performance }=require('perf_hooks');
6+
constassert=require('assert');
7+
8+
assert.strictEqual(performance.length,1);
9+
assert.strictEqual(performance.maxEntries,150);
10+
11+
performance.maxEntries=1;
12+
13+
[-1,0xffffffff+1,'',null,undefined,Infinity].forEach((i)=>{
14+
common.expectsError(
15+
()=>performance.maxEntries=i,
16+
{
17+
code: 'ERR_INVALID_ARG_TYPE',
18+
type: TypeError
19+
}
20+
);
21+
});
22+
23+
common.expectWarning('Warning',[
24+
'Possible perf_hooks memory leak detected. There are 2 entries in the '+
25+
'Performance Timeline. Use the clear methods to remove entries that are no '+
26+
'longer needed or set performance.maxEntries equal to a higher value '+
27+
'(currently the maxEntries is 1).']);
28+
29+
performance.mark('test');

0 commit comments

Comments
 (0)