feat: Taskdump viewer & expand inline frames in flamegraphs#377
Conversation
tokio's `taskdump` feature only compiles on Linux (aarch64/x86/x86_64). The unconditional [dependencies] entry was causing macOS CI builds to fail. Move it to the linux-only target section where it already existed.
jlizen
left a comment
There was a problem hiding this comment.
New interface looks great, just some small things.
Consider adding unit tests for TaskDumpEvent parsing and the frame expansion logic.
| callframeSymbols: mapToEntries(trace.callframeSymbols), | ||
| threadNames: mapToEntries(trace.threadNames), | ||
| runtimeWorkers: mapToEntries(trace.runtimeWorkers), | ||
| taskDumps: mapToEntries(trace.taskDumps), |
There was a problem hiding this comment.
Bit surprised not to see any changes to steering, i would have expected the schema to change at least?
Np if planned as a follow up.
| self: 0, | ||
| }); | ||
| // Expand inlined frames: an array entry means multiple frames at one address | ||
| const frames = Array.isArray(entry) ? entry : [entry]; |
There was a problem hiding this comment.
Is it just me or is this reversing the ordering of the flamegraphs, to put the outermost deepest? That seems unintuitive if so.
| for (let fi = frames.length - 1; fi >= 0; fi--) { | ||
| const resolved = frames[fi]; | ||
| const key = resolved ? resolved.symbol : addr || "??"; | ||
| const formatted = resolved ? formatFrame(resolved) : formatFrame(addr, callframeSymbols); |
There was a problem hiding this comment.
This seems more fragile than the old way since frames might be [null].
We could do something like:
Array.isArray(entry) ? entry[0] : entry.
| // Check if clicking an idle region with task dumps | ||
| for (const r of taskDetailHitRegions) { | ||
| if (mx >= r.x1 && mx <= r.x2 && my >= r.y1 && my <= r.y2 && r.taskDumps) { | ||
| showTaskDumpStack(r.taskDumps); |
There was a problem hiding this comment.
probably should be in a try/catch similar to showIdleTimeFlamegraph?
| const fgContainer = document.getElementById("fg-container"); | ||
| const fgInstance = FlamegraphRenderer.createFlamegraph(fgContainer); | ||
|
|
||
| function showTaskDumpStack(dumps) { |
There was a problem hiding this comment.
there is a lot of redundant sidebar code between showTaskDumpStack and showIdleTimeFlamegraph, should we consolidate?
Also consider extracting the dump UI logic into a separate module.
| ctx.strokeStyle = "#444"; | ||
|
|
||
| // Cross-hatch pattern for idle periods with task dumps | ||
| if (hasDump) { |
There was a problem hiding this comment.
feels like we'll want this in a helper sooner or later
1. Fix inlined-frame iteration order in buildFlamegraphTree. Per blazesym,
an array entry in callframeSymbols is [outermost, ..., innermost] — the
real function at the address is at [0] and [i>0] are inlined callees. The
previous implementation iterated N→0, which inverted the call graph in the
flamegraph (inner inlined functions appeared as parents of the outer
function they were inlined into). Now iterates 0→N, matching caller→callee.
Skip nullish slots so sparse arrays (from out-of-order SymbolTableEntry
events) no longer produce phantom (unknown) tree levels.
2. Wrap showTaskDumpStack click in try/catch matching the
showIdleTimeFlamegraph pattern — errors now surface as a toast instead of
silently failing.
3. Extract renderFlamegraphInSidebar({title, subtitle, samples}) helper.
Both showTaskDumpStack and showIdleTimeFlamegraph now delegate to it,
removing ~40 lines of duplicated sidebar setup.
4. Extract drawCrossHatch(x, y, w, h) helper for the diagonal stripe pattern
used on idle periods that have a task dump.
5. Document taskDumps in the ParsedTrace schema
(dial9-trace-loading/SKILL.md) so agent skills can find it. Extend the
schema validator to understand Map<K, [{obj}]> (array-of-objects map
values).
6. Add unit tests in test_trace_analysis.js covering:
- Flamegraph inline frame ordering (catches the bug fixed in #1)
- Sparse inline arrays with undefined slots
- Unresolved address handling
- TaskDumpEvent parsing shape, sort order, task-id integrity
1. Fix inlined-frame iteration order in buildFlamegraphTree. Per blazesym,
an array entry in callframeSymbols is [outermost, ..., innermost] — the
real function at the address is at [0] and [i>0] are inlined callees. The
previous implementation iterated N→0, which inverted the call graph in the
flamegraph (inner inlined functions appeared as parents of the outer
function they were inlined into). Now iterates 0→N, matching caller→callee.
Skip nullish slots so sparse arrays (from out-of-order SymbolTableEntry
events) no longer produce phantom (unknown) tree levels.
2. Wrap showTaskDumpStack click in try/catch matching the
showIdleTimeFlamegraph pattern — errors now surface as a toast instead of
silently failing.
3. Extract renderFlamegraphInSidebar({title, subtitle, samples}) helper.
Both showTaskDumpStack and showIdleTimeFlamegraph now delegate to it,
removing ~40 lines of duplicated sidebar setup.
4. Extract drawCrossHatch(x, y, w, h) helper for the diagonal stripe pattern
used on idle periods that have a task dump.
5. Document taskDumps in the ParsedTrace schema
(dial9-trace-loading/SKILL.md) so agent skills can find it. Extend the
schema validator to understand Map<K, [{obj}]> (array-of-objects map
values).
6. Add unit tests in test_trace_analysis.js covering:
- Flamegraph inline frame ordering (catches the bug fixed in #1)
- Sparse inline arrays with undefined slots
- Unresolved address handling
- TaskDumpEvent parsing shape, sort order, task-id integrity
…#378) * add: TaskDumps UI to viewer * Address PR dial9-rs#377 review feedback 1. Fix inlined-frame iteration order in buildFlamegraphTree. Per blazesym, an array entry in callframeSymbols is [outermost, ..., innermost] — the real function at the address is at [0] and [i>0] are inlined callees. The previous implementation iterated N→0, which inverted the call graph in the flamegraph (inner inlined functions appeared as parents of the outer function they were inlined into). Now iterates 0→N, matching caller→callee. Skip nullish slots so sparse arrays (from out-of-order SymbolTableEntry events) no longer produce phantom (unknown) tree levels. 2. Wrap showTaskDumpStack click in try/catch matching the showIdleTimeFlamegraph pattern — errors now surface as a toast instead of silently failing. 3. Extract renderFlamegraphInSidebar({title, subtitle, samples}) helper. Both showTaskDumpStack and showIdleTimeFlamegraph now delegate to it, removing ~40 lines of duplicated sidebar setup. 4. Extract drawCrossHatch(x, y, w, h) helper for the diagonal stripe pattern used on idle periods that have a task dump. 5. Document taskDumps in the ParsedTrace schema (dial9-trace-loading/SKILL.md) so agent skills can find it. Extend the schema validator to understand Map<K, [{obj}]> (array-of-objects map values). 6. Add unit tests in test_trace_analysis.js covering: - Flamegraph inline frame ordering (catches the bug fixed in dial9-rs#1) - Sparse inline arrays with undefined slots - Unresolved address handling - TaskDumpEvent parsing shape, sort order, task-id integrity
I am pretty stoked about this it came out really nice.
when the idle time has a crosshatch, it means we have a task dump for that period

when you click it, we render it as a flamegraph (there can be multiple futures that you are waiting on)
You can also see a task-flamegraph for the entire task