Repository navigation
feat(tools): hrx2kineto — HRX dispatch shapes and a TraceLens extension - #323
Conversation
PR Reviewer Guide 🔍(Review updated until commit fb0abc2)Here are some key observations to aid the review process:
|
f585933 to
0d61005
Compare
|
Persistent review updated to latest commit 0d61005 |
…ns.sh hrx2kineto.py (HRX dispatch profile -> Kineto trace) keeps its old positional behaviour byte for byte and adds --shapes/--commands: with the llama.cpp fork's GGML_HRX_DISPATCH_SHAPE_LOG (fork branch 1bit/hrx-dispatch-shape-log, not in the pin yet) every dispatch is joined to the ggml dispatch match that emitted it and emitted as an hrx::<ggml op> cpu_op with Input Dims/types/strides, the fused op chain, FLOPs and bytes (quantized weights at their real bits per weight, MUL_MAT_ID reading only the routed experts), nested under hrx::step / hrx::layer so TraceDiff aligns runs with and without graph splits. The same file is a TraceLens --extension_file (GEMM / GroupedGEMM / SDPA / NORM / RoPE / reduce / SSM / elementwise perf models), --write-arch writes a gfx1151 arch JSON for the roofline columns, --summary prints a per-op roofline table with the concurrent-dispatch overlap, and --tracediff-top summarises TraceDiff. hrx-tracelens.sh profiles one prompt or decode run, converts it and writes the TraceLens report (optionally with TraceDiff against another run). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
0d61005 to
03947eb
Compare
|
Persistent review updated to latest commit 03947eb |
The profile executor looks for a Kineto trace it never got: it probes <workspace>/torch_trace, <workspace>/capture_traces and <workspace>.parent/capture_traces for *.trace.json.gz. This entrypoint ignored PROFILE and the profiler dir Hyperloom hands it (see bypass_scriptable.py: PROFILE=1 plus VLLM/SGLANG_TORCH_PROFILER_DIR), so all three candidates were empty, the profile phase failed three times and the whole 2026-09-30 pass ran in degraded mode with no roofline to direct the search -- which is how it reported 0.00% gain against a blind search space. With PROFILE=1, run the existing, already-proven HRX trace production (hrx-tracelens.sh -> hrx2kineto.py -> trace.json) and write it where the executor globs: <trace dir>/rank_0.trace.json.gz. The box lock is taken earlier in this script, so BOX_LOCK is cleared for the helper -- a second flock on the same file from a child would deadlock. Failure here is loud but non-fatal: the benchmark number still counts.
|
Persistent review updated to latest commit 4d56c4a |
The profile leg traced HRX_BIN, defaulting to a separate shape-log build, while the benchmark measures $REPO/build/bin. That would aim the roofline -- and so the whole optimisation -- at a binary nobody measured. Hyperloom's own profile_custom.yaml warns about exactly this: a trace of a different run than the headline number is worthless. Now prefer this checkout's build, and fall back to a shape-log build only when this one lacks GGML_HRX_DISPATCH_SHAPE_LOG, printing a warning that says the trace then describes a DIFFERENT build. `strings` on libggml-hrx.so.0 is the test, since the instrumentation is a runtime shape log rather than a CLI flag. Re-tested with stubs: fallback path warns and still produces a valid gzip; a build carrying the shape log takes the direct path with no warning; PROFILE unset remains a no-op so the baseline leg is untouched.
|
Persistent review updated to latest commit fb0abc2 |
…produces a trace The profile leg failed end to end for two reasons that only running it exposes: - iree-profile was hard-coded to a path that does not exist, and the two tools on the box are a month older than the v2 profile the current HRX writes, so they abort with "unsupported IREE HAL profile file version". Derive the tool from HRX_BIN's own deps build instead (IREE_PROFILE, then PATH). - hrx2kineto's op-level match needs the command buffer's dispatch order to equal the logged program's build order; the runtime may reorder it (multisets match, orders do not), so no trace is written and Hyperloom's profile phase degrades. Fall back to a kernel-level trace, which TraceLens accepts, so the phase yields real data instead of failing. README records all three limitations and the order-independent matcher that would remove the fallback.
|
Preparing review... |
…ofile leg fell back `strings $B/libggml-hrx.so.0 | grep -q GGML_HRX_DISPATCH_SHAPE_LOG` under `set -o pipefail` returns non-zero: `grep -q` exits on the first match, `strings` is killed by SIGPIPE, and the pipeline status is the failure. On a build that carries the shape log the check therefore ALWAYS took the fallback branch and traced $HRX_SHAPELOG_BIN (a build that does not exist here), so the Hyperloom profile leg produced no trace and the pass degraded -- exactly as observed on 2026-10-05. `grep -c` reads to EOF, so nothing is killed. Verified with the check under pipefail.
What
tools/hyperloom/hrx2kineto.py— converts HRX dispatch profiles (iree-profile dispatch --format=jsonl) into a Kineto trace, so Hyperloom/TraceLens and TraceDiff can analyse HRX runs.cpu_op+cuda_runtime+ kernel event per dispatch.--shapes/--commands: joins each dispatch to theggmldispatch match that emitted it (fed by the llama.cpp fork'sGGML_HRX_DISPATCH_SHAPE_LOG) and emits onehrx::<ggml op>cpu_opper match execution carrying input dims/type/strides, the fused op chain, FLOPs and bytes, nested underhrx::step/hrx::layerso TraceDiff aligns runs layer by layer.--extension_file(GEMM/GroupedGEMM/SDPA/NORM/RoPE/reduce/SSM/elementwise perf models), with--write-arch(gfx1151 roofline JSON),--summary(per-op roofline table with concurrent-dispatch overlap) and--tracediff-top.tools/hyperloom/hrx-tracelens.sh— one-command driver: profile prompt or decode → convert → TraceLens report, optional TraceDiff, with a thermal watchdog, a box lock and a memory pre-check.Why only one commit
This was recovered from an unreported branch of 18 commits. 17 of them are already in
main— merged by PR #306, whose squash91dc6f9has exactly the branch's merge-base as its parent. Verified:So opening a PR from that branch would have re-introduced ~18,864 deletions. This PR is just the one genuinely unmerged commit, cherry-picked onto current
main.Dependency
The
--shapes/--commandspath needs the llama.cpp fork branch1bit/hrx-dispatch-shape-log(GGML_HRX_DISPATCH_SHAPE_LOG), which is not in the engine pin — so CI can build and lint this, but cannot exercise--shapes. It needs a Strix Halo run with that build to verify. The positional (base) path is byte-compatible with the previous behaviour.Risks flagged in review (offline tooling, not runtime — no GPU/NPU lifetime impact)
hrx2kineto.py:328,:575and:843usejson.dump(..., open(dst, "w"))with nowith, relying on CPython refcount flushing at exit.model_matchindexesprimary["out"]at:232,:248,:262,:274-277with no null check — a shape-log node withoutoutaborts the conversion (notry/exceptanywhere).map_command_buffers(:369) assumes program uids increase with execution order and each command buffer is used once. A reused buffer or non-monotonic uid attaches the wrong program → wrong op identity/shapes/FLOPs. Wrong answer, not an error.convert_shapes(:428-446) matches bygraph_uidonly; unmatched executions are counted (missed) and silently fall back to build-time names, so layer numbers can be wrong.--summaryoverlap (:623-628) only looks back 16 events, so%ovlunderstates wide fan-outs (e.g. concurrent Q/K/V).hrx-tracelens.sh:51-54: if nok10temphwmon,$Kis empty and the arithmetic error insidewhile :silently disables the 93 °C guard;pkill -f "$BIN/llama-"uses a build path as an unescaped regex against the whole process table.hrx-tracelens.sh:45-48hard-codes personal defaults ($HOME/wt/hrx2kineto-src/build/bin,$HOME/wt/hrx-disasm-test2/...) — worth parameterising before this is used by anyone else.tools/copyright.py --checkpasses.Not to be merged: the release is on hold until the owner calls it.