Skip to content

Reduce time profiler memory usage with lazy profile tree - #287

Merged
IlyasShabi merged 9 commits into
mainfrom
ishabi/lazy-time-profiler
Mar 10, 2026
Merged

Reduce time profiler memory usage with lazy profile tree#287
IlyasShabi merged 9 commits into
mainfrom
ishabi/lazy-time-profiler

Conversation

@IlyasShabi

@IlyasShabiIlyasShabi commented Mar 2, 2026

Copy link
Copy Markdown

What does this PR do?:
Introduces a new stopAndCollect function for the time profiler that reduces memory usage during profile serialization. Instead of materializing the entire V8 CPU profile tree as JS objects upfront, the new API resolves children on demand using getters.

This also moves totalHitCount() computation to C++ instead of TS to avoid getting children twice from C++

Motivation:
The current stop() API recursively translates the entire profile tree into JS objects, creating a full copy in heap memory which can be significant for large applications.
The new stopAndCollect() API uses a callback to keep the V8 profile alive while the TS serializer traverses the tree lazily.
Scalar properties are set at creation time, but children are resolved on first access, reducing peak memory usage.

Additional Notes:

  • Similar to heap profiling
  • Benchmark on CI shows:
* ~99% on initial load which normal since we are not materializing the profiler to JS objects.
* ~52% after traversing the profiler tree to explicitly call getters.
* ~58% after calling afterHitCount() which is moved to c++.

How to test the change?:
Unit tests

@IlyasShabiIlyasShabi added the semver-patch Bug or security fixes, mainly label Mar 2, 2026
@github-actions

github-actionsBot commented Mar 2, 2026

Copy link
Copy Markdown

Overall package size

Self size: 1.98 MB
Deduped: 2.34 MB
No deduping: 2.34 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | source-map | 0.7.6 | 185.63 kB | 185.63 kB | | pprof-format | 2.2.1 | 163.06 kB | 163.06 kB | | node-gyp-build | 3.9.0 | 8.81 kB | 8.81 kB |

🤖 This report was automatically generated by heaviest-objects-in-the-universe

@IlyasShabi
IlyasShabiforce-pushed the ishabi/lazy-time-profiler branch from 216d01f to 0d480d5CompareMarch 3, 2026 14:45
@pr-commenter

pr-commenterBot commented Mar 3, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-03-10 13:04:35

Comparing candidate commit 5434977 in PR branch ishabi/lazy-time-profiler with baseline commit 2db9741 in branch main.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 91 metrics, 29 unstable metrics.

@IlyasShabi
IlyasShabiforce-pushed the ishabi/lazy-time-profiler branch from 9881a82 to 0e5f1dcCompareMarch 3, 2026 19:10
@IlyasShabi
IlyasShabiforce-pushed the ishabi/lazy-time-profiler branch 6 times, most recently from 7ee93d7 to b617efbCompareMarch 4, 2026 15:02
@IlyasShabi
IlyasShabiforce-pushed the ishabi/lazy-time-profiler branch from b617efb to c4d4158CompareMarch 4, 2026 19:58
@IlyasShabi
IlyasShabi marked this pull request as ready for review March 4, 2026 21:05
@IlyasShabi

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:3a567e03d1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadbindings/translate-time-profile.cc Outdated

@szegediszegedi left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, great work. I'm sorry you had to go through all that trouble for supporting line-info. I have two refactoring suggestions to reduce code duplication between two modes of stopping.

Comment on lines +202 to +218
if (restart) {
gV8ProfilerStuckEventLoopDetected =
gProfiler.v8ProfilerStuckEventLoopDetected();
if (gV8ProfilerStuckEventLoopDetected > 0) {
gProfiler.stop(false);
gProfiler.start();
}
} else {
gV8ProfilerStuckEventLoopDetected = 0;
gProfiler.dispose();
gProfiler = undefined;
gSourceMapper = undefined;
if (gStore !== undefined) {
gStore.disable();
gStore = undefined;
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could extract these into two module-private functions (the way they are in the original stop method) and call these functions instead, to reduce some code duplication.

Comment threadbindings/profilers/wall.cc Outdated
Comment on lines +1103 to +1105
Result WallProfiler::StopAndCollectImpl(bool restart,
v8::Local<v8::Function> callback,
v8::Local<v8::Value>& result) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is very similar to ::Stop. I had Claude extract the common code from the two to see if it can be done; I put it up as a draft PR here. Feel free to incorporate the commit here, I just put the PR up for the ease of review.

@IlyasShabi

Copy link
Copy Markdown
Author

@szegedi Thanks for your suggestions! I actually preferred not to use shared helper functions for the duplicated code because the upcoming PR will remove the old stop function, but I’m also fine with this approach.

@szegediszegedi left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, 🚢 it!

@IlyasShabi
IlyasShabi merged commit bd5ca5d into mainMar 10, 2026
67 checks passed
@IlyasShabi
IlyasShabi deleted the ishabi/lazy-time-profiler branch March 10, 2026 17:31
@szegediszegedi mentioned this pull request Mar 13, 2026
szegedi pushed a commit that referenced this pull request Mar 18, 2026
Reduce time profiler memory usage with lazy profile tree
szegedi pushed a commit that referenced this pull request Mar 18, 2026
Reduce time profiler memory usage with lazy profile tree
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

semver-patchBug or security fixes, mainly

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@IlyasShabi@szegedi