Repository navigation
docs(ArcQuant/ArcInfer): V4 could not serve past ~22 tokens — TCFRAG held 63 GB (wave66-CS) - #214
Merged
Merged
Conversation
Code Metrics Report━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Language Files Lines Code Comments Blanks ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ C Header 5 305 210 52 43 CSS 2 1181 1036 34 111 CUDA 81 29464 20161 6264 3039 Dockerfile 1 39 22 8 9 JavaScript 16 3546 2676 482 388 Jinja2 7 694 656 5 33 JSON 75 4896 4893 0 3 Makefile 1 6 5 0 1 Metal Shading Lan| 33 12224 9431 1142 1651 PowerShell 1 300 227 30 43 Python 147 15371 12677 824 1870 Shell 42 10274 6849 2750 675 Plain Text 4 3801 0 2479 1322 TOML 33 1498 1294 54 150 YAML 3 25 23 2 0 ───────────────────────────────────────────────────────────────────────────────── HTML 4 2687 2604 43 40 |- CSS 2 543 479 37 27 |- JavaScript 1 1233 1215 12 6 (Total) 4463 4298 92 73 ───────────────────────────────────────────────────────────────────────────────── Jupyter Notebooks 4 122 83 23 16 |- Markdown 1 60 30 22 8 |- Python 1 122 113 1 8 (Total) 304 226 46 32 ───────────────────────────────────────────────────────────────────────────────── Markdown 212 47877 0 37224 10653 |- BASH 72 1655 1203 331 121 |- C 3 17 17 0 0 |- CUDA 2 84 56 16 12 |- JSON 19 779 779 0 0 |- PowerShell 1 1 1 0 0 |- Python 23 1008 787 113 108 |- Rust 67 2058 1723 77 258 |- TOML 6 207 164 0 43 |- YAML 5 41 36 5 0 (Total) 53727 4766 37766 11195 ───────────────────────────────────────────────────────────────────────────────── Rust 680 340521 292882 18037 29602 |- Markdown 503 32080 471 27656 3953 (Total) 372601 293353 45693 33555 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Total 1351 514719 362803 97723 54193 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ |
…e-user number is void (wave66-CS) The durable record of session 9. Issues are disabled on this repo, so this is the issue. THE BLOCKER. At cc5487a on an H200, batch=1 decode dies with CUDA_ERROR_OUT_OF_MEMORY after 22-30 generated tokens, 3/3 runs, two independent arms. Growth is ~11 MiB/token and is never released across requests: one run ended at 142,959 MiB used and the next started there. The card is genuinely full at failure, 143,151 of 143,771 MiB. Consequence, stated as strongly as the evidence supports: every single-user V4 throughput number this project has recorded was measured over <=30 tokens before a crash. The three-way b=1 agreement (15.11 / 15.39 / 15.51 tok/s) has "24 tokens" written in its own FACTS row. The best clean fragment tonight was 37.35 tok/s over 20 tokens - a fragment, not a rate. Six more findings, each with its ref: TCFRAG was default-ON with "UNVERIFIED ON HARDWARE - NEVER RUN" in its own header (fixed, #209); two host round-trips per decode step, not one; the dedicated decode tier cannot accept V4 architecturally; the b=1 FP8 GEMV is instruction-bound; four instrument failures; and #182 is a precondition whose hazard is masked by the OOM. Retractions added to FACTS: the 5,300-cast / 1,571-MHC premise (stale, profiled at 05af600), DecodeKvGeometry (never existed in Rust), the 27.2% TAIL (sole source is a docs file not on master), the latency-bound b=1 story, and "op count is retired as a lever". Corrections made while verifying, all against 9c127a2 rather than against the report: normal.rs:2515 -> :2619; has_cached_kv_info is 3 prose references and 0 definitions, not zero occurrences; ba026e9 is a root/import commit and introduced nothing; the TCFRAG OnceLock does not panic, it caches None permanently; tcfrag2b.rs:151-157 -> :151-158; the 2.97 TB/s issue ceiling used the FP32 warp rate, and the INT32 pipe gives 1.49, so the defensible claim is a 1.5-3.0 TB/s range; ARC_NO_DEFERRED_FREE was overstated; and mark_unreachable being dark was already on the record from session 8. Also surfaced, unresolved: PR #182's H200 leg ran 2,600 tokens with no OOM, which needs >=15.7 GB free at decode start against tonight's 844 MiB. Nobody has explained the ~60 GB gap, and if it is the serve config then this is a concurrency-budget defect as much as a per-token leak. Gates: doc_citations 12/12 green, run standalone against this tree, and the gate reproduced a real failure on an earlier revision of this file first, so the green is not vacuous. typos clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UMmjFy8TvsgypxVWNVhhC7
…26-08-21 The blocker block at the top is no use if the read order still sends people to the session-8 FACTS section first. Adds wave66-CS as item 2 (before the census, because a GPU-spend decision made on void single-user numbers is worse than one made late) and renumbers. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UMmjFy8TvsgypxVWNVhhC7
… round-trips The first wording said the 1,137x launch cut "left two host syncs in both arms", which is wrong: the eager arm never replays a graph, so it never reaches graph.rs:362. The correct and stronger statement is about the CAPTURED arm — it still pays the replay sync and the sampler's 4-byte D2H, so the CPU never left the loop and the ~8% cannot be read as the value of removing it. Also adds the guard against over-claiming in the other direction: this does not show the two syncs ARE the limiter, only that the experiment could not see them. The number that would settle it has not been taken. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UMmjFy8TvsgypxVWNVhhC7
…arity cuts both ways The env-flag consequence was stated as "both arms ran with the feature on". That holds for the 13 .is_some() flags; for the 5 .is_none() ones, =0 counts as set and therefore SUPPRESSES, so the legs are inverted rather than identical. Either way the control leg was not a control, but the two failure shapes are different and a reader debugging an old A/B needs to know which one they have. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UMmjFy8TvsgypxVWNVhhC7
It was cross-referenced loosely as "the same provenance problem as the 27.2%". Both numbers live on the same line of docs/engineering/OPENROUTER_READY.md, which is not on master — it exists only on agent/tail-sinkhorn-warp-v2 and agent/decode-share-probe. One of the two is already being multiplied into a projected win, so the pointer should be explicit rather than a cross-reference. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UMmjFy8TvsgypxVWNVhhC7
#209's merged doc comment argues TCFRAG "owns the whole of the b=1 decode path" and cites the .cu header for it. The header says that about qtip2b_gemv_tuned_kernel — the shipped kernel TCFRAG was written to replace — at qtip2b_tcfrag.cu:19, not about TCFRAG. The conclusion is still right, and the two dispatch sites in bitshift.rs establish it without the quote, so this changes nothing about #209 being the correct fix. But the quoted sentence does not say what it was cited as saying, and it is now on master saying it. Recorded rather than left for someone to re-derive. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UMmjFy8TvsgypxVWNVhhC7
The box measured the missing ~60 GB after this file was drafted: ARC_QTIP_TCFRAG=0 frees 64,262 MiB against 262 MiB with it on. tcfrag_words is a per-weight OnceLock caching a repacked copy of every weight for the process lifetime — ~63 GB against a ~79.5 GB model. #182's leg predates TCFRAG, so it had ~15.7 GB of headroom and survived 2,600 tokens at the same per-token rate. Same leak, two orders of magnitude less room. The concurrency-budget hypothesis is WITHDRAWN. It was a fair reading of the evidence available; the measurement removed the need for it. Attribution corrected: two independent single-variable rescues each work alone (ARC_QTIP_TCFRAG=0 -> 256/256 tokens x5; ARC_CANDLE_ALLOC_CACHE=0 -> 1,000 tokens), so #209 restored the headroom and #213 is defence in depth on the rate. Also splits an over-claim of my own. "Every single-user number was measured inside a crashing run" is two claims and only one is universal: A: every V4 single-user tok/s figure is a <=30-token short window. Stands. B: "inside a crashing run" holds only at or after cc5487a (#203, today). The b=1 trio is from 08-17, before TCFRAG existed - its 24 was a harness choice, not a truncation. Claiming otherwise would be a fabrication. And the 33.4 -> 34.2 pair is a third case: its source CAPTURE_LANE.md exists nowhere in this repo, on any branch. Unsourced, like the 27.2% and the 16.0%. Drops the unsourced "declined 4 of 4 loads" claim, records that #210 merged with a projection multiplied out of the unsourced 16.0% share, and notes #211 merged (registers the hazard; the pin is still unwritten) - and that #209 un-masks it, since 256-token runs now live long enough for the probe to mean something. cuda_ops.rs: fix the mis-quote #209 shipped. The header phrase "the whole of the b=1 decode path" describes qtip2b_gemv_tuned_kernel, not TCFRAG. The conclusion rests on the dispatch sites instead. Adds the 63 GB retention to the gate's doc comment, where the next reader of #203 will look. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UMmjFy8TvsgypxVWNVhhC7
…f them Master moved twice more while this was being written (#210 -> f709872, #205 -> fdf0b6c). #205 added +292 lines to normal.rs, +275 to layers.rs and +144 to deepseek4.rs, moving fifteen citations in this file including every mark_unreachable site and the return Ok(None) that section 4 is built on. doc_citations stayed GREEN through both. That is not a gate failure, it is the gate's contract: it checks a line is in RANGE, not that it is the RIGHT line, and a citation with no backticked symbol gets no symbol check at all. Recorded in the provenance block, because it is the most useful thing on the page for anyone maintaining these docs. Everything re-derived by grep, twice. Corrections: normal.rs 1432->1465, 2379->2665, 2370->2656, 2575->2861, 2604->2890, 2619->2905, 2977->3263, and the six mark_unreachable sites 1556/1635/1921/2404/2474/2602 -> 1589/1668/1954/2690/2760/2888; deepseek4.rs 2968->3030, 3149->3190, 3165->3206, 3283->3324, 3334->3375, 2219->2281; cuda_ops.rs 1601->1614, 1612->1627; graph.rs 214->212; blockwise_fp8/ops.rs 1139->1179, 1140->1180; and three self-citations into 00_RESUME_HERE.md that my own edits had shifted. Also notes that master's own code carries the same rot: the site marker inside mark_unreachable("cuda_graph.autonomous_decode.capture") still reads "normal.rs:2619". It is a string literal, so the gate cannot see it by design. Title no longer says "taken inside a crashing run" — that was the half of the claim the TCFRAG measurement showed is not universal. Verified capture is still default-off after #205 (ARC_V4_CAPTURE_PROBE, unset, normal.rs:1940), so section 7's sequencing statement stands. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UMmjFy8TvsgypxVWNVhhC7
heydryft
force-pushed
the
docs/session9-the-22-token-wall
branch
from
August 21, 2026 14:06
16018ae to
df0e29f
Compare
The "Owner: PR #213" block still sat above the TCFRAG resolution and read as if #213 owned the blocker. Moved below it and retitled "the rate half", with the part of #213's diagnosis that survives stated plainly: the 1 GiB constant really was unreachable at 844 MiB free, and that stays true at any headroom small enough to matter. It is worth landing; it is not why serving was broken. Adds the sequencing point that follows: #213's falsification criterion wants a 256-token run, which only exists because #209 landed. Testing it against a 22-token crash would have measured nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UMmjFy8TvsgypxVWNVhhC7
Three corrections to my own text: - The FACTS session-9 header still asserted "every single-user V4 tok/s figure was measured inside a crashing run", which the Claim A/B split immediately below it contradicts. Header now states the universal half (<=30-token fragment) and points at section 2 for what it does and does not void. - Provenance SHA f709872 -> fdf0b6c (#205 landed after the rebase). - TCFRAG (#203, cc5487a) landed 2026-08-21, not 08-20. git log -1 --date=short is the check; the date is load-bearing because it is what establishes that #182's leg predates TCFRAG. Also 11 -> ~11.8 MiB/token where the retained figure is contrasted with wave65-CQ's ~22 MB/token moved, so the two are not confusable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UMmjFy8TvsgypxVWNVhhC7
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.
The durable record of session 9. Issues are disabled on this repo, so this is the issue.
Rebased onto
fdf0b6c19. Every citation re-verified there — see "the citations rotted twice" below, which is the most reusable thing in this PR.What lands
memory/mission/wave66-CS-session9-the-22-token-wall.md(new) — seven findings, each with its ref and how it was established.FACTS.md— a2026-08-21block with the measured numbers and seven retraction rows, plus an in-situ marker on the b=1 table.00_RESUME_HERE.md— the blocker prepended above everything.mistralrs-quant/src/qtip/cuda_ops.rs— comment-only. Fixes a mis-quote fix(ArcQuant): make ARC_QTIP_TCFRAG opt-in — an unverified kernel is default-on for b=1 decode #209 shipped, and records the 63 GB where the next reader of perf(ArcQuant/ArcKernels): TCFRAG-2B — put the qtip2b trellis GEMV on the tensor cores #203 will look. The only non-memory/edit.🔴 The blocker, and it is CLOSED — but not by the PR everyone expected
V4 died with
CUDA_ERROR_OUT_OF_MEMORYafter 22–30 generated tokens, 3/3 runs, card full at 143,151 of 143,771 MiB. It looked like an allocator leak. The leak was never what changed — the headroom was:ARC_QTIP_TCFRAG=0cc5487ad3)tcfrag_wordsis a per-weightOnceLockcaching a repacked copy of every weight for the process lifetime — ~63 GB against a ~79.5 GB model. That left decode 844 MiB free, so a ~12 MiB/token leak that PR #182's leg survived for 2,600 tokens killed this one in ~20. #182's leg predates TCFRAG entirely.Two independent single-variable rescues, each sufficient alone — which is what makes this an attribution rather than a story:
ARC_QTIP_TCFRAG=0→ 256/256 tokens, five runs,finish=length(cache still on);ARC_CANDLE_ALLOC_CACHE=0→ 1,000 tokens (TCFRAG still on).#203 costed instructions and never costed memory. The
.cu's performance section still only costs instructions.The tok/s consequence — two claims, and only one is universal
The brief said "every single-user number was measured inside a crashing run". The TCFRAG result forces that apart, and I did not keep the half that isn't supported:
cc5487ad3(perf(ArcQuant/ArcKernels): TCFRAG-2B — put the qtip2b trellis GEMV on the tensor cores #203, today). The b=1 trio is from 2026-08-17, before TCFRAG existed — its 24 was a harness choice, not a truncation. Claiming otherwise would be a fabrication.CAPTURE_LANE.mddoes not exist in this repo, on any branch. Unsourced, like the 27.2% TAIL and perf(ArcQuant/ArcKernels): fp8_gemv_wide — the b=1 decode GEMV is instruction-bound, not latency-bound #210's 16.0%.✅ A real steady-state single-user number is now obtainable for the first time — 256/256 runs clean. Nobody has taken it.
🔴 The citations in this file rotted twice while it was being written, and the gate caught neither
blockwise_fp8/ops.rs~40 lines. The kernel's own lines survived only because perf(ArcQuant/ArcKernels): fp8_gemv_wide — the b=1 decode GEMV is instruction-bound, not latency-bound #210 appended rather than inserted.normal.rs, +275 tolayers.rs, +144 todeepseek4.rs— moving fifteen citations, including everymark_unreachablesite and thereturn Ok(None)§4 is built on.doc_citationsstayed green through both, and that is its contract, not a bug: it checks a line is in range, not that it is the right line, and a citation with no backticked symbol gets no symbol check at all. A green gate is not a verified citation. Everything was re-derived by grep againstfdf0b6c19.Master carries the same rot in code: the site marker inside
mark_unreachable("cuda_graph.autonomous_decode.capture", …)still reads"normal.rs:2619", which #205 moved to 2905. It is a string literal, so the gate cannot see it by design.The other six
ci_cuda.yamlgating nothing and 21 presence-tested env flags where=0turns a feature ONCorrections to the brief, kept as corrections
normal.rs:2515→:2619→ now:2905.tcfrag2b.rs:151-157→:151-158.has_cached_kv_infois 3 prose occurrences, 0 definitions, and the misleading comment is already fixed in-tree.ba026e9d1is a root/import commit (1,430 files, 0 deletions) and introduced nothing — the analysis is6e58c5dbf. TheOnceLockcachesNonepermanently rather than panicking — same blast radius, different mechanism. "Declined 4 of 4" is removed as unsourced, and the 63 GB measurement points the other way: a repack that declined every time would retain nothing. The 2.97 TB/s ceiling used the FP32 warp rate; the INT32 pipe gives 1.49, so the honest form is the range 1.5–3.0 TB/s. "45 inst / 4 B" is derived from #210's own prose, not measured — probe iscuobjdump -sass.ARC_NO_DEFERRED_FREEwas overstated.mark_unreachablebeing dark was already on the record from session 8; only the consequence is new.One correction goes the other way: the 08-19 row narrowing "the default config silently disables prefix caching" is confirmed, not contradicted.
Gates
doc_citations12/12, run standalone (std-only) againstfdf0b6c19; zero drift from the new content. The green is not vacuous — the gate failed on an earlier revision of this file first, on adevice.rscitation inside the very sentence explaining why candle must not be cited that way.typosclean (two SHAs reworded rather than widening.typos.toml, per #211's precedent).cargo check -p mistralrs-quantgreen;cargo fmt -p mistralrs-quant --checkshows no diff incuda_ops.rs.Related: #209, #213, #211, #210, #212, #205, #206, #182, #203.
🤖 Generated with Claude Code
https://claude.ai/code/session_01UMmjFy8TvsgypxVWNVhhC7