VT_CUDA_GRAPH_DEDUP=1 (PR #1178, ENG-CUDAGRAPH-DEDUP, #1162) cannot complete a
single decode step once a CUDA graph is actually captured. Found by the owed device
gate on dgx:gpu0, which the change had not yet run.
Measured
Commit e4ce5571a, GB10 / sm_121a, driver 580.173.02, boot id
1cf6179f-0150-4052-b507-506fd6751953, leased through rc. Model
Qwen3ForCausalLM 0.6B bf16, model.safetensors sha256 11293257…6f6641. Same
binary in every cell (sha256 2f689337…f824d2); arms differ only by
VT_CUDA_GRAPH_DEDUP.
Every dedup=1 run dies in this exact order:
vt graph dedup: captured 1 graphs, deduped to 1 execs
[Qwen3DenseDecodeGraph] captured dense decode graph for padded size S=8 (real B=8)
engine-fatal: EngineCore busy loop threw: vt cuda: greedy_argmax launch: invalid device function
[Qwen3DenseDecodeGraph] dense decode graph: 1 total replays across 1 captured size(s)
| cell |
VT_CUDA_GRAPH_DEDUP |
exit |
decode-graph stats |
ids sha256 |
| s8_off_a / s8_off_b |
unset |
0 |
92 replays / 1 size |
a2ed218d…acdeac |
| s8_zero |
0 |
0 |
92 replays / 1 size |
a2ed218d…acdeac |
| s8_on_a / s8_on_b |
1 |
1 |
1 replay / 1 size |
MISSING |
| s16_off_a / s16_off_b |
unset |
0 |
140 replays / 1 size |
a7cee2a5…7aeb55 |
| s16_on_a / s16_on_b |
1 |
1 |
1 replay / 1 size |
MISSING |
Isolation, 6 cells, one job, same binary: the failure needs both dedup=1
and a graph that is actually captured. QWEN3_DENSE_DECODE_GRAPH=0 → clean;
VLLM_CPP_CUDAGRAPH=0 → clean; dedup off with the graph on → clean (59 replays);
dedup on with the graph on at batch 1 → dies after 1 replay. CUDA_LAUNCH_BLOCKING=1
does not move it, so it is not a deferred asynchronous error from an earlier
operation. 6/6 deterministic.
Consequences. Byte-identity cannot be established at all — the deduped arm
produces no artifact. And the benefit is unmeasured too: every ON run reports
captured 1 graphs, deduped to 1 execs, a 1:1 ratio, so no fold ever happened.
Cause: a latched CUDA runtime error, misattributed to the next kernel
greedy_argmax is not at fault. src/vt/graph_dedup_runtime.h walks the retained raw
graph with runtime APIs and checks each return code but never clears the runtime's
latched error. grep -n "cudaGetLastError\|hipGetLastError" src/vt/graph_dedup_runtime.h
returns nothing. The next raw launch using the ordinary
kernel<<<>>>(); Check(cudaGetLastError()) pattern then reports that stale code as its
own, which is why it names an unrelated kernel and why cudaGraphLaunch itself returns
success — it is checked on its return value, which does not consume the latch.
Twelve sites swallow a non-success return without clearing:
graph_dedup_runtime.h:98,100,115,130,137,146,154,173,179,281,307,317.
Two of those are the worst, because failure there is by design, not exceptional:
The signature walk's five degradation escapes (:115,130,137,146,154) are the same
class. This is precisely the risk the fresh review recorded as MEDIUM-3: those 356 lines
have zero executable coverage, and the predicted invisible mode was "a signature
unstable for one topology folds nothing while every CPU test stays green, and the only
observable is the device-only log line". The review called the class; the device gate
found the instance.
Why nothing else caught it
Green at the time of discovery: the full local agent-preflight.sh, cuda-fat-build,
both sanitize-cpu legs, build-test-cpu, 13 focused cases / 65 assertions, and 4/4
negative mutations — plus a fresh adversarial review. No CPU-tier instrument can see
this, because the tests drive a fake ops table and never touch the CUDA runtime's
latched-error state.
Scope
- Clear the latched error at the boundary of every runtime call in
graph_dedup_runtime.h that is allowed to fail, so a by-design refusal cannot be
misattributed downstream.
- Re-run the device A/B on
dgx:gpu0 and establish byte-identity, which is still owed.
- The exec-count ratio is also still owed: the workload held a steady concurrency, so
only one padded size was ever captured and the multi-bucket fold was never exercised.
Not a production regression: VT_CUDA_GRAPH_DEDUP is default OFF, and the unset and
=0 arms are byte-identical across 7 runs.
Two caveats on the environment, recorded rather than hidden: the worker container carries
CUDA 13.3.73 against the recorded dgx gate stack of 13.0.88, and its own cuBLASLt could
not capture in either arm, so the runs used a locally staged cu130 libcublasLt. The
OFF arm is clean under that identical library in 7 runs, which is what makes the
ON/OFF asymmetry arm-attributable, but the absolute stack is not the gate stack and this
wants a re-run on 13.0.88.
Evidence: dedup-gate/EVIDENCE.md, logs4/, logs5/, out4/, mirrored on the NAS at
/mnt/nas_share/rc/dedup-gate/.
Owned by ENG-CUDAGRAPH-DEDUP. Blocks #1162.
FOLLOWING_AGENTS_PROTOCOL
Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
VT_CUDA_GRAPH_DEDUP=1(PR #1178,ENG-CUDAGRAPH-DEDUP, #1162) cannot complete asingle decode step once a CUDA graph is actually captured. Found by the owed device
gate on
dgx:gpu0, which the change had not yet run.Measured
Commit
e4ce5571a, GB10 /sm_121a, driver580.173.02, boot id1cf6179f-0150-4052-b507-506fd6751953, leased throughrc. ModelQwen3ForCausalLM0.6B bf16,model.safetensorssha25611293257…6f6641. Samebinary in every cell (sha256
2f689337…f824d2); arms differ only byVT_CUDA_GRAPH_DEDUP.Every
dedup=1run dies in this exact order:VT_CUDA_GRAPH_DEDUPa2ed218d…acdeaca2ed218d…acdeaca7cee2a5…7aeb55Isolation, 6 cells, one job, same binary: the failure needs both
dedup=1and a graph that is actually captured.
QWEN3_DENSE_DECODE_GRAPH=0→ clean;VLLM_CPP_CUDAGRAPH=0→ clean; dedup off with the graph on → clean (59 replays);dedup on with the graph on at batch 1 → dies after 1 replay.
CUDA_LAUNCH_BLOCKING=1does not move it, so it is not a deferred asynchronous error from an earlier
operation. 6/6 deterministic.
Consequences. Byte-identity cannot be established at all — the deduped arm
produces no artifact. And the benefit is unmeasured too: every ON run reports
captured 1 graphs, deduped to 1 execs, a 1:1 ratio, so no fold ever happened.Cause: a latched CUDA runtime error, misattributed to the next kernel
greedy_argmaxis not at fault.src/vt/graph_dedup_runtime.hwalks the retained rawgraph with runtime APIs and checks each return code but never clears the runtime's
latched error.
grep -n "cudaGetLastError\|hipGetLastError" src/vt/graph_dedup_runtime.hreturns nothing. The next raw launch using the ordinary
kernel<<<>>>(); Check(cudaGetLastError())pattern then reports that stale code as itsown, which is why it names an unrelated kernel and why
cudaGraphLaunchitself returnssuccess — it is checked on its return value, which does not consume the latch.
Twelve sites swallow a non-success return without clearing:
graph_dedup_runtime.h:98,100,115,130,137,146,154,173,179,281,307,317.Two of those are the worst, because failure there is by design, not exceptional:
:307and:317— thecudaGraphExecUpdateprobe. The whole safety argument forthis feature is that a probe refusal is normal and simply means "do not fold". Every
routine refusal therefore poisons the runtime for the next unrelated kernel.
:281—cudaGraphInstantiatefailing, the path feat(ENG-CUDAGRAPH-DEDUP): fold captures that share a topology onto one graph executable #1178's own MEDIUM-1 repair added aVT_CHECKfor.The signature walk's five degradation escapes (
:115,130,137,146,154) are the sameclass. This is precisely the risk the fresh review recorded as MEDIUM-3: those 356 lines
have zero executable coverage, and the predicted invisible mode was "a signature
unstable for one topology folds nothing while every CPU test stays green, and the only
observable is the device-only log line". The review called the class; the device gate
found the instance.
Why nothing else caught it
Green at the time of discovery: the full local
agent-preflight.sh,cuda-fat-build,both
sanitize-cpulegs,build-test-cpu, 13 focused cases / 65 assertions, and 4/4negative mutations — plus a fresh adversarial review. No CPU-tier instrument can see
this, because the tests drive a fake ops table and never touch the CUDA runtime's
latched-error state.
Scope
graph_dedup_runtime.hthat is allowed to fail, so a by-design refusal cannot bemisattributed downstream.
dgx:gpu0and establish byte-identity, which is still owed.only one padded size was ever captured and the multi-bucket fold was never exercised.
Not a production regression:
VT_CUDA_GRAPH_DEDUPis default OFF, and the unset and=0arms are byte-identical across 7 runs.Two caveats on the environment, recorded rather than hidden: the worker container carries
CUDA 13.3.73 against the recorded dgx gate stack of 13.0.88, and its own cuBLASLt could
not capture in either arm, so the runs used a locally staged cu130
libcublasLt. TheOFF arm is clean under that identical library in 7 runs, which is what makes the
ON/OFF asymmetry arm-attributable, but the absolute stack is not the gate stack and this
wants a re-run on 13.0.88.
Evidence:
dedup-gate/EVIDENCE.md,logs4/,logs5/,out4/, mirrored on the NAS at/mnt/nas_share/rc/dedup-gate/.Owned by
ENG-CUDAGRAPH-DEDUP. Blocks #1162.FOLLOWING_AGENTS_PROTOCOL
Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]