mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
perf_hooks: add histogram option to timerify
Allows setting a `Histogram` object option on timerify to record function execution times over time. Signed-off-by: James M Snell <jasnell@gmail.com> PR-URL: https://github.com/nodejs/node/pull/37475 Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
parent
9c1274a123
commit
b803bca4fa
@ -210,10 +210,13 @@ added: v8.5.0
|
||||
The [`timeOrigin`][] specifies the high resolution millisecond timestamp at
|
||||
which the current `node` process began, measured in Unix time.
|
||||
|
||||
### `performance.timerify(fn)`
|
||||
### `performance.timerify(fn[, options])`
|
||||
<!-- YAML
|
||||
added: v8.5.0
|
||||
changes:
|
||||
- version: REPLACEME
|
||||
pr-url: https://github.com/nodejs/node/pull/37475
|
||||
description: Added the histogram option.
|
||||
- version: REPLACEME
|
||||
pr-url: https://github.com/nodejs/node/pull/37136
|
||||
description: Re-implemented to use pure-JavaScript and the ability
|
||||
@ -221,6 +224,10 @@ changes:
|
||||
-->
|
||||
|
||||
* `fn` {Function}
|
||||
* `options` {Object}
|
||||
* `histogram` {RecordableHistogram} A histogram object created using
|
||||
`perf_hooks.createHistogram()` that will record runtime durations in
|
||||
nanoseconds.
|
||||
|
||||
_This property is an extension by Node.js. It is not available in Web browsers._
|
||||
|
||||
|
@ -42,6 +42,10 @@ const {
|
||||
JSTransferable,
|
||||
} = require('internal/worker/js_transferable');
|
||||
|
||||
function isHistogram(object) {
|
||||
return object?.[kHandle] !== undefined;
|
||||
}
|
||||
|
||||
class Histogram extends JSTransferable {
|
||||
constructor(internal) {
|
||||
super();
|
||||
@ -193,6 +197,7 @@ module.exports = {
|
||||
RecordableHistogram,
|
||||
InternalHistogram,
|
||||
InternalRecordableHistogram,
|
||||
isHistogram,
|
||||
kDestroy,
|
||||
kHandle,
|
||||
createHistogram,
|
||||
|
@ -3,6 +3,7 @@
|
||||
const {
|
||||
FunctionPrototypeBind,
|
||||
ObjectDefineProperties,
|
||||
MathCeil,
|
||||
ReflectApply,
|
||||
ReflectConstruct,
|
||||
Symbol,
|
||||
@ -13,6 +14,14 @@ const {
|
||||
now,
|
||||
} = require('internal/perf/perf');
|
||||
|
||||
const {
|
||||
validateObject
|
||||
} = require('internal/validators');
|
||||
|
||||
const {
|
||||
isHistogram
|
||||
} = require('internal/histogram');
|
||||
|
||||
const {
|
||||
isConstructor,
|
||||
} = internalBinding('util');
|
||||
@ -29,8 +38,10 @@ const {
|
||||
|
||||
const kTimerified = Symbol('kTimerified');
|
||||
|
||||
function processComplete(name, start, args) {
|
||||
function processComplete(name, start, args, histogram) {
|
||||
const duration = now() - start;
|
||||
if (histogram !== undefined)
|
||||
histogram.record(MathCeil(duration * 1e6));
|
||||
const entry =
|
||||
new InternalPerformanceEntry(
|
||||
name,
|
||||
@ -45,10 +56,23 @@ function processComplete(name, start, args) {
|
||||
enqueue(entry);
|
||||
}
|
||||
|
||||
function timerify(fn) {
|
||||
function timerify(fn, options = {}) {
|
||||
if (typeof fn !== 'function')
|
||||
throw new ERR_INVALID_ARG_TYPE('fn', 'function', fn);
|
||||
|
||||
validateObject(options, 'options');
|
||||
const {
|
||||
histogram
|
||||
} = options;
|
||||
|
||||
if (histogram !== undefined &&
|
||||
(!isHistogram(histogram) || typeof histogram.record !== 'function')) {
|
||||
throw new ERR_INVALID_ARG_TYPE(
|
||||
'options.histogram',
|
||||
'RecordableHistogram',
|
||||
histogram);
|
||||
}
|
||||
|
||||
if (fn[kTimerified]) return fn[kTimerified];
|
||||
|
||||
const constructor = isConstructor(fn);
|
||||
@ -65,9 +89,10 @@ function timerify(fn) {
|
||||
result,
|
||||
fn.name,
|
||||
start,
|
||||
args));
|
||||
args,
|
||||
histogram));
|
||||
}
|
||||
processComplete(fn.name, start, args);
|
||||
processComplete(fn.name, start, args, histogram);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -4,10 +4,15 @@ const common = require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
const {
|
||||
createHistogram,
|
||||
performance,
|
||||
PerformanceObserver
|
||||
} = require('perf_hooks');
|
||||
|
||||
const {
|
||||
setTimeout: sleep
|
||||
} = require('timers/promises');
|
||||
|
||||
{
|
||||
// Intentional non-op. Do not wrap in common.mustCall();
|
||||
const n = performance.timerify(function noop() {});
|
||||
@ -81,3 +86,38 @@ const {
|
||||
assert.strictEqual(n.length, m.length);
|
||||
assert.strictEqual(n.name, 'timerified m');
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const histogram = createHistogram();
|
||||
const m = (a, b = 1) => {};
|
||||
const n = performance.timerify(m, { histogram });
|
||||
assert.strictEqual(histogram.max, 0);
|
||||
for (let i = 0; i < 10; i++) {
|
||||
n();
|
||||
await sleep(10);
|
||||
}
|
||||
assert.notStrictEqual(histogram.max, 0);
|
||||
[1, '', {}, [], false].forEach((histogram) => {
|
||||
assert.throws(() => performance.timerify(m, { histogram }), {
|
||||
code: 'ERR_INVALID_ARG_TYPE'
|
||||
});
|
||||
});
|
||||
})().then(common.mustCall());
|
||||
|
||||
(async () => {
|
||||
const histogram = createHistogram();
|
||||
const m = async (a, b = 1) => {
|
||||
await sleep(10);
|
||||
};
|
||||
const n = performance.timerify(m, { histogram });
|
||||
assert.strictEqual(histogram.max, 0);
|
||||
for (let i = 0; i < 10; i++) {
|
||||
await n();
|
||||
}
|
||||
assert.notStrictEqual(histogram.max, 0);
|
||||
[1, '', {}, [], false].forEach((histogram) => {
|
||||
assert.throws(() => performance.timerify(m, { histogram }), {
|
||||
code: 'ERR_INVALID_ARG_TYPE'
|
||||
});
|
||||
});
|
||||
})().then(common.mustCall());
|
||||
|
Loading…
Reference in New Issue
Block a user