From 4004d4c9d021787b155354198d4e7dc73b33eb8a Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Wed, 21 Oct 2026 00:06:54 -0500 Subject: [PATCH] Answer 511 for an empty event-loop-delay histogram's percentiles Node creates monitorEventLoopDelay's histogram with a lowest discernible value of 1000 ns, so an empty histogram's percentile() returns 511, the highest value its first bucket holds. The runtime returned 0. 6397-event-loop-metrics.ts now skips a sampling window that has no recorded delta. A delta needs two samples after reset(), and a loop that wakes late runs only one sample in a window, so on a loaded machine the program printed an empty window under Node and compiled alike. The program also prints percentile(50) after each reset. --- packages/runtime/src/scr_perf_loop.c | 8 +++++++- tests/corpus/6397-event-loop-metrics.ts | 13 ++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/runtime/src/scr_perf_loop.c b/packages/runtime/src/scr_perf_loop.c index 68d3bf10f..57142b97b 100644 --- a/packages/runtime/src/scr_perf_loop.c +++ b/packages/runtime/src/scr_perf_loop.c @@ -274,10 +274,16 @@ void scr_eld_reset(double handle) { if (h != NULL) scr_eld_clear(h); } +/* Node's event-loop-delay histogram has a lowest discernible value of 1000 ns + * (Histogram::Options { 1000 }): its smallest bucket spans 0..511, so an empty + * histogram answers 511 for every percentile. Recorded deltas are at least the + * resolution (>= 1 ms), where that layout and this one share bucket bounds. */ +#define SCR_ELD_EMPTY_PERCENTILE 511 + /* hdr_value_at_percentile; the compiler checked Node's 0 < p <= 100 range. */ double scr_eld_percentile(double handle, double percentile) { ScrEld *h = scr_eld_of(handle); - if (h == NULL || h->total == 0) return 0; + if (h == NULL || h->total == 0) return SCR_ELD_EMPTY_PERCENTILE; double requested = percentile < 100.0 ? percentile : 100.0; int64_t wanted = (int64_t)((requested / 100.0) * (double)h->total + 0.5); if (wanted < 1) wanted = 1; diff --git a/tests/corpus/6397-event-loop-metrics.ts b/tests/corpus/6397-event-loop-metrics.ts index 8477dcc48..58c8083ac 100644 --- a/tests/corpus/6397-event-loop-metrics.ts +++ b/tests/corpus/6397-event-loop-metrics.ts @@ -15,6 +15,10 @@ let ticks = 0; // until the third sample. const keepAlive = setTimeout(() => console.log("never"), 10_000); const interval = setInterval(() => { + // A delta needs two samples after a reset. A loop that wakes late can run + // only one sample per window; that window is skipped without a reset, so + // the next one records. + if (histogram.count === 0) return; const now = performance.eventLoopUtilization(); const delta = performance.eventLoopUtilization(now, last); last = now; @@ -33,7 +37,14 @@ const interval = setInterval(() => { histogram.count > 0, ); histogram.reset(); - console.log("after reset", histogram.count, histogram.max, histogram.min, Number.isNaN(histogram.mean)); + console.log( + "after reset", + histogram.count, + histogram.max, + histogram.min, + Number.isNaN(histogram.mean), + histogram.percentile(50), + ); if (ticks === 3) { clearInterval(interval); clearTimeout(keepAlive);