node/lib/internal/perf/timerify.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

104 lines
1.9 KiB
JavaScript

'use strict';
const {
FunctionPrototypeBind,
ObjectDefineProperties,
ReflectApply,
ReflectConstruct,
Symbol,
} = primordials;
const {
InternalPerformanceEntry,
now,
} = require('internal/perf/perf');
const {
isConstructor,
} = internalBinding('util');
const {
codes: {
ERR_INVALID_ARG_TYPE,
},
} = require('internal/errors');
const {
enqueue,
} = require('internal/perf/observe');
const kTimerified = Symbol('kTimerified');
function processComplete(name, start, args) {
const duration = now() - start;
const entry =
new InternalPerformanceEntry(
name,
'function',
start,
duration,
args);
for (let n = 0; n < args.length; n++)
entry[n] = args[n];
enqueue(entry);
}
function timerify(fn) {
if (typeof fn !== 'function')
throw new ERR_INVALID_ARG_TYPE('fn', 'function', fn);
if (fn[kTimerified]) return fn[kTimerified];
const constructor = isConstructor(fn);
function timerified(...args) {
const start = now();
const result = constructor ?
ReflectConstruct(fn, args, fn) :
ReflectApply(fn, this, args);
if (!constructor && typeof result?.finally === 'function') {
return result.finally(
FunctionPrototypeBind(
processComplete,
result,
fn.name,
start,
args));
}
processComplete(fn.name, start, args);
return result;
}
ObjectDefineProperties(timerified, {
[kTimerified]: {
configurable: false,
enumerable: false,
value: timerified,
},
length: {
configurable: false,
enumerable: true,
value: fn.length,
},
name: {
configurable: false,
enumerable: true,
value: `timerified ${fn.name}`
}
});
ObjectDefineProperties(fn, {
[kTimerified]: {
configurable: false,
enumerable: false,
value: timerified,
}
});
return timerified;
}
module.exports = timerify;