Generic trace splitting support - #1003
Open
kyle-hoffmeyer wants to merge 15 commits into
Open
Conversation
kyle-hoffmeyer
marked this pull request as ready for review
September 3, 2026 19:38
kyle-hoffmeyer
requested review from
ajassani,
devalshahamd,
gabeweisz and
tsrikris
as code owners
September 3, 2026 19:38
kyle-hoffmeyer
marked this pull request as draft
September 3, 2026 19:38
kyle-hoffmeyer
marked this pull request as ready for review
September 3, 2026 20:26
Collaborator
|
Looks good to me - fix linting and I'll approve |
kyle-hoffmeyer
added this pull request to stack #1010
September 9, 2026 01:38
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
kyle-hoffmeyer
force-pushed
the
feat/khoffmey/split_refactor_generic
branch
from
September 11, 2026 18:03
186bf82 to
0dc139b
Compare
kyle-hoffmeyer
force-pushed
the
feat/khoffmey/split_refactor_generic
branch
from
September 11, 2026 22:32
0dc139b to
83c16cd
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds robustness to trace splitting logic, allowing it to gracefully handle traces from a variety of different frameworks and workload types.
Motivation
The trace splitter was built to split inference traces via the annotations that TraceLens recognizes. There was some support to handle generic traces of any workload and without any of these annotations, but it was faulty and could not handle traces that differed from the norm:
Solution
The detection pipeline is now a flat, three-step cascade in a single function (
find_iteration_rootsinexecution_roots.py):execute_*, SGLang'sstep[*],ProfilerStep#*, etc.), use them directly. These annotations are known to explictly mark each iteration. This mirrors the original trace splitting implementation. When a recognized pattern is found, the detector also looks for an enclosing family to widen the split (so a 512-iteration run isn't split into only the 15 iterations a regex happened to know). Coverage is audited by correlating GPU kernels back to the annotation spans — if the annotations explain enough GPU work, accept the split. If the known annotations don't provide good coverage try using unrecognized annotations.After the annotation-based detection, the entire trace tree is used to determine what events can be used as splitting points.
TraceToTreeis ran and a new function called_reattach_worker_threadsis ran. This function allows training traces to be traversable by reattaching the call stacks in the worker threads to the call stack in the main thread.The following steps are then ran:
Branch descent on the call tree. BFS from the tree's roots looking for the first frame whose children form a repeating pattern with high GPU coverage. diffusion denoise steps, and any workload with a regular call-tree structure. The coverage gate (95% of GPU time) prevents the descent from stopping on a shallow sub-loop (like a grad-norm poll that repeats but does almost no work). If the best candidate found has poor coverage, the detector still returns it rather than None, letting the cascade's fallback logic decide what to do.
Sibling-root periodicity. For some traces (especially those with missing python call stacks) contain many roots with short call stacks instead of one root with a sprawling call stack. In this case, the repeating pattern exists across roots and the branch descent step can not find the pattern. Sibling-root detection finds the repeating period across the roots.
Each step returns a
RootSetdataclass with information about the splitting result. EachRootSetobject carries a coverage metric, indicating how much of the GPU time is covered by the splits. If the coverage is too (<95%) then the subsequent step is ran. If nothing passes this coverage gate, the best failed candidate is returned with its honest status so the caller can decide whether to use it anyway (with--allow-degraded).Detection Flow
flowchart TD START["find_iteration_roots<br/>(entry point)"] --> PREP["Collect annotations"] %% Step 1: Annotations PREP --> ANN["Step 1: _detect_from_annotations<br/><br/> Try known annotations then unknown annotations"] ANN --> ANN_AUDIT["Audit GPU coverage:<br/>correlate kernels to annotation spans"] ANN_AUDIT --> ANN_GATE{"coverage ≥ 95%?"} ANN_GATE -->|yes| OK_ANN["SPLITTABLE<br/>method = annotation:tier / widened / family:unknown_only"] ANN_GATE -->|no| TREE["Build TraceToTree <br/>Reattach cross-thread worker roots<br/>"] --> BD %% Step 2: Branch descent BD["Step 2: detect_from_branch_descent<br/><br/> Search for repeating pattern of events"] --> BD_GATE{"SPLITTABLE<br/>(coverage ≥ 95%)?"} BD_GATE -->|yes| OK_BD["SPLITTABLE<br/>method = generic:branch_descent"] BD_GATE -->|no| SR %% Step 3: Sibling roots SR["Step 3: detect_from_sibling_roots<br/><br/>Check if the top-level entry roots themselves form a repeating pattern"] --> SR_GATE{"SPLITTABLE<br/>(coverage ≥ 95%)?"} SR_GATE -->|yes| OK_SR["SPLITTABLE<br/>method = generic:sibling_roots"] SR_GATE -->|no| BEST %% Pick best across all detectors BEST["Pick the best result across all detectors"] %% Converge to extraction OK_ANN --> EXT OK_BD --> EXT OK_SR --> EXT BEST --> ABRT{"NOT_SPLITTABLE and<br/>no --allow-degraded?"} ABRT -->|yes| STOP["Write manifest, ABORT"] ABRT -->|no| EXT EXT["Tiling + extraction:<br/>build gap-free per-thread tiles,<br/>assign events by start timestamp,<br/>follow correlation IDs to GPU kernels"] --> OUT["Write per-iteration slices +<br/>split_manifest.json +<br/>execution_details.csv"]When does each detector fire?
user_annotationevents with enough GPU coverageprofiler.step()After splitting completes,
split_inference_trace_annotation.pywrites asplit_manifest.jsonalongside the split traces. This is a machine-readable record of the detection and extraction result:{ "status": 0, "method": "family:unknown_only", "phase_confidence": "unknown", "n_roots": 11, "attribution_strategy": "projection", "coverage_any_annotation": 1.0, "coverage_selected_roots": 1.0, "root_family_skeleton": "ProfilerStep##", "gap_fill": true, "n_gpu_events_in_trace": 24069, "n_gpu_events_extracted": 24069, "gpu_events_duplicated": false, "gpu_event_retention": 1.0 }Key fields:
--allow-degraded)projection(GPU-side annotation spans) orcorrelation(CPU launch correlation IDs) — how GPU kernels were mapped to annotations for coverage auditingNext steps