Skip to content

fix(kernel): honor graph under-recording in the TraceLens idle gate - #1121

Merged
jiaqiang-dot-liu merged 3 commits into
mainfrom
bugfix/yunkai/idle-gate-graph-guard
Aug 7, 2026
Merged

fix(kernel): honor graph under-recording in the TraceLens idle gate#1121
jiaqiang-dot-liu merged 3 commits into
mainfrom
bugfix/yunkai/idle-gate-graph-guard

Conversation

@BaoYunkai

Copy link
Copy Markdown
Contributor

Summary

The high-idle gate suppresses the hot-kernel candidate list (skipping the forge kernel lane entirely) whenever GPU idle % exceeds the threshold (default 80%). The bypass trace route already skips that gate when the trace is a cuda/HIP-graph under-recorded capture — under continuous graph replay the profiler activity buffer overflows and only ~1 of N replays is recorded, so idle% is inflated (bypass_graph_under_recorded). The TraceLens route (deterministic + LLM-orchestrator) applied the idle gate with no such guard.

Result: a graph-mode workload that is actually compute/GEMM-bound (rocm-smi shows full saturation) gets reported as ~87% idle from the roofline capture, every hot kernel is suppressed, and forge-loop is wrongly skipped as "host/scheduling-bound".

Observed on Qwen3-8B sglang (.../safe-opt-claw-top-models-forge-qwen-sgla-b0c92b15-a1/.../20260806T082051Z): busy_of_wall=0.093 roofline artifact → report_source=skipped:high_gpu_idle_pct, while the session's own scouts flagged the 87% idle as a "cuda-graph capture artifact" and the real workload as GEMM-bound.

Changes

  • tracelens_analysis.py:
    • _graph_coverage_from_raw_trace() — reuse the tested _bypass_trace_reader.analyze_trace(..., emit_launches=True) graph-coverage detection; fail-open to {}.
    • _evaluate_idle_gate_with_graph_guard() — when idle exceeds the threshold, first check graph under-recording; if under-recorded, skip suppression and return the bypass_graph_under_recorded warning instead of high_gpu_idle_pct.
    • Wire both TraceLens idle-gate sites (deterministic + LLM-orchestrator) through the guard.
  • Aligns the TraceLens route with the semantics the bypass route already enforces; no new mechanism.

Test plan

  • New unit tests in test_tracelens_csv.py: under-recorded → skip suppression; not-under-recorded → plain gate applies; below-threshold → no probe; bad trace path → never raises.
  • pytest test_tracelens_csv.py test_idle_gate.py test_bypass_trace_analysis.py — 273 passed, no regressions.

The high-idle gate suppresses the hot-kernel list (and thus skips the whole
forge kernel lane) whenever GPU idle exceeds the threshold. The bypass trace
route already skips that gate when the trace is a cuda/HIP-graph under-recorded
capture -- continuous graph replay overflows the profiler activity buffer, so
only ~1 of N replays is recorded and idle% is inflated. The TraceLens route
(deterministic + LLM-orchestrator) applied the idle gate with no such guard, so
a graph-mode workload that is really compute/GEMM-bound (rocm-smi shows full
saturation) was reported as ~87% idle and had every hot kernel suppressed,
wrongly skipping forge-loop.

Reuse the tested _bypass_trace_reader graph-coverage detection on both TraceLens
idle-gate sites: when the raw trace is graph under-recorded, skip the high-idle
suppression and surface the existing bypass_graph_under_recorded warning instead
(candidates stay ranked by recorded-kernel GPU share). Best-effort and fail-open
-- any probe failure falls back to the plain idle gate, never worse than today.

Adds unit tests for the guard (under-recorded skip, plain-gate passthrough,
below-threshold no-op, and never-raises on a bad trace path).
@BaoYunkai
BaoYunkai requested review from a team, devalshahamd and tsrikris as code owners August 7, 2026 08:19
…lighten probe

Addresses review of #1121.

P1 (correctness): _graph_under_recorded treated any graph-mode trace with
busy_fraction < 0.5 (or >=4 launches and busy < 0.9) as under-recorded, so a
genuinely idle / sparse / host-bound graph workload -- whose replays are all
fully recorded -- was wrongly cleared through the idle gate, defeating the
high-idle suppression. Rekey the decision on *recorded-launch coverage*: the
share of graph-launch correlations that actually recorded a kernel. Activity-
buffer overflow drops whole replays so coverage collapses toward ~1/launches,
whereas a fully-recorded idle workload keeps kernels on essentially every
launch (coverage ~1.0) and stays gated. The reader now counts distinct
graph-launch correlations with recorded kernels and exposes
graph_launches_with_kernels.

P2 (perf): the TraceLens graph-coverage probe called analyze_trace with
top_k=0 + emit_launches=True, materializing every kernel-launch row and full
top-N lists on large --skip-split traces. graph_coverage is independent of
both, so probe with top_k=1 + emit_launches=False.

Log fix: after skipping the idle gate for graph under-recording, both TraceLens
routes no longer also log the contradictory "below gate" line.

Tests: counter-example (4 launches all recorded, ~100% idle -> NOT
under-recorded, idle gate still suppresses) on the bypass route; existing
under-recorded cases (coverage 0.25/0.33) stay flagged.
Addresses the second review round of #1121.

A (wrong trace on the default split path): cli_trace_path is reassigned to the
steady-state chunk before the idle gate runs, and the graph-coverage probe used
it. A chunk can drop the hipGraphLaunch runtime events, so detection reported
non-graph and the original high-idle misfire returned on the default (non
--skip-split) path. Capture the un-split raw_trace_path = trace_files[0] and
probe graph coverage from it at both TraceLens idle-gate sites; add a
raw-vs-launch-stripped-chunk regression showing detection needs the launch
events.

B (numerator/denominator scope mismatch under steady state): _finalize filtered
k_events to the steady window before counting launches-with-kernels, while
graph_launch_count stayed whole-trace, so a fully-recorded N-launch trace whose
window held one replay read as 1/N and false-flagged under-recorded (breaking
xDiT / explicit steady-state bypass). Compute recorded-launch coverage over the
full event stream BEFORE the window filter so numerator and denominator share
whole-trace scope; add a _finalize steady-window regression.

Tests: +3 (whole-trace scope under window, raw-vs-chunk detection); full suite
277 passed.

@jiaqiang-dot-liu jiaqiang-dot-liu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@jiaqiang-dot-liu
jiaqiang-dot-liu merged commit 03c16f4 into main Aug 7, 2026
27 of 28 checks passed
@jiaqiang-dot-liu
jiaqiang-dot-liu deleted the bugfix/yunkai/idle-gate-graph-guard branch August 7, 2026 11:36
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

CI E2E report — ✅ Succeeded

item value
result ✅ Succeeded
model Qwen/Qwen3-0.6B (dense)
resources 1× GPU, TP=1
PR branch bugfix/yunkai/idle-gate-graph-guard
commit 846f1cbe6fed9ef869e4e6884043a237226d6a0d
session_id 0f921deb-f415-4824-916a-5ce572349095
queue → dispatch 0s
run time 154m 18s
total 154m 18s

details

ZhengGong-amd added a commit that referenced this pull request Aug 8, 2026
One conflict, both sides adding imports to the workload-env builder: main
brought `deps_cache_root` and `GENERIC_FRAMEWORK_ROOT_ENV`, this branch the two
FlyDSL source-root helpers. Resolved as the union; every name is used.

Nothing from main needed mirroring into the rewrite route. Its kernel-source
work -- rejecting non-path sentinels (#1107) and honoring graph under-recording
in the idle gate (#1121) -- lands in trace analysis, upstream of where this
branch picks a candidate up, and only ever hands the route fewer bogus
candidates. The integrate hardening applies to the `integrate_patch` executor,
which is a separate path from the kernel `integrate` handler an apply-back
flows through.

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

3 participants