Skip to content

perf_hooks: add histogram snapshot and diff - #66099

Open
jasnell wants to merge 3 commits into
nodejs:mainfrom
jasnell:jasnell/perf-hooks-histogram-snapshot
Open

jasnell wants to merge 3 commits into
nodejs:mainfrom
jasnell:jasnell/perf-hooks-histogram-snapshot

Conversation

@jasnell

@jasnell jasnell commented Sep 18, 2026

Copy link
Copy Markdown
Member

Cloning a histogram with structuredClone() or postMessage() shares
the native histogram instead of copying it. Capturing the state of a
histogram at a point in time, while other code keeps recording into
it, requires serializing it with export() and parsing the result
with importHistogram().

This adds histogram.snapshot() and `histogram.diff().

snapshot() returns a new, independent Histogram containing a
copy of the histogram's configuration, recorded values, exceeds
count, and EWMA state, without the serialization round trip. Values
cannot be recorded into the returned histogram. The method is
available on all histograms, including RecordableHistogram and
ELDHistogram instances.

diff() returns a new, independent Histogram containing the
delta between snapshots. This is useful for identifying what has
changed in an histogram between points in time.

@jasnell jasnell added semver-minor PRs that contain new features and should be released in the next minor version. perf_hooks Issues and PRs related to the perf_hooks module and performance measurement APIs. labels Sep 18, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/performance

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. lib / src Issues and PRs involving general changes in the lib/ or src/ directories. needs-ci PRs that need a full CI run. labels Sep 18, 2026
@jasnell
jasnell force-pushed the jasnell/perf-hooks-histogram-snapshot branch from ebdc07b to 2c4057d Compare September 18, 2026 03:35
Cloning a histogram with `structuredClone()` or `postMessage()` shares
the native histogram instead of copying it. Capturing the state of a
histogram at a point in time, while other code keeps recording into
it, requires serializing it with `export()` and parsing the result
with `importHistogram()`.

Add `histogram.snapshot()`, which returns a new, independent
`Histogram` containing a copy of the histogram's configuration,
recorded values, `exceeds` count, and EWMA state, without the
serialization round trip. Values cannot be recorded into the returned
histogram. The method is available on all histograms, including
`RecordableHistogram` and `ELDHistogram` instances.

Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: OpenCode
The native object behind histograms created by `createHistogram()`,
`importHistogram()`, and `snapshot()` did not report the memory of its
HDR histogram to V8. That memory is about 352 KiB with the default
options, and V8 did not take it into account when scheduling garbage
collection. Short-lived histograms could therefore hold on to a large
amount of native memory until an unrelated garbage collection: in a
loop taking 2,000 snapshots, RSS grew by 477 MiB.

Report the size of the native histogram while the object is alive, as
`SlidingWindowHistogram` already does for its chunks. Objects that
share a native histogram after cloning each report its full size.
With this change, RSS grows by 8 MiB in the same loop.

Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: OpenCode
Getting the values recorded during an interval requires calling
`reset()`, which removes them for every other user of the histogram,
or copying and subtracting histograms, which silently produces a wrong
result when the source was reset in between.

Add `histogram.diff(other)`, which returns a new read-only `Histogram`
containing the values recorded after `other`, an earlier snapshot of
the histogram, was taken. Neither histogram is changed. Unlike
`subtract()`, it verifies that both histograms have the same layout,
and it throws instead of clamping when `other` contains values that
the histogram does not.

Add `histogram.resetCount`, the number of calls to `reset()` and
`subtract()`, which `snapshot()` copies. `diff()` throws when the
counts differ, so a reset between two snapshots is detected even when
every bucket has since grown past its previous count.

Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: OpenCode
@jasnell
jasnell force-pushed the jasnell/perf-hooks-histogram-snapshot branch from 2c4057d to cbb0180 Compare September 18, 2026 03:45
@codecov

codecov Bot commented Sep 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.60759% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.28%. Comparing base (6a7f94c) to head (cbb0180).
⚠️ Report is 24 commits behind head on main.

Files with missing lines Patch % Lines
src/histogram.cc 84.34% 7 Missing and 11 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #66099      +/-   ##
==========================================
+ Coverage   90.27%   90.28%   +0.01%     
==========================================
  Files         790      790              
  Lines      271591   271738     +147     
  Branches    51829    51861      +32     
==========================================
+ Hits       245185   245352     +167     
+ Misses      16914    16878      -36     
- Partials     9492     9508      +16     
Files with missing lines Coverage Δ
lib/internal/histogram.js 97.32% <100.00%> (+0.10%) ⬆️
src/histogram-inl.h 95.09% <100.00%> (+0.15%) ⬆️
src/histogram.h 84.31% <ø> (ø)
src/histogram.cc 85.76% <84.34%> (+0.08%) ⬆️

... and 32 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jasnell
jasnell requested a review from mcollina September 18, 2026 13:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Issues and PRs that require attention from people who are familiar with C++. lib / src Issues and PRs involving general changes in the lib/ or src/ directories. needs-ci PRs that need a full CI run. perf_hooks Issues and PRs related to the perf_hooks module and performance measurement APIs. semver-minor PRs that contain new features and should be released in the next minor version.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants