Description
Version
v14, v16, v17, v18
Platform
macOS v12.4 (21F79).
Darwin 21.5.0 Darwin Kernel Version 21.5.0: Tue Apr 26 21:08:37 PDT 2022; root:xnu-8020.121.3~4/RELEASE_ARM64_T6000 arm64
Subsystem
perf_hooks
What steps will reproduce the bug?
Run this snippet:
import {createHistogram, performance} from 'node:perf_hooks';
const fn = () => {};
const timerified = performance.timerify(fn, {histogram: createHistogram()});
for (let i = 0; i < 100_000; i++) {
try {
timerified();
} catch (error) {
console.error('Crashed on iteration', i);
throw error;
}
}
How often does it reproduce? Is there a required condition?
100% consistent reproduction, requires arm64, maybe requires macOS.
What is the expected behavior?
Calling the timerified function returned from perf_hooks.performance.timerify()
should successfully record to the histogram.
What do you see instead?
node:internal/errors:466
ErrorCaptureStackTrace(err);
^
RangeError [ERR_OUT_OF_RANGE]: The value of "val" is out of range. It must be a safe integer greater than 0. Received 0
at new NodeError (node:internal/errors:377:5)
at RecordableHistogram.record (node:internal/histogram:290:13)
at processComplete (node:internal/perf/timerify:40:15)
at timerified fn (node:internal/perf/timerify:88:5)
at file:///Users/jonah/programming/benchmark/index.mjs:9:3
at ModuleJob.run (node:internal/modules/esm/module_job:198:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:409:24)
at async loadESM (node:internal/process/esm_loader:85:5)
at async handleMainPromise (node:internal/modules/run_main:61:12) {
code: 'ERR_OUT_OF_RANGE'
}
Node.js v18.1.0
Additional information
Originally reported here: sindresorhus/yoctocolors#9 (comment)
The bug appears to be from the implementation of perf_hooks.performance.timerify()
with a histogram, when calling the returned timerified function. The error comes from the input validation of RecordableHistogram#record()
, attempting to record a value x < 1
will throw. For whatever reason timerify()
seems to be recording an execution duration of 0 and trying to record that. See the error stacktrace for more info.