hyp E: TP collectives, not the second card's DRAM, are a slice of the 48.6 ms step #57
Labels
No labels
human-approved
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
bitpartner/tt-stack#57
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Parent: the P150 single-stream ≤25.0 ms issue.
Claim
Two P150a cards shard the weights, so each reads ~10.76 GB at the same time. That does not make one user's decode twice a single card: every token pays a collective to put the sharded result back together. On the Arc Pro B70 lab (Sept 2026, no-MTP), TP2 all-reduce was ~47% of device time and 2× FP8 was 33 tok/s against 19 tok/s on one card — not a doubling. Our 2-card no-MTP number is 20.6 tok/s. A large CCL tax on the fused production path would explain part of the ~15 ms residue and would mean the second card cannot deliver the missing ~20 ms.
TPAttentioncannot run at TP=1 (n_local_kv_headsexists only fornum_devices > 1). Do not shim a TP=1 baseline and call it a measurement.Falsifier
In the production fused decode forward, count the collectives per token (all-gather, reduce-scatter, barrier). For each: bytes, which tensors, which layers (48 GDN vs 16 attention vs lm_head), and whether
LM_HEAD_GATHER_MODE=nonealready removed the logits all-gather (it should have: host concatenates vocab/2 shards; that concat is inside the 3.3 ms host, not a win to re-claim). Estimate a latency floor from the bytes at the measured 450 GB/s and say why a collective is usually latency-bound rather than that byte floor. Rank the single largest collective.If the sum of plausible collective time is under ~2 ms, close this hypothesis in the comment. If it is a multi-millisecond slice of the 15 ms, name the one collective whose removal or overlap is the experiment. No boot during the code drill. No TP=1 shim. No MTP. Do not start serving.
Already known, do not re-derive
Parent: #53. Code drill only — do not boot the cards, do not start tenstorrent-serving.service, do not edit the tree. Comment the falsifier here.
Supersedes "do not boot". Card use is the cfx-llm2 lock: atomic mkdir /tmp/ttlock, owner hyp-57 in /tmp/ttlock/owner, release only if that owner is still yours, trap exits on signal. If mkdir fails, read the owner and do not wait. MemAvailable ≥ ~4 GB. docker stop -t 60, never docker rm -f on a live container. Do not start tenstorrent-serving.service. See #53.
Count from the production source: 257 collectives per token. I cannot close this at < 2 ms from code.
Per layer, all 64 layers, 4 collectives:
attention_norm:DistributedNormall-gathers the fractured residual before the norm in decode (all_gather_asyncdim=3).tt_all_reduce, which on a 1xN mesh isreduce_scatter_minimal_async:forward_decode→tt_all_reduce(patches/k/tp-k1-conv-gates.py:1195)attention/tp.py:837ffn_norm: the same pre-norm all-gather.tt_all_reduce→ reduce-scatter (mlp.py:341).Plus one all-gather for the final norm (
_final_norm_decode,model.py:631).lm_head: with
QWEN36_LM_HEAD_GATHER_MODE=nonethere is no logits all-gather (model.py:610-620returns the vocab shard as ROW_MAJOR). Confirmed; nothing to re-claim.Bytes. M is padded to 32 rows even at B=1. Each all-gather moves 32×2560 bf16 = 160 KB per device, and each reduce-scatter sends half of a 320 KB partial. That is about 41 MB per token. At 450 GB/s it is about 0.1 ms, and at an assumed ~100 GB/s over 2 ethernet links about 0.4 ms. So bytes are not the cost.
Latency. Each op is an async fabric handshake with a barrier semaphore and EDM round trips. At an assumed 10–30 µs per op (a guess; no P150 per-op number exists), 257 ops cost 2.6–7.7 ms. That range straddles the 2 ms close line.
Only third-party evidence of sensitivity: a second QSFP-DD cable measured −1.35 ms in the external tree (
docs/EXTERNAL-LEDGER.md, lever E). That is a hardware ask, not a flag.Largest single collective. Unresolved per op. By count, the 128 pre-norm all-gathers and the 128 reduce-scatters are equal.
Falsifier. No separate boot: the CCL rows of the #55 profile table. Close this issue if the CCL sum is < 2 ms. If it is ≥ 2 ms, the experiment is to wire the existing but unused
tp_common.matmul_reduce_scatter_decodefor MLP down, 64 per token. It can hide at most min(RS, down matmul) per layer: under ~2 ms total, and only the RS half. That is still not one diff:mlp.pyis baked into the image, anddecode-serving-ab.shdoes not mount it.Performance advisory (automated review, 2026-09-24)
A measured per-op CCL latency already exists, so the "10–30 µs guess" can be replaced with a number.
bench/probes/round2-reader/ccl_latency.pyran on 2026-09-12 (log:docs/advisory/round2-logs/ccl_full.log). It covered the decode shape ([1,1,32,5120]bf16, 1×2 mesh, traced, 20 interleaved samples x 30 iterations, exact validation):reduce_scatter_minimal_asyncall_gather_asyncAt 257 collectives per token that is ~6.6 ms/token. This is an ESTIMATE for the in-model cost. It could be lower, because each sample is one single-op trace launch and so includes launch overhead. It could be higher, because in-model rank skew and producer waits add time. Either way it is well above your 2 ms close line, so #57 should not close. CCL is plausibly the largest single class in #55's ~15 ms residue. Caveats: the probe ran with
num_links=1andpersistent_output_buffers=None, while productiontt_all_reduceauto-selects 2 links for P300 (docs/EXTERNAL-LEDGER.md:74-84).Cheapest next measurement (no model boot, minutes of device time): extend that probe rather than waiting on #55. Measure:
--links 2.docs/advisory/ADVISORY-DECODE-RESIDUAL-20260912.md[S2]. That advisory estimated 0.5–3 ms for this lever.all_reducevs the RS→AG pair at the same shape. Today every sub-layer boundary pays a reduce-scatter after the out-proj and then an all-gather before the next norm, which together are an all-reduce. If a fused all-reduce costs about one op's latency, the per-token count drops from ~257 to ~129.What this is not. It is not the closed "op-count" line. That line is closed because host dispatch is amortised inside trace. CCLs cost device-side handshake latency, which trace does not hide, and the probe measures exactly that.
Makespan conversion:
bench/runs/sweep-32k-20260914T142154Z.jsonl).Traps:
matmul_reduce_scatter_decodeexists but has no call sites. The fused path needs RS workers on rows disjoint from the matmul grid (tp_common.py:473-476warns that a full-grid fused CCL deadlocks).