Skip to content

feat(jitdump): recover V8 inlined frames from the V8 code log#10

Open
GuillaumeLagrange wants to merge 1 commit into
cod-2889-fix-go-flamegraphs-with-samplyfrom
cod-2821-v8-maglevturbofan-inlining-loses-nested-inline-information
Open

feat(jitdump): recover V8 inlined frames from the V8 code log#10
GuillaumeLagrange wants to merge 1 commit into
cod-2889-fix-go-flamegraphs-with-samplyfrom
cod-2821-v8-maglevturbofan-inlining-loses-nested-inline-information

Conversation

@GuillaumeLagrange

@GuillaumeLagrange GuillaumeLagrange commented Jun 18, 2026

Copy link
Copy Markdown

V8's jitdump (--perf-prof) records only the innermost inlined source
position per PC, so a sampling profiler collapses an inlined chain
root->a->b->c down to a single `root` frame for both TurboFan and Maglev
(COD-2821; Maglev needs COD-2820).

The full inline tree is emitted, with no node/V8 fork, to the code log's
`code-source-info` records (positions + inlining_positions +
inlined_functions), which use the same runtime code addresses as the
jitdump.

- v8_inline.rs: parse that log into a per-code-object inline map (keyed on
  address + size, since V8 reuses freed code addresses over a run) and
  reconstruct the inline stack via the SourcePosition::InliningStack walk.
- jitdump.rs: resolve the producing process's log as
  $CODSPEED_V8_LOG/codspeed-v8-<pid>.log from the jitdump header pid, then
  expand a single jitdump frame into the full inline stack, innermost
  first, with the code object's own frame appended last so a non-inlined
  hit resolves exactly as before. Falls back to the single-frame path when
  no log is found.

Refs COD-2821

Generated with AI Agent (Claude Code)

@not-matthias not-matthias left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM overall. I think the code readability can be improved a bit by:

  • Dropping the references to COD-2821 (I didn't comment for all, so pls search for other references)
  • Removing 1-3 letter variables by either renaming them or creating a struct (I think I prefer the latter)

index: JitDumpIndex,
/// Inline map from the V8 code log of the process that produced this
/// jitdump, used to expand TurboFan/Maglev inlined frames that the jitdump
/// itself collapses (COD-2821). `None` when no log was found.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd drop the (COD-2821) here, it's already included in the commit/branch.

//!
//! V8's jitdump records only the *innermost* inlined source position per PC, so
//! a sampling profiler collapses an inlined chain `root -> a -> b -> c` down to
//! just `root` (COD-2821). The full inline tree is instead present in the code

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

drop (COD-2821)

/// `(code_offset, script_offset, inlining_id)`, sorted ascending by code_offset.
positions: Vec<(u32, u32, Option<u32>)>,
/// `code-source-info` inlining tree: `(inlined_function_id, call_site_script_offset, parent_inlining_id)`.
inl_pos: Vec<(i32, u32, Option<u32>)>,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

inlined_function_id can be negative? 🤔

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

a bit further down below we even check for negative results, maybe just convert it to u32 like the others

}
let (_script_off, mut iid) = cur?;
let mut frames = Vec::new();
// Mirror of V8 SourcePosition::InliningStack.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: link to the function that's referenced could be helpful

// Source-position table: an entry applies from its code_offset until the
// next one, so take the last entry with code_offset <= pc_offset.
let mut cur = None;
for &(co, so, iid) in &ci.positions {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: I see the comment above but 2-3 letter var names are a bit hard to follow when reading. I think creating a struct could make sense here.

/// there is no genuine inlining at that PC; the code object's own frame is
/// supplied by the caller (the jitdump symbol), so it is *not* included.
pub fn lookup(&self, code_addr: u64, code_size: u32, pc_offset: u64) -> Option<Vec<V8Frame>> {
let ci = self.by_key.get(&(code_addr, code_size))?;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: by_key is already expressed by .get(key) -> could be renamed to code_inlines then it's also clear what ci is

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants