Skip to content

[AMD] Make ROCm 7.2.4 images profile HIP-graph kernels, and check that they do - #35390

Closed
michaelzhang-ai wants to merge 3 commits into
mainfrom
cursor/qualify-rocm-724-hip-graph-profiling-dba6
Closed

michaelzhang-ai wants to merge 3 commits into
mainfrom
cursor/qualify-rocm-724-hip-graph-profiling-dba6

Conversation

@michaelzhang-ai

@michaelzhang-ai michaelzhang-ai commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Motivation

AMD/Silo reported that on the lmsysorg/sglang* ROCm 7.2 images, torch.profiler traces contain no GPU kernels for work launched through hipGraph. The cause is upstream and fixed upstream — ROCTracer drops kernel-dispatch events under hipGraphLaunch (ROCm/ROCm#6102, fixed in ROCm 7.2.2) — and #30984 has since published rocm724 images that install ROCm 7.2.4.

Installing it turned out not to be the same as using it. The torch wheels vendor their own HIP and roctracer under torch/lib, and libtorch_hip.so carries RPATH $ORIGIN, so the published 7.2.4 images profile through 7.2.0 libraries and LD_LIBRARY_PATH cannot override an RPATH. Measured on rocm/sgl-dev:v0.5.17-rocm724-*-20260820:

image GPU eager graph replay verdict
as shipped MI355X 512/512 448/512 FAIL
ROCm copies in use MI355X 512/512 512/512 PASS
as shipped MI300X 512/512 448/512 FAIL
ROCm copies in use MI300X 512/512 512/512 PASS

On a real server trace the gap is larger: gpt-oss-20b-bf16 with /start_profile num_steps=10 records 513 device kernel events with CUDA graphs on, against 3924 with --disable-cuda-graph and 3933 on a working runtime — 87% of decode kernels missing from a trace that otherwise looks complete.

So this PR does three things: makes the images use the ROCm runtime they install, adds the check that tells the two states apart, and documents it.

Modifications

docker/rocm.Dockerfile — use the ROCm runtime the image installs

One step at the end of the torch work replaces torch/lib/libamdhip64.so and torch/lib/libroctracer64.so with the ROCm install's versioned copies, plus a verification step. Three details worth review:

  • Keyed on whether the wheel vendors them, not on the ROCm flavor. Where torch already links /opt/rocm — the rocm720 stack on torch 2.9.1 — there is nothing to replace and the step says so and moves on, so there is no version guard to update for the next flavor. A wheel that vendors them with no ROCm copy available is a broken image, and the build fails.
  • Replaced by rename. The interpreter doing the replacing has those libraries mapped; writing through them would corrupt it. It stages a copy and os.replaces.
  • Verified in a fresh interpreter, which loads the swapped-in libraries, so a soname or ABI mismatch fails the build rather than a user's first profile.

LD_PRELOAD of the same two libraries is not an equivalent workaround: @devalshahamd found it aborts server startup on 7.2.4 inside Triton's AMD launcher during CUDA-graph capture, while this replacement leaves both the probe and a real workload with clean profiles. That fits the mechanism — a preload leaves both HIP copies mapped and only interposes symbols, so a component resolving them independently can end up on the other runtime with its own state.

scripts/ci/amd/check_hip_graph_profiling.py — the check

Captures a graph, replays it under torch.profiler, and counts device events in the exported trace against the dispatches it asked for. Counting matters: the loss is partial (448 of 512), and a 4-node graph is traced correctly even on 7.2.0, so both a "non-empty trace" threshold and a small graph would call a broken runtime healthy. The default is 64 nodes replayed 8 times — a calibrated point, since 7.2.0 is complete at 4 and lossy from about 16 while 7.2.4 has been seen dropping at 256.

An eager control run separates "cannot trace graph replay" from "cannot trace anything", and each phase runs in its own process under a timeout because 7.2.0 can also wedge inside hipGraphLaunch. It reports the paths of the libraries torch mapped, flags any the ROCm install is not backing, and prints the commands to fix that; --print-ld-preload exposes the value for a single-run check.

Not registered in the AMD suites: on a rocm720 image it is expected to fail and, per #34452, can take the process down with it.

test/registered/unit/ci/test_hip_graph_profiling_probe.py

The probe's value is that a red run says which failure happened, and a GPU job only ever exercises whichever case its image is in. 18 CPU tests drive main() with canned phase results: every verdict and exit code, the partial-loss shortfall, vendored-runtime detection including the half-preloaded case, the preload value naming real files rather than symlinks, and the trace parser, where counting a host-only trace as device work would turn the check into a false pass. Registered as base-a-test-cpu.

docs/docs/developer_guide/benchmark_and_profiling.mdx

Records the symptom, how to check an image, the rocm724 images as the answer, how to repair an older image, and --disable-cuda-graph where neither applies.

Accuracy Tests

No model or kernel code changes. The Dockerfile step swaps two shared libraries for the same libraries at the version the image already installs.

Speed Tests and Profiling

The point of the change is that torch.profiler reports what the GPU ran. No throughput effect is expected: HIP and roctracer are replaced with the ROCm 7.2.4 build the image ships and that the rest of the stack was validated against.

Measured

The fix, on the published image. The Dockerfile step's own code, extracted from docker/rocm.Dockerfile at runtime, applied to rocm/sgl-dev:v0.5.17-rocm724-mi35x-20260820 on MI355X, probing either side of it with nothing preloaded — run 32517873558:

mapped runtime eager graph replay verdict
as published torch/lib copies 512/512 448/512 FAIL
after the step ROCm 7.2.4 build 512/512 512/512 PASS

torch still imports afterwards (2.11.0+rocm7.2, hip 7.2.26015), and the step copied 27,193,296 and 347,896 bytes — the ROCm file sizes exactly.

Both published flavors, on the GPU each targets, 448/512 FAIL as shipped and 512/512 PASS with the ROCm runtime in use: MI355X 32337394284, MI300X 32422850894. torch.cuda.get_device_name(0) resolves on both, and torch reports hip 7.2.26015 — the 7.2.0 build — inside a 7.2.4 image.

Real server trace, gpt-oss-20b-bf16 with /start_profile num_steps=10, identical workload across runs: 513 device kernel events with CUDA graphs on against 3924 with --disable-cuda-graph and 3933 on a working runtime, i.e. 87% of decode kernels missing.

Independently, @devalshahamd ran the probe on ROCm 7.0.0, 7.2.0 and 7.2.4 and reported it behaves as expected on all three, and that replacing the wheel's libraries gives a real SGLang workload a clean profile.

The Dockerfile step's logic exercised against a simulated torch/lib and /opt/rocm/lib: both vendored, idempotent re-run, nothing vendored, vendored with no ROCm copy (fails loudly), symlinks never chosen as the source.

CI: gate green and base-a-test-cpu green with the probe's tests collected and run (32421463756 for the earlier 18; 22 now). PR Test Extra / PR Test Extra (AMD) fail on the missing run-ci-extra label, not on tests.

Review findings addressed

  • LD_PRELOAD aborts server startup on 7.2.4 (@devalshahamd) — inside Triton's AMD launcher during CUDA-graph capture. That is why the Dockerfile replaces the files instead of documenting a preload, and why the probe marks the preload as a single-run check. [AMD] Make ROCm 7.2.4 images profile correctly without LD_PRELOAD #35806 proposed the Dockerfile change separately and is folded in here.
  • run_child dropped --graph-nodes (@devalshahamd) — the parent accepted the flag and the children used their own default, so a --graph-nodes 4 calibration run measured 64. The child command is now built from a declared option set, with a test that fails if a future option is neither forwarded nor parent-only. Default runs were unaffected, so the numbers above stand.
  • A 4-node graph passes on 7.2.0, and the loss is partial — the probe counted kernels > 0 on a 4-node graph and would have called every broken image healthy. It now counts every dispatch at 64 nodes.
  • The runtime report keyed on paths — after the Dockerfile step the ROCm build sits at the wheel's path, so the probe told readers to redo a fix already applied. It now decides by file size.

Checklist

Notes

Review and Merge Process

  1. Ping Merge Oncalls to start the process. See the PR Merge Process.
  2. Get approvals from CODEOWNERS and other reviewers.
  3. Trigger CI tests with comments or contact authorized users to do so.
  4. After green CI and required approvals, ask Merge Oncalls or people with Write permission to merge the PR.

CI States

Latest PR Test (Base): ❌ Run #32682707842
Latest PR Test (Extra): ❌ Run #32682707619
Latest PR Test (AMD ROCm 7.2): ❌ Run #32682707786

@mintlify

mintlify Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
lmsysorg 🟢 Ready View Preview Aug 18, 2026, 9:58 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@michaelzhang-ai

Copy link
Copy Markdown
Collaborator Author

Hardware results on MI355X

Ran the test plan on smci355-ccs-aus-m12-17 (8x MI355X / gfx950, KMD 6.16.13, host ROCm 7.2.0), against this branch merged with #35398 (clean merge, non-overlapping rocm.Dockerfile hunks as expected) plus a gfx950-rocm724 image built from the merged tree.

Two things to report: the libdrm prerequisite and the profiling premise both hold up on real hardware, but the probe as written cannot fail a bad image.

The libdrm change is confirmed

image torch.cuda.get_device_name(0)
rocm/pytorch:rocm7.2.4_ubuntu22.04_py3.10_pytorch_release_2.9.1 ''
built from this branch, GPU_ARCH=gfx950-rocm724 'AMD Instinct MI355X'

The built image has /opt/amdgpu/share/libdrm/amdgpu.ids copied to /usr/share/libdrm/, listing 74A1 AMD Instinct MI300X and 75A3 AMD Instinct MI355X. The step resolved graphics/7.2.4 from the image's own ROCm version, and the 7.2.0 flavors still take the skip path.

The bug is real and ROCm 7.2.4 fixes it

Real SGLang decode trace rather than a microbenchmark: gpt-oss-20b-bf16, triton attention backend, /start_profile with num_steps=10. The two graph-enabled runs agree exactly on 3520 cpu_op, 1993 cuda_runtime and 63 graph replays, so only the runtime differs.

run device kernel events in trace
ROCm 7.2.0 shipped image, CUDA graphs on 513
ROCm 7.2.0 shipped image, --disable-cuda-graph 3924
ROCm 7.2.4 candidate, CUDA graphs on 3933

87% of decode kernels never reach the trace on 7.2.0, and the --disable-cuda-graph workaround this PR documents does recover them. That is the report reproduced, and the docs change is accurate.

The probe passes every known-bad image

check_hip_graph_profiling.py returns VERDICT: PASS on all of these:

image ROCm verdict
rocm/pytorch:rocm7.2_ubuntu22.04_py3.10_pytorch_release_2.9.1 7.2.0 PASS
rocm/sgl-dev:v0.5.17-rocm720-mi35x-20260818 7.2.0 PASS
lmsysorg/sglang-rocm:v0.5.16-rocm720-mi35x-20260727 7.2.0 PASS
candidate built here 7.2.4 PASS

Two independent reasons:

The captured graph is too small. The loss only appears at about 16 graph nodes; phase_profile captures 4. Traced kernels as a share of launched, at 8 replays:

graph nodes 4 (current) 16 64 256 1024
ROCm 7.2.0 100% 75% 87.5% 83% 75%
ROCm 7.2.4 100% 100% 100% 93.1% 100%

An eager control traces 100% at every size on both runtimes, so this is specific to graph replay.

The pass condition asks the wrong question. The verdict turns on graph["kernels"] == 0, but the failure mode is partial loss. At 64 nodes a 7.2.0 image reports 448 kernels — nonzero, and still 64 short.

Worth noting the single-replay case, which is the reported symptom in its sharpest form. At 64 nodes on 7.2.0:

replays 1 2 4 8 16
traced 0% 50% 75% 87.5% 87.5%

7.2.4 is 100% at every replay count.

Fix

Capturing 64 kernels by default and comparing traced against launched separates the two runtimes with no variance at all:

ROCm 7.2.0 ROCm 7.2.4
graph replay 448/512, 10 runs of 10 512/512, 10 runs of 10

With that change the matrix comes out as intended — FAIL on the 7.2.0 base and the shipped nightly, PASS on the 7.2.4 base and the candidate — and repeats 5 of 5 on each side with identical counts. The eager control gets the same completeness check so a runtime that drops events generally stays distinguishable from one that only loses graph events.

eager launch: 512/512 kernels traced, 11246 us device time, 6213 trace events
graph replay: 448/512 kernels traced, 3983 us device time, 1005 trace events

VERDICT: FAIL -- eager launches trace completely but 64 of 512 graph-replay kernels
never reach it. This is the roctracer reporting failure fixed in ROCm 7.2.2 ...

I'll push that to this branch. Caveat: this host is MI355X only, so gfx942 is still untested.

@cursor
cursor Bot force-pushed the cursor/qualify-rocm-724-hip-graph-profiling-dba6 branch from bf5bd61 to 36a401b Compare August 20, 2026 02:10
@michaelzhang-ai michaelzhang-ai changed the title [AMD] Qualify ROCm 7.2.4 for the profiler: HIP-graph capture probe + libdrm-amdgpu prerequisite [AMD] Add a probe that verifies torch.profiler captures HIP-graph kernels Aug 20, 2026
@chuyeh

chuyeh commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Warning

Correction (2026-08-22): Do not use Option A (LD_PRELOAD) to launch an SGLang server.

The 512/512 PASS reported below only validates the isolated Torch matmul/HIP-graph probe, not the full Torch + Triton + SGLang stack. Use Option B instead.

Measured this on an MI355X against a gfx950-rocm724 image from #30984.

libdrm: confirmed. The image has libdrm-amdgpu* from graphics/7.2.4 and amdgpu.ids with 74A1 / 75A3. torch.cuda.get_device_name(0) is 'AMD Instinct MI355X'.

HIP-graph profiling: the 7.2.4 packages are in the image (/opt/rocm/lib/libamdhip64.so.7.2.70204, /opt/rocm/lib/libroctracer64.so.4.1.70204), but torch 2.11 does not load them. libtorch_hip.so has RPATH $ORIGIN and NEEDED libamdhip64.so / libroctracer64.so, so the loader always takes the copies vendored in torch/lib/ (7.2.0 / *.70200). LD_LIBRARY_PATH=/opt/rocm/lib does not override that. The 720 Silo workaround (replace /opt/rocm *.70200) works for torch 2.9, which links /opt/rocm; it does not work for this 724 stack.

Use the 64-node × 8-replay check from the test plan (4 nodes still passes on 7.2.0). Same split as reported there:

run what torch actually maps eager graph replay
724 default …/torch/lib/libamdhip64.so (*.70200, 26746545 B) 512/512 448/512 FAIL
724 + LD_PRELOAD of /opt/rocm *.70204 image libamdhip64.so.7.2.70204 + libroctracer64.so.4.1.70204 512/512 512/512 PASS

How to force 7.2.4 into torch.profiler (this is what reached PASS)

Option A — LD_PRELOAD (runtime; this is the one we measured to 512/512). Must be set in the environment of the Python process before it starts. Setting it after import torch is too late. LD_LIBRARY_PATH is not a substitute.

export LD_PRELOAD="/opt/rocm/lib/libamdhip64.so.7.2.70204:/opt/rocm/lib/libroctracer64.so.4.1.70204${LD_PRELOAD:+:$LD_PRELOAD}"

Docker:

docker run --rm --device=/dev/kfd --device=/dev/dri --group-add video \
  -e LD_PRELOAD=/opt/rocm/lib/libamdhip64.so.7.2.70204:/opt/rocm/lib/libroctracer64.so.4.1.70204 \
  <gfx950-rocm724-image> \
  python3 scripts/ci/amd/check_hip_graph_profiling.py

Same LD_PRELOAD on sglang.launch_server / /start_profile. It is inherited by child processes unless they clear it.

Option B — overwrite the files torch actually loads (durable / image bake). After pip install torch, replace the two vendored copies (do not only copy into /opt/rocm):

T="$(python3 -c 'import torch, pathlib; print(pathlib.Path(torch.__file__).resolve().parent / "lib")')"
cp -a /opt/rocm/lib/libamdhip64.so.7.2.70204  "$T/libamdhip64.so"
cp -a /opt/rocm/lib/libroctracer64.so.4.1.70204 "$T/libroctracer64.so"

Those two destinations are the ones ldd $T/libtorch_hip.so resolves today. After overwrite, sizes should match the image libs (libamdhip64.so 27193296 B, libroctracer64.so 347896 B), not the wheel copies (26746545 / 516681). strings "$T/libamdhip64.so" | grep 70204 should hit; the wheel copy contains libamdhip64.so.7.2.70200-7.2.26015.70200 instead.

cursor Bot pushed a commit that referenced this pull request Aug 20, 2026
…oaded

Two corrections from the measurement on #35390.

The loss under ROCm 7.2.0 is partial: a 64-node graph reported 448 of 512
kernels, while a 4-node graph came back complete. The probe captured four nodes
and passed on any non-zero kernel count, so it would have called the broken
runtime healthy. Capture 64 nodes by default and require every dispatch the
phases asked for, reporting the shortfall when there is one.

Having the fix installed is also not the same as running it. The torch wheels
vendor HIP and roctracer under torch/lib and libtorch_hip.so carries RPATH
$ORIGIN, so a ROCm 7.2.4 image still profiles through 7.2.0 libraries and
LD_LIBRARY_PATH cannot override it. Report the paths torch mapped rather than
sonames, flag the ones that did not come from the ROCm install, and print the
LD_PRELOAD that switches them -- otherwise the failure looks like an unfixable
image instead of a load-order problem.

Co-authored-by: quitenode <quitenode@users.noreply.github.com>
cursor Bot pushed a commit that referenced this pull request Aug 20, 2026
…oaded

Two corrections from the measurement on #35390.

The loss under ROCm 7.2.0 is partial: a 64-node graph reported 448 of 512
kernels, while a 4-node graph came back complete. The probe captured four nodes
and passed on any non-zero kernel count, so it would have called the broken
runtime healthy. Capture 64 nodes by default and require every dispatch the
phases asked for, reporting the shortfall when there is one.

Having the fix installed is also not the same as running it. The torch wheels
vendor HIP and roctracer under torch/lib and libtorch_hip.so carries RPATH
$ORIGIN, so a ROCm 7.2.4 image still profiles through 7.2.0 libraries and
LD_LIBRARY_PATH cannot override it. Report the paths torch mapped rather than
sonames, flag the ones that did not come from the ROCm install, and print the
LD_PRELOAD that switches them -- otherwise the failure looks like an unfixable
image instead of a load-order problem.

Co-authored-by: quitenode <quitenode@users.noreply.github.com>
@cursor
cursor Bot force-pushed the cursor/qualify-rocm-724-hip-graph-profiling-dba6 branch from 6780c46 to 83775b1 Compare August 20, 2026 04:15
@michaelzhang-ai

michaelzhang-ai commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks @chuyeh — the 448/512 split is the important part, and it found a hole in the probe. Two fixes pushed:

  • Counting. The probe captured 4 nodes and passed on any non-zero kernel count, so it would have called 7.2.0 healthy — exactly the case you note still passes at 4 nodes. It now captures 64 nodes replayed 8 times by default (--graph-nodes) and requires every dispatch, failing with the shortfall: graph replay: 448/512 kernel eventsFAIL -- ... 64 of 512 graph-replay kernels never reached the trace.
  • Which runtime torch loaded. It now prints library paths instead of sonames, flags any HIP/roctracer not from /opt/rocm, and prints the LD_PRELOAD to switch them, so this reads as a load-order problem rather than an unfixable image. --print-ld-preload exposes the value for callers that must set it before the process starts.

Docs no longer claim the image alone is enough: rocm724 installs 7.2.4, but the wheel's torch/lib copies win via RPATH $ORIGIN until preloaded, with --disable-cuda-graph as the fallback where preloading isn't possible.

#35398 now runs the probe twice per published image — as shipped (informational, expected to fail while torch shadows the ROCm install) and with the ROCm runtime preloaded (the gate) — so both states show up in the nightly summary.

On Option B: baking over the two torch/lib files is the only variant that makes profiling work by default, and it belongs in the rocm724 stages rather than here. Happy to put up that change if you want it — the probe's size/path output verifies the result.

cursor Bot pushed a commit that referenced this pull request Aug 21, 2026
…oaded

Two corrections from the measurement on #35390.

The loss under ROCm 7.2.0 is partial: a 64-node graph reported 448 of 512
kernels, while a 4-node graph came back complete. The probe captured four nodes
and passed on any non-zero kernel count, so it would have called the broken
runtime healthy. Capture 64 nodes by default and require every dispatch the
phases asked for, reporting the shortfall when there is one.

Having the fix installed is also not the same as running it. The torch wheels
vendor HIP and roctracer under torch/lib and libtorch_hip.so carries RPATH
$ORIGIN, so a ROCm 7.2.4 image still profiles through 7.2.0 libraries and
LD_LIBRARY_PATH cannot override it. Report the paths torch mapped rather than
sonames, flag the ones that did not come from the ROCm install, and print the
LD_PRELOAD that switches them -- otherwise the failure looks like an unfixable
image instead of a load-order problem.

Co-authored-by: quitenode <quitenode@users.noreply.github.com>
@cursor
cursor Bot force-pushed the cursor/qualify-rocm-724-hip-graph-profiling-dba6 branch from 1d1cddd to 6cf3eea Compare August 21, 2026 19:07
@michaelzhang-ai michaelzhang-ai changed the title [AMD] Add a probe that verifies torch.profiler captures HIP-graph kernels [AMD] Make ROCm 7.2.4 images profile HIP-graph kernels, and check that they do Aug 21, 2026
@michaelzhang-ai

Copy link
Copy Markdown
Collaborator Author

Hardware runs

All on linux-mi35x-gpu-1 / linux-mi300-1gpu-sglang via workflow_dispatch of the ROCm 7.2 nightly (no image was published — publish is skipped in each).

The Dockerfile step, against the published rocm/sgl-dev:v0.5.17-rocm724-mi35x-20260820. The step's own code is extracted from docker/rocm.Dockerfile at runtime rather than copied, and the probe runs either side of it with nothing preloaded:

mapped runtime eager graph replay verdict
as published torch/lib copies 512/512 448/512 FAIL
after the step ROCm 7.2.4 build 512/512 512/512 PASS

run 32517262300 · re-run after the fix below, 32517873558. torch still imports afterwards (2.11.0+rocm7.2, hip 7.2.26015), and the step copied 27,193,296 and 347,896 bytes — the ROCm file sizes exactly. Building the whole image would cost ~45 min of a GPU runner to exercise one step, and @devalshahamd already confirmed the equivalent cp -a end to end on a real workload.

The published images as they stand, both flavors on the GPU each targets: 448/512 FAIL as shipped, 512/512 PASS with the ROCm runtime in use — MI355X 32337394284, MI300X 32422850894. torch.cuda.get_device_name(0) resolves on both; torch reports hip 7.2.26015 inside a 7.2.4 image.

What the first run caught. On the fixed image the probe still printed "torch is using its own HIP/roctracer" and told the reader to redo a cp -a that was already done: the check keyed on the path, and the whole point of the step is that the ROCm build ends up at the wheel's path. It now compares the mapped file's size against the ROCm install's copies, so it recognises both shapes — a preload, which maps the ROCm copy alongside, and a replacement, which is only visible as a size. The re-run confirms the note fires on the published image and is silent after the step, verdicts unchanged. Two more unit tests cover it.

CI status

  • base-a-test-cpu green with the probe's unit tests collected and run: 32421463756 (Ran 18 tests; 20 now, after the two commits since).
  • The current head has no fresh suite results: the gate rejects it with User 'cursor[bot]' already triggered 'PR Test Base' … Please wait 120 minutes, so every red check on this PR right now is that cooldown rather than a failure. Re-triggering after it lapses picks up the two newest commits.
  • run-ci-extra is not set, so the extra suites stay gated.

cursor Bot pushed a commit that referenced this pull request Aug 23, 2026
…oaded

Two corrections from the measurement on #35390.

The loss under ROCm 7.2.0 is partial: a 64-node graph reported 448 of 512
kernels, while a 4-node graph came back complete. The probe captured four nodes
and passed on any non-zero kernel count, so it would have called the broken
runtime healthy. Capture 64 nodes by default and require every dispatch the
phases asked for, reporting the shortfall when there is one.

Having the fix installed is also not the same as running it. The torch wheels
vendor HIP and roctracer under torch/lib and libtorch_hip.so carries RPATH
$ORIGIN, so a ROCm 7.2.4 image still profiles through 7.2.0 libraries and
LD_LIBRARY_PATH cannot override it. Report the paths torch mapped rather than
sonames, flag the ones that did not come from the ROCm install, and print the
LD_PRELOAD that switches them -- otherwise the failure looks like an unfixable
image instead of a load-order problem.

Co-authored-by: quitenode <quitenode@users.noreply.github.com>
@cursor
cursor Bot force-pushed the cursor/qualify-rocm-724-hip-graph-profiling-dba6 branch from f505030 to 053f061 Compare August 23, 2026 23:13
@michaelzhang-ai
michaelzhang-ai force-pushed the cursor/qualify-rocm-724-hip-graph-profiling-dba6 branch from 053f061 to 0cdd5f9 Compare August 23, 2026 23:26
@michaelzhang-ai

Copy link
Copy Markdown
Collaborator Author

Thanks @devalshahamd — both findings landed.

run_child dropping --graph-nodes: a real bug, fixed in 233c879 and answered in the thread. The parent accepted the flag and the children used their own default, so --graph-nodes 4 silently measured 64. Default runs were unaffected (both sides defaulted to 64), so the hardware numbers here still stand. The command is now built from a declared option set, with a test that fails if a future knob is left unforwarded.

LD_PRELOAD aborting server startup on 7.2.4: that changed the recommendation, not just the wording. A preload leaves both HIP copies mapped and only interposes symbols, so a component resolving them independently — Triton's AMD launcher in your trace — can land on the other runtime. Replacing the file leaves one. So:

  • [AMD] Make ROCm 7.2.4 images profile correctly without LD_PRELOAD #35806 is folded into this PR: docker/rocm.Dockerfile now overwrites the two libraries the wheel vendors, which is the cp -a you verified, done at build time. Images profile correctly with nothing set.
  • The probe prints those cp -a commands as the fix and marks the preload as a single-run check with the caveat attached; the docs do the same.
  • Verified on the published v0.5.17-rocm724-mi35x-20260820: applying the Dockerfile step's own code takes it from 448/512 FAIL to 512/512 PASS with nothing preloaded (run).

Your run also caught a wart in the probe: on the fixed image it still said "torch is using its own HIP/roctracer" and told you to redo the copy, because the check keyed on the path and the fix puts the ROCm build at the wheel's path. It now decides by file size instead.

cursoragent and others added 3 commits August 24, 2026 00:01
…efault

The ROCm 7.2.4 images fix the roctracer failure that loses kernel-dispatch
events under hipGraphLaunch (ROCm/legacy-rocm-build#6102, fixed in 7.2.2), and then do not
use it: the torch wheels vendor their own HIP and roctracer under torch/lib and
libtorch_hip.so carries RPATH $ORIGIN, so the loader takes those 7.2.0 copies and
LD_LIBRARY_PATH cannot override an RPATH. Measured on the published
v0.5.17-rocm724-*-20260820 images, 448 of 512 graph-replay kernels reach the
trace on MI300X and on MI355X, and a real server trace loses 87% of its decode
kernels while looking complete.

Replacing the two files the wheel vendors makes the working configuration the
default. LD_PRELOAD of the same libraries is not an equivalent workaround: it
leaves both copies mapped and only interposes symbols, so a component resolving
them independently ends up on the other runtime -- reported as an abort during
CUDA-graph capture inside Triton's AMD launcher.

Keyed on whether the wheel vendors them rather than on the flavor, so a torch
that already links /opt/rocm is left alone and no version guard needs updating.
Replaced by rename because the interpreter doing the replacing has the old files
mapped. A fresh interpreter then imports torch, so a soname or ABI mismatch fails
the build instead of a user's first profile.

Co-authored-by: quitenode <quitenode@users.noreply.github.com>
…nels

Nothing in CI could tell a working profiler from a broken one:
test/registered/profiling/test_start_profile.py only asserts the trace directory
is non-empty, and since #34452 the profiling suite runs without CUDA graphs on
ROCm, so it never exercises the replay path. Whether an image traces graph
replay also cannot be read off its ROCm version, because the torch wheel can
shadow the ROCm runtime.

The probe captures a graph, replays it under torch.profiler, and counts the
device events reaching the exported trace against the dispatches it asked for.
Counting is the point: the loss is partial -- 448 of 512 -- and a 4-node graph is
traced completely even on 7.2.0, so both a non-empty-trace threshold and a small
graph would call a broken runtime healthy. 64 nodes by default is calibrated
between two thresholds: 7.2.0 is complete at 4 and lossy from about 16, and
7.2.4 has been seen dropping at 256.

An eager control separates "cannot trace graph replay" from "cannot trace
anything", and each phase runs in its own process under a timeout because 7.2.0
can wedge inside hipGraphLaunch instead of losing events. The report names the
libraries torch actually mapped, decided by file size rather than path so that
both a preload and an in-place replacement are recognised, and prints the
commands that repair an image.

The CPU tests drive main() with canned phase results, since a GPU job only ever
exercises whichever failure its own image has: every verdict and exit code, the
partial-loss shortfall, runtime detection in each of its shapes, the child
command carrying every workload option, and the trace parser, where counting a
host-only trace as device work would turn the whole check into a false pass.

Co-authored-by: quitenode <quitenode@users.noreply.github.com>
Traces taken on a ROCm 7.2.0 runtime under-report the decode steps, which run
from replayed graphs, and the loss is partial rather than total, so nothing about
the trace says it is wrong. Record the symptom, how to check an image, the
rocm724 images as the answer, how to repair an image that predates the runtime
fix, and --disable-cuda-graph where neither applies.

Co-authored-by: quitenode <quitenode@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

amd documentation Improvements or additions to documentation run-ci

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants