From 692a3a87e384901b388d26c1af51bb515bce9b32 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Fri, 18 Sep 2026 19:16:16 +0000 Subject: [PATCH 1/4] perf_hooks: fix truncation of monitorEventLoopDelay() resolution `IntervalHistogram` stored the interval as `int32_t`, so a resolution above 2^31 - 1 ms wrapped: `resolution: 2 ** 32 + 1` sampled every millisecond. Signed-off-by: James M Snell Assisted-by: OpenCode --- src/histogram.cc | 4 +-- src/histogram.h | 6 ++-- ...oks-monitor-event-loop-delay-resolution.js | 31 +++++++++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 test/parallel/test-perf-hooks-monitor-event-loop-delay-resolution.js diff --git a/src/histogram.cc b/src/histogram.cc index eb7fd575c984..79e539f18731 100644 --- a/src/histogram.cc +++ b/src/histogram.cc @@ -2616,7 +2616,7 @@ void IntervalHistogram::RegisterExternalReferences( IntervalHistogram::IntervalHistogram(Environment* env, Local wrap, AsyncWrap::ProviderType type, - int32_t interval, + uint64_t interval, OnInterval on_interval, const Histogram::Options& options) : HandleWrap(env, wrap, reinterpret_cast(&timer_), type), @@ -2633,7 +2633,7 @@ IntervalHistogram::IntervalHistogram(Environment* env, BaseObjectPtr IntervalHistogram::Create( Environment* env, - int32_t interval, + uint64_t interval, OnInterval on_interval, const Histogram::Options& options, AsyncWrap::ProviderType type) { diff --git a/src/histogram.h b/src/histogram.h index 93fe2b267d46..1a07f93ba992 100644 --- a/src/histogram.h +++ b/src/histogram.h @@ -499,7 +499,7 @@ class IntervalHistogram final : public HandleWrap, static BaseObjectPtr Create( Environment* env, - int32_t interval, + uint64_t interval, OnInterval on_interval, const Histogram::Options& options, AsyncWrap::ProviderType type = AsyncWrap::PROVIDER_ELDHISTOGRAM); @@ -507,7 +507,7 @@ class IntervalHistogram final : public HandleWrap, IntervalHistogram(Environment* env, v8::Local wrap, AsyncWrap::ProviderType type, - int32_t interval, + uint64_t interval, OnInterval on_interval, const Histogram::Options& options = Histogram::Options{}); @@ -534,7 +534,7 @@ class IntervalHistogram final : public HandleWrap, template friend void StopHandleHistogram(v8::Local); - int32_t interval_ = 0; + uint64_t interval_ = 0; OnInterval on_interval_ = nullptr; uv_timer_t timer_; diff --git a/test/parallel/test-perf-hooks-monitor-event-loop-delay-resolution.js b/test/parallel/test-perf-hooks-monitor-event-loop-delay-resolution.js new file mode 100644 index 000000000000..f0402524e7c4 --- /dev/null +++ b/test/parallel/test-perf-hooks-monitor-event-loop-delay-resolution.js @@ -0,0 +1,31 @@ +'use strict'; + +// Tests that monitorEventLoopDelay() does not truncate a resolution greater +// than 2 ** 31 - 1 milliseconds to 32 bits. + +const common = require('../common'); +const assert = require('assert'); +const { monitorEventLoopDelay } = require('perf_hooks'); + +// Truncated to 32 bits, this resolution would be 1 ms. +const histogram = monitorEventLoopDelay({ resolution: 2 ** 32 + 1 }); +const control = monitorEventLoopDelay({ resolution: 1 }); +histogram.enable(); +control.enable(); + +const done = common.mustCall(() => { + histogram.disable(); + control.disable(); + // The first sample is recorded after two timer callbacks, which for this + // resolution is roughly 99 days after enable(). + assert.strictEqual(histogram.count, 0); + assert.strictEqual(histogram.exceeds, 0); +}); + +(function wait() { + if (control.count >= 10) { + done(); + } else { + setTimeout(wait, 2); + } +})(); From 468ca5cd4171ea92f55d952700385d619ab6a3b3 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Fri, 18 Sep 2026 19:17:20 +0000 Subject: [PATCH 2/4] doc: fix description of histogram.exceeds It counts values above the highest recordable value, for every histogram type. Event loop delay histograms no longer have a 1 hour limit. Signed-off-by: James M Snell Refs: https://github.com/nodejs/node/pull/41153 Assisted-by: OpenCode --- doc/api/perf_hooks.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/api/perf_hooks.md b/doc/api/perf_hooks.md index f9533c1260aa..8dfb47663d3a 100644 --- a/doc/api/perf_hooks.md +++ b/doc/api/perf_hooks.md @@ -2253,8 +2253,8 @@ added: v11.10.0 * Type: {number} -The number of times the event loop delay exceeded the maximum 1 hour event -loop delay threshold. +The number of values that were not recorded because they exceeded the +histogram's highest recordable value. ### `histogram.exceedsBigInt` @@ -2266,8 +2266,8 @@ added: * Type: {bigint} -The number of times the event loop delay exceeded the maximum 1 hour event -loop delay threshold. +The number of values that were not recorded because they exceeded the +histogram's highest recordable value. ### `histogram.export()` From 4fee9585c68327a641543874626434d6f478a95d Mon Sep 17 00:00:00 2001 From: James M Snell Date: Fri, 18 Sep 2026 19:31:36 +0000 Subject: [PATCH 3/4] perf_hooks: add range options to monitorEventLoopDelay() Accept `lowest`, `highest`, and `figures`, as `createHistogram()` does. The defaults are unchanged, and use up to 432 KiB per histogram. Signed-off-by: James M Snell Assisted-by: OpenCode --- doc/api/perf_hooks.md | 23 ++ lib/internal/histogram.js | 2 + lib/internal/perf/event_loop_delay.js | 30 ++- src/histogram.cc | 17 +- src/histogram.h | 8 +- src/node_perf.cc | 38 +++- ...oks-monitor-event-loop-delay-fast-calls.js | 2 +- ...-hooks-monitor-event-loop-delay-options.js | 213 ++++++++++++++++++ typings/internalBinding/performance.d.ts | 3 + 9 files changed, 313 insertions(+), 23 deletions(-) create mode 100644 test/parallel/test-perf-hooks-monitor-event-loop-delay-options.js diff --git a/doc/api/perf_hooks.md b/doc/api/perf_hooks.md index 8dfb47663d3a..13d77941c6e5 100644 --- a/doc/api/perf_hooks.md +++ b/doc/api/perf_hooks.md @@ -1926,6 +1926,9 @@ are not guaranteed to reflect any correct state of the event loop.