node/lib/internal/perf/nodetiming.js
James M Snell f3eb224c83
perf_hooks: complete overhaul of the implementation
* Update the user timing implementation to conform to
  User Timing Level 3.
* Reimplement user timing and timerify with pure JavaScript
  implementations
* Simplify the C++ implementation for gc and http2 perf
* Runtime deprecate additional perf entry properties
  in favor of the standard detail argument
* Disable the `buffered` option on PerformanceObserver,
  all entries are queued and dispatched on setImmediate.
  Only entries with active observers are buffered.
* This does remove the user timing and timerify
  trace events. Because the trace_events are still
  considered experimental, those can be removed without
  a deprecation cycle. They are removed to improve
  performance and reduce complexity.

Old: `perf_hooks/usertiming.js n=100000: 92,378.01249733355`
New: perf_hooks/usertiming.js n=100000: 270,393.5280638482`

PR-URL: https://github.com/nodejs/node/pull/37136
Refs: https://github.com/nodejs/diagnostics/issues/464
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
2021-02-22 08:46:11 -08:00

173 lines
3.5 KiB
JavaScript

'use strict';
const {
ObjectDefineProperties,
ObjectSetPrototypeOf,
SafeArrayIterator,
SafeSet,
} = primordials;
const {
PerformanceEntry,
kReadOnlyAttributes,
now,
} = require('internal/perf/perf');
const {
customInspectSymbol: kInspect,
} = require('internal/util');
const { inspect } = require('util');
const {
constants: {
NODE_PERFORMANCE_MILESTONE_NODE_START,
NODE_PERFORMANCE_MILESTONE_V8_START,
NODE_PERFORMANCE_MILESTONE_LOOP_START,
NODE_PERFORMANCE_MILESTONE_LOOP_EXIT,
NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE,
NODE_PERFORMANCE_MILESTONE_ENVIRONMENT
},
loopIdleTime,
milestones,
timeOrigin,
} = internalBinding('performance');
function getMilestoneTimestamp(milestoneIdx) {
const ns = milestones[milestoneIdx];
if (ns === -1)
return ns;
return ns / 1e6 - timeOrigin;
}
const readOnlyAttributes = new SafeSet(new SafeArrayIterator([
'nodeStart',
'v8Start',
'environment',
'loopStart',
'loopExit',
'bootstrapComplete',
]));
class PerformanceNodeTiming {
constructor() {
ObjectDefineProperties(this, {
name: {
enumerable: true,
configurable: true,
value: 'node'
},
entryType: {
enumerable: true,
configurable: true,
value: 'node'
},
startTime: {
enumerable: true,
configurable: true,
value: 0
},
duration: {
enumerable: true,
configurable: true,
get: now
},
nodeStart: {
enumerable: true,
configurable: true,
get() {
return getMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_NODE_START);
}
},
v8Start: {
enumerable: true,
configurable: true,
get() {
return getMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_V8_START);
}
},
environment: {
enumerable: true,
configurable: true,
get() {
return getMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_ENVIRONMENT);
}
},
loopStart: {
enumerable: true,
configurable: true,
get() {
return getMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_LOOP_START);
}
},
loopExit: {
enumerable: true,
configurable: true,
get() {
return getMilestoneTimestamp(NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
}
},
bootstrapComplete: {
enumerable: true,
configurable: true,
get() {
return getMilestoneTimestamp(
NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE);
}
},
idleTime: {
enumerable: true,
configurable: true,
get: loopIdleTime,
}
});
}
[kInspect](depth, options) {
if (depth < 0) return this;
const opts = {
...options,
depth: options.depth == null ? null : options.depth - 1
};
return `PerformanceNodeTiming ${inspect(this.toJSON(), opts)}`;
}
toJSON() {
return {
name: 'node',
entryType: 'node',
startTime: this.startTime,
duration: this.duration,
nodeStart: this.nodeStart,
v8Start: this.v8Start,
bootstrapComplete: this.bootstrapComplete,
environment: this.environment,
loopStart: this.loopStart,
loopExit: this.loopExit,
idleTime: this.idleTime,
};
}
static get [kReadOnlyAttributes]() {
return readOnlyAttributes;
}
}
ObjectSetPrototypeOf(
PerformanceNodeTiming.prototype,
PerformanceEntry.prototype);
module.exports = new PerformanceNodeTiming();