Measured serving throughput and quality for current open-weight models on sm_120 — the architecture shared by the RTX PRO 6000 Blackwell (96 GB) and the RTX 5090 (32 GB). Run by Sqwish Labs in September 2026 to decide a two-year hardware commitment, and published because almost nothing about this architecture is written down: the datacentre kernels (sm_100) do not run here, and the defaults are wrong in ways that cost between 30% and 300%.
Everything here is reproducible from the scripts in box/. Every number is steady state with 6–8× as many
prompts as concurrent slots, a unique seed per run, and controls launched minutes apart in the same session.
Workload shapes (chosen for agent harnesses, not for leaderboards): router 1,024 in / 128 out ·
promptopt 3,072-token shared prefix + 512 in / 256 out · judge 4,096 in / 512 out · short 256 / 64 ·
rollout 8,192 / 2,048. Intelligence figures in brackets are the Artificial Analysis Intelligence Index
v4.2 (5 September 2026); a dash marks a model absent from its open-source view.
- NVFP4 beats FP8 by 64%, but only if you force the kernel. vLLM's auto-selection picks a W4A16
dequant kernel for a W4A4 checkpoint and lands 47% below FP8.
--kernel-config.linear_backend b12xorflashinfer_b12xare the only true W4A4 paths on this silicon. Always read theUsing … Kernelline the engine prints, and force the backend. - Use ModelOpt NVFP4 checkpoints, not compressed-tensors ones. RedHat and unsloth "NVFP4" builds are mixed precision: attention is FP8 with dynamic activation scales, which the b12x kernel refuses, so they fall back to 2,048 out tok/s where the ModelOpt build does 5,161.
- Never hard-code a mixture-of-experts backend — sweep it.
flashinfer_cutlass, correct for gpt-oss, is rejected outright by any four-bit expert checkpoint with group-16 scales. Eleven arms died on this in one night. When the engine rejects a backend it prints the set it accepts;tritonis not in it for NVFP4. - Four replicas beat one tensor-parallel server, by several times, whenever the model fits one card. There is no NVLink here; replicas exchange nothing.
--no-enable-flashinfer-autotuneon every tensor-parallel launch. If rank 0 has a cached autotune result and the others do not, the ranks desynchronise in a collective and the server hangs forever.- Per-architecture flags that are not optional. Qwen3.8-Flash-Next rejects an fp8 KV cache outright
(
Qwen4Exp QSA requires a BF16 main KV cache). MiniMax-M3 and Inkling need--enforce-eageron sm_120 — aKeyError: '/psm_…'is a worker segfault seen from the parent, not a config error. MiniMax also needs--block-size 128; GLM-5.3-Flash needs--block-size 1024for the DeepGEMM indexer. DeepSeek-V4-Flash needsVLLM_DSV4_OPROJ_SM120_FALLBACK=1in the server's environment: vLLM routes its attention output projection through DeepGEMM'sfp8_einsum, which has no sm_120 path and asserts during memory profiling for every MoE backend (box/patch_oproj.pyadds the BF16 fallback that flag enables). Three sweeps died blaming the MoE backend and the sequence budget before the traceback's frames were read. - Check
power.limitagainstpower.max_limitbefore trusting any host. The same cards at 400 W instead of 600 W lose 23% on NVFP4 and 34% on FP8. - On consumer cards, the container's CUDA must match the host driver. The cu130 image ships a compatibility shim that only works on datacentre GPUs; on an RTX 5090 host with a 575 driver every launch dies with CUDA error 804.
- Serve each model the way its vendor says to, or you are benchmarking your own harness. A missing
--reasoning-parsermakes the scorer grade the model's chain-of-thought; the wrong sampling costs more than any kernel here; andenable_thinkingdefaults differ per model, so a naive table compares some models thinking and others not. Worth +0.17 aggregate on Qwen3.8-27B — larger than every kernel finding in this document combined. Seebox/lists/profiles.tsv. - A model that does not fit one card is a different product. Replicas exchange nothing; tensor parallelism over PCIe without NVLink costs 8× throughput and turns a 0.7 s time-to-first-token into 324 s. Decide the memory ceiling before the card count.
Qwen3.8-27B, four replicas, one per card — the kernel comparison the whole campaign turns on. Same checkpoint, same session, only the backend changes:
| kernel the engine used | router C256 | router C1024 | promptopt C1024 | judge C512 | tripwire |
|---|---|---|---|---|---|
B12xNvFp4 W4A4 (b12x) |
4,288 | 5,161 | 4,804 | 4,400 | 19/20 |
FlashInferB12xNvFp4 W4A4 (flashinfer_b12x) |
4,304 | 5,182 | 4,842 | 4,448 | 20/20 |
| B12xFp8BlockScaledMM (FP8 checkpoint) | 2,642 | 3,148 | 2,992 | 2,799 | 19/20 |
| FlashInferCuteDslNvFp4 W4A16 (auto) | 1,608 | 1,671 | 1,637 | 1,621 | 19/20 |
Output tokens/s per node. The NVFP4 checkpoint is 17.9 GB against 29 GB for FP8, and faster — but the auto-selected kernel is slower than FP8 and slower than it looks, because it barely moves from C256 to C1024 while FP8 climbs 19%.
Other models on the same box:
| model (AA index) | configuration | shape | out tok/s | in tok/s | TTFT p50 |
|---|---|---|---|---|---|
| gpt-oss-120b (16) | 4 replicas, FlashInfer CUTLASS + mxfp8 | promptopt C2048 | 19,689 | 275,653 | 1.5 s |
| router C2048 | 9,948 | 79,581 | 1.0 s | ||
| short C2048 | 16,017 | 64,066 | 1.3 s | ||
| judge C1024 | 7,468 | 59,745 | 1.4 s | ||
| gpt-oss-20b (–) | 4 replicas, mxfp8 activations | router C2048 | 13,752 | 110,017 | 0.7 s |
| judge C1024 | 9,152 | 73,217 | 1.0 s | ||
| 4 replicas, Marlin (the default) | router C2048 | 9,956 | 79,649 | 1.0 s | |
| gemma-4-26B-A4B (–) | 4 replicas, BF16, vendor recipe | router C1024 | 9,119 | 72,952 | 1.1 s |
| promptopt C1024 | 15,502 | 217,028 | 1.2 s | ||
| judge C512 | 7,229 | 57,832 | 1.4 s | ||
| Muse-Glimmer-30B (24) | 4 replicas, BF16, vendor recipe | router C1024 | 3,029 | 24,232 | 3.5 s |
| promptopt C1024 | 7,751 | 108,514 | 4.8 s | ||
| judge C512 | 2,627 | 21,016 | 4.7 s | ||
| DeepSeek-V4-Flash (41) | TP4, b12x W4A4 experts, 256 seqs (this box) |
router C256 | 1,107 | 8,855 | 3.7 s |
| promptopt C1024 | 2,387 | 33,411 | 45.7 s ⁱ | ||
| judge C512 | 1,082 | 8,656 | 121 s ⁱ | ||
| same + DSpark speculation (7 draft tokens, 37% accepted) | router C256 | 665 | 5,320 | 4.8 s | |
| promptopt C1024 | 735 | 10,293 | 125 s ⁱ | ||
| DeepSeek-V4-Flash (41) | TP1 × DP4 + expert parallel, 512 seqs per engine (this box) | router C1024 | 1,640 | 13,124 | 7.6 s |
| promptopt C1024 | 4,430 | 62,024 | 6.4 s | ||
| same layout, 1,024 seqs per engine, 16k prefill batch | router C1024 | 1,584 | 12,674 | 15 s ⁱ | |
| promptopt C1024 | 4,293 | 60,106 | 13 s ⁱ | ||
TP4, b12x W4A4 experts, 512 seqs (the control) |
router C1024 | 1,245 | 9,962 | 53 s ⁱ | |
| DeepSeek-V4-Flash (41) | TP1 × DP4 + expert parallel, 256 seqs (first box) | promptopt C512 | 3,683 | 51,562 | 6.6 s |
| Marlin + EP | promptopt C512 | 3,002 | 42,032 | 3.1 s | |
| Qwen3.8-Flash-Next (46) | TP4, Marlin MoE, FP8 n-gram tables (patch_ple.py), auto linear kernel |
router C1024 | 1,442 | 11,538 | 70 s ⁱ |
| promptopt C1024 | 1,919 | 26,871 | 104 s ⁱ | ||
same, b12x W4A4 linear kernel |
router C1024 | 1,443 | 11,545 | 70 s ⁱ | |
| GLM-5.3-Flash (46) | TP4, ported vendor vLLM, 256 seqs | promptopt C256 | 1,002 | 14,030 | 2.7 s |
| router C256 | 920 | 7,362 | 2.2 s | ||
| judge C128 | 771 | 6,165 | 2.1 s | ||
| TP4, 512 seqs, 16k prefill batch | router C1024 | 911 | 7,288 | 64 s ⁱ | |
| promptopt C1024 | 992 | 13,887 | 115 s ⁱ | ||
| TP4 + expert parallel, 512 seqs | router C1024 | 931 | 7,449 | 62 s ⁱ | |
| promptopt C1024 | 1,008 | 14,108 | 120 s ⁱ | ||
| TP4, 512 seqs, MTP speculation (3 draft tokens, 10% accepted at this batch) | router C1024 | 592 | 4,738 | 101 s ⁱ | |
| TP1 × DP4 + expert parallel, 192 seqs per rank (the build's cap at TP1; quality 0.792, identical to TP4) | router C1024 | 1,073 | 8,585 | 97 s ⁱ | |
| DP2 × TP2 + EP, eager mode + Marlin MoE — the DGX Spark recipe; clean 19/20 tripwire, no 403-item run yet | router C1024 | 1,125 | 9,003 | 89 s ⁱ | |
| DP2 × TP2 + EP, eager mode, Triton MoE — clean tripwire, no 403-item run yet | router C1024 | 1,460 | 11,678 | 69 s ⁱ | |
| native FP8 (zai-org's release, 330 GB), TP4, 32 seqs — the budget the weights leave; quality 0.809 | router C32 | 500 | 4,000 | 1.7 s | |
| promptopt C32 | 527 | 7,383 | 2.6 s | ||
| judge C32 | 471 | 3,770 | 2.3 s | ||
| DP2 × TP2 + expert parallel, 384 seqs per rank — rejected by quality tripwire | router C1024 | 1,300 (diagnostic only) | 10,397 | 72 s ⁱ |
ⁱ Time-to-first-token here is queueing: the server admits 256 or 512 sequences and the shape offers 1,024.
GLM's ceiling was a step-time ceiling, and the step time was tensor parallelism. At TP4, doubling the
sequence budget from 256 to 512 and sharding the experts changed output throughput by 1% and 2%: the decode step
took about 200 ms at every setting, and that time is the four-way all-reduce over PCIe with no NVLink, plus a
Hopper attention backend ported to sm_120 and a 1,024-token DeepGEMM indexer block. Remove the all-reduce —
four independent engines with the experts sharded across them (TP1 × DP4 + EP) — and the step drops to 93 ms
and output rises to 1,073 tokens a second, +15%. It is not more because the vendor build caps a TP1 rank at 192
sequences (its linear-attention state cache), so the batch is shallower even though each step is twice as fast.
The faster DP2 × TP2 + EP run is not a usable winner: its own 20-item tripwire reports eight degenerate
outputs and one wrong answer. Its 1,300 tokens/s cannot be combined with quality measured at TP4. DP4 × TP1 + EP
passed all 20 tripwire items and is the candidate for a fresh full evaluation. Growing its Mamba cache remains
an unmeasured throughput opportunity. The build refuses the flashinfer_b12x expert kernel for this model
(swiglu_limit clamp not implemented); the captured DP runs actually selected FLASHINFER_CUTLASS NVFP4 MoE.
The MTP head makes it worse at saturation — 592 against 911, because only 10% of drafted tokens are accepted at
1,024 streams and every rejected draft is a wasted slot in a batch that was already full. The 403-item quality
run must apply to the exact accepted layout. The baseline uses NVFP4 expert weights and BF16 KV; the proposed
BF16 SSM-state and FP8 KV arms in box/glm_perf3.sh change precision and require their own paired quality gate.
The reversible FA2 planned-length diagnostic is documented in patches/glm_fa2_plan_audit.md. Its 403-item run has since landed: 0.792, paired against TP4 16 to 15 — identical — so DP4 + EP at 1,073 tokens a second is the qualified fast layout. Every lever tried on it refused (192 slots at TP1 whatever the SSM dtype, a 32k prefill chunk out of memory, FP8 KV for MLA Hopper-only). The TP2 diagnosis probes (eager mode, Marlin MoE, both, TP2 without expert parallelism; box/glm_perf5.sh, one change per arm, a 20-item probe as the verdict) were queued behind the native-FP8 run and did not execute: the box was destroyed at 00:27 UTC — an hour before the agreed stop — by the operator's own hard-stop script, which read its 01:27 cut-off in the host's local time (BST) rather than UTC; the results were pulled first and nothing already measured was lost. Nish granted one more hour and a fourth box ran them (600 W Server Edition, box/glm_hour.sh, provisioned from nothing in eight minutes): eager mode + Marlin MoE (the DGX Spark recipe): clean (19 ok, 1 degenerate, 0 wrong of 20); 1,125 out tok/s router C1024; Marlin MoE alone: degenerate (9 ok, 11 degenerate, 0 wrong of 20); eager mode alone: clean (18 ok, 1 degenerate, 1 wrong of 20); 1,460 out tok/s router C1024; TP2 × 2 without expert parallelism: not reached before the cut-off. Reading: the two-engine layout serves clean output with eager mode alone at 1,460 out tok/s on routing traffic — a 20-item tripwire, not a 403-item run; the layout is recoverable on this build and its full quality run is the next step. At the market-median API price the two-engine layout is 1.9× if it holds quality (see Economics). A merged FlashInfer change (PR #4802, 3 Sept 2026, not yet in a numbered release) adds a native GLM53_NOPE sparse-MLA path for SM120 with FP8 KV cache support, −24% decode latency at T=1 and 1.4–1.8× prefill over the path this port uses; our pinned FlashInfer 0.6.18 predates it. Re-basing the vendor port on it is the next kernel-level lever for GLM and would lift the FP8-KV refusal too. It is untested here.
DeepSeek's ceiling was a layout ceiling, and it moved. Tensor-parallel across four cards gave 1,107 output
tokens a second. Four independent engines with the experts sharded across them (TP1 × DP4 + EP), each admitting
512 sequences, give 1,640 at 1,024 concurrent streams — 48% more from the same weights and kernels, because
each card decodes its own batch and only the expert dispatch crosses PCIe. On shared-prefix traffic the gap is
wider still: 4,430 against 2,387, +86%, because prefix caching is per engine and four engines each hold the
whole prefix. The price is per-stream latency: 581 ms per token at that load on the router shape, 7.6 s to first
token. At 256 streams the same layout gave 1,289 (first box), so the gain is mostly batch depth that TP4 could
not reach — but not only that: TP4 given the same 512-sequence budget reaches 1,245 (+14% over its 256-sequence
number), so batch depth helps both layouts and the layout itself is worth +32% at equal depth. Raising the
per-engine budget to 1,024 sequences changed nothing, because 1,024 streams across four engines is 256 each. The
W4A4 expert kernel that gave TP4 its +5% is not available in this layout: the b12x MXFP4 MoE backend refuses
dp_size=4, ep_size=4 outright ("does not support the deployment configuration"), so the DP4 + EP numbers are on
the Marlin MXFP4 path, and a W4A4 expert kernel that shards would be the next lever. Its 403-item quality run
on this layout scored 0.844 — the best score measured without a drafter, 0.030 above the same weights and
expert kernel at TP4, at the edge of the suite's 0.022 repeat spread: the layout costs nothing in quality and may
have bought a little (fewer truncations at 4.2% against 5.5%). Its 403-item quality run on this layout is in progress;
the same weights and MoE kernel scored 0.814 at TP4.
GLM-5.3-Flash is the highest-intelligence open model that fits in 384 GB at all — four points below the top open score (Kimi K3, 50), which only 750B–2.8T models reach. Getting it to produce correct output on this card took a day; see "GLM-5.3-Flash" below.
These throughput numbers do not transfer to a purchase. Scan sells the Server Edition; this host caps
the same silicon at 400 W and loses 23% on NVFP4 and 34% on FP8 for that alone. The rows below are kept
because they are internally consistent — same box, same session, same controls (c6_* in results/) — so
they rank configurations and prove models feasible. For anything absolute, use the 600 W section above.
Quality scores are the exception: accuracy does not depend on the power limit, so eval results from either
box are directly comparable, which is why both hosts run the quality suite.
| model (AA) | shape | out tok/s | in tok/s | TTFT p50 | tripwire |
|---|---|---|---|---|---|
| gpt-oss-20b (–), 4 replicas | promptopt C256 | 13,442 | 188,192 | 0.6 s | 20/20 |
| router C256 | 10,291 | 82,332 | 0.7 s | ||
| Nemotron-3.5-Lightning-30B (16, estimate) | router C256 | 8,037 | 64,296 | 1.2 s | 18/20 |
| judge C128 | 6,317 | 50,533 | 1.0 s | ||
| Qwen3.6-35B-A3B (–) | promptopt C256 | 7,680 | 107,518 | 1.2 s | 16/20 |
| router C256 | 6,903 | 55,220 | 0.8 s | ||
| gemma-4-26B-A4B (–) | promptopt C256 | 7,705 | 107,870 | 1.1 s | 19/20 |
| gemma-4-26B-A4B + official MTP | promptopt C256 | 9,560 | 133,834 | 0.22 s | 20/20 |
| judge C128 | 4,720 | 37,764 | 0.47 s | ||
| Laguna-S-2.1 (agentic coder) | promptopt C256 | 4,527 | 63,382 | 1.6 s | 20/20 |
| router C256 | 2,850 | 22,803 | 1.2 s | ||
| Laguna-S-2.1 + DFlash drafter | judge C128 | 2,455 | 19,643 | 0.63 s | 20/20 |
| Nemotron-3-Super-120B (–) | router C256 | 2,845 | 22,761 | 1.9 s | 20/20 |
| Qwen3.8-27B + DFlash2 drafter | judge C128 | 2,682 | 21,458 | 1.0 s | 20/20 |
| Ornith-1.5-397B | router C256 | 877 | 7,017 | 2.4 s | 20/20 |
| Hy3 (–) | promptopt C256 | 1,821 | 25,488 | 3.6 s | 20/20 |
Speculative decoding buys latency, not throughput. Every drafter measured loses output tokens per second at saturation and cuts time-to-first-token by 2–5×: Nemotron-3.5 with NVIDIA's DSpark drafter goes from 1,161 ms to 244 ms TTFT while output drops from 8,037 to 4,305 tok/s. For an interactive agent that is the right trade; for batch rollouts it is not. The two exceptions are gemma-4-26B's official MTP head and Laguna's DFlash, which win on both axes.
Scan sells an 8× RTX 5090 machine for the same £1,999.98/month as the 4× RTX PRO 6000, so this is a straight read of throughput per pound: twice the tensor cores, a third of the memory each, 256 GB aggregate against 384 GB.
| model | best kernel pair found | router C1024 | promptopt C1024 | judge C512 |
|---|---|---|---|---|
| gpt-oss-20b | mxfp8 activations | 25,634 | 39,529 | 16,790 |
| gemma-4-26B-A4B NVFP4 | engine auto | 15,674 | 27,696 | 13,478 |
| Nemotron-3.5-Lightning-30B NVFP4 | b12x + Marlin experts |
16,154 | 10,773 | 13,838 |
| Qwen3.6-35B-A3B NVFP4 | b12x + Marlin experts |
13,654 | 15,352 | 10,212 |
| Muse-Glimmer-30B NVFP4 | b12x + FlashInfer CUTLASS |
9,782 | 23,833 | 8,056 |
| Qwen3.8-27B NVFP4 | b12x |
6,558 | 4,889 | 5,237 |
Head to head on the identical checkpoint, kernel and shapes:
Qwen3.8-27B NVFP4, b12x, one replica per card |
4× PRO 6000, 600 W | 8× RTX 5090 | Δ |
|---|---|---|---|
| router C256 | 4,288 | 6,445 | +50% |
| router C1024 | 5,161 | 6,558 | +27% |
| judge C512 | 4,400 | 5,237 | +19% |
| promptopt C1024 | 4,804 | 4,889 | +2% |
| KV cache per server | 1,500,000 tokens | 181,000 | −88% |
The consumer node wins everywhere and wins hugely on short-prompt routing; the advantage collapses to nothing on shared-prefix traffic, where 32 GB per card leaves an eighth of the cache and the scheduler queues instead of batching. Caveats worth carrying: this rented host is dual-socket (Scan's is not, so its tensor-parallel tiers should be better than measured here), and its cards are also capped at 400 W.
And then the memory ceiling arrives. Everything above is a model that fits on one card. A model that does not is forced into tensor parallelism across cards with no NVLink, where the 96 GB box still runs independent replicas that exchange nothing. gpt-oss-120b is the one model measured both ways:
| gpt-oss-120b, same MoE kernel | 4× PRO 6000, four TP1 replicas | 8× RTX 5090, two TP4 groups |
|---|---|---|
| router, out tok/s | 13,752 (C2048) | 1,640 (C1024) |
| prompt-optimisation | 19,689 | 3,352 |
| judge | 9,152 | 1,578 |
| TTFT p50 | 0.7 s | 324 s |
Eight times the throughput and three orders of magnitude on time-to-first-token. That is not a tuning gap, it is the configuration: 61 GB fits a 96 GB card and does not fit a 32 GB one. Two further tensor-parallel arms failed there outright — Ling-3.0-flash needs 102,400 bytes of shared memory against the 101,376 the architecture allows, and Qwen3.8-Flash-Next rejects an fp8 KV cache. So the consumer box is the better buy for high-volume work on models under ~30 GB, and the wrong buy for anything frontier-class, which on this roster means DeepSeek-V4-Flash (167 GB) and GLM-5.3-Flash (198 GB). Both are queued at TP8 there to put a number on it rather than an inference.
Neither vLLM 0.28.1 nor SGLang 0.5.18 knows the glm5_next architecture; both vendors ship it as a
per-model Docker image. box/pull_image.py lifts those images' Python trees over the registry API without
Docker.
- The vLLM route works. Its only sm_120 sparse-attention backend is hard-wired to DeepSeek's cache
layout (
pe_dim64; GLM has 0). Its Hopper NoPE backend supports that but was gated to major 9 and built on FlashAttention-3.box/vllm_sm120_nope.pywidens the gate to major 12 and rebuilds the wrapper on FlashInfer's FA2 path. With--block-size 1024(DeepGEMM's paged-MQA indexer accepts arch 12 only at particular block sizes) and autotune off, it serves TP4 with a 2.14M-token KV cache and passes 18/20 on the chat tripwire. - The SGLang route does not. Nine blockers cleared, server healthy in 135 s, prefill exact after a
dense-prefill patch — and decode still drifts into loops. Ten discriminators cleared CUDA graphs, MTP, the
MoE runner, TileLang tiles, PDL, the indexer, conv and SSM dtype. The TileLang sparse decode kernel is
what is left. Documented in
notes/rather than swept under it.
Credit: the DGX Spark (GB10, sm_121) community had already hit most of these and published fixes.
Throughput numbers are worthless without a quality gate, and string comparison of greedy generations is not one — a single differing token cascades, and it cannot tell better from worse. Three layers here:
1. A corruption tripwire (box/quality20.py), run on every configuration before it is benchmarked: 20
fixed prompts through the model's own chat template, a repetition detector (repeated 6-grams, distinct-token
ratio) and expected substrings. Reported as ok/degenerate/wrong in every table above. The first version of
this passed GLM output reading "111 222 333 444"; do not trust a tripwire that only checks for !!!!.
2. Logit-level divergence (box/logit_diff.py), for questions a task benchmark cannot resolve: identical
contexts on two servers, twenty log-probabilities per position, and a control pair that fixes the noise
floor.
Qwen3.8-27B, ~104 positions per pair, 600 W box. Read every row against the control, which is the same configuration served twice:
| pair | top-1 agreement | mean KL | verdict |
|---|---|---|---|
| control — same config, twice | 0.9615 | 0.01840 | the noise floor |
b12x vs flashinfer_b12x |
0.9904 | 0.00158 | below the floor — the two W4A4 kernels are interchangeable |
| fp8 KV cache vs bf16 | 0.9417 | 0.02555 | just above: excess KL +0.007 |
| NVFP4 (community PTQ) vs FP8 | 0.8190 | 0.14515 | excess KL +0.127, seven times the floor |
Three things this settles that task accuracy could not.
The stack is not deterministic, and the control quantifies it: two identical servers disagree on 3.8%
of top-1 tokens. Prefix caching, atomics in MoE and attention reductions, and continuous batching all
contribute. Any claim resting on reproducing an output exactly — including "speculation must be
bit-identical" — is unfounded here, which is why the greedy sequence comparison in box/specdiff.py now
refuses to draw a conclusion unless its own control reproduces.
The two four-bit kernels are equivalent, and by a wide margin: they agree with each other better than
one configuration agrees with itself. Choosing between b12x and flashinfer_b12x is a throughput
decision only.
Four-bit post-training quantisation really does change the model. 18% of top-1 tokens differ from the FP8 release — not a subtle shift, and measured without a single task, token cap or scorer involved. It corroborates the maths gap seen in the task suite (0.650 against 0.939) through a completely independent instrument, which is the strongest form of agreement available here.
For fp8 KV cache on gpt-oss, measured earlier the same way:
| metric | control: fp8 vs fp8 | treatment: fp8 vs bf16 | excess |
|---|---|---|---|
| top-1 token agreement | 0.988 | 0.925 | −0.062 |
| top-5 overlap | 0.988 | 0.965 | −0.023 |
| mean KL divergence | 0.0053 | 0.0589 | +0.054 |
3. A task-accuracy suite (box/evalsuite/), 435 items across six capability families — contest
mathematics, code executed against its tests in a sandbox, tool calling matched against the Berkeley
function-calling answer sets, synthetic long-context retrieval calibrated to the served window, ten-option
knowledge questions and short-answer factuality, and instruction following with two dozen checkers
re-implemented from the reference. Ungated public sources, programmatic scoring, no model judging another
model, Wilson intervals, and the same items and seed across configurations so arms are directly pairable.
Six capability families, 403 items, one seed, no token cap, each model with its own reasoning parser, chat-template flags and sampling recipe. Accuracy does not depend on the power limit, so results from both 4× RTX PRO 6000 hosts are pooled; the host is noted where it matters.
| model (AA index) · configuration | items | overall | maths | code | tools | long ctx | knowledge | instructions |
|---|---|---|---|---|---|---|---|---|
| GLM-5.3-Flash (46) · NVFP4, TP4, MTP speculation | 403 | 0.809 | 0.812 | 0.773 | 0.900 | 0.917 | 0.614 | 0.883 |
| GLM-5.3-Flash (46) · native FP8 (zai-org's release, 330 GB), TP4, 32 seqs, no speculation | 403 | 0.809 ⁸ | 0.738 | 0.787 | 0.914 | 0.958 | 0.643 | 0.883 |
| DeepSeek-V4-Flash (41) · native MXFP4 + FP8, TP1 × DP4 + EP, Marlin experts, no speculation | 403 | 0.844 ⁴ | 0.938 | 0.747 | 0.900 | 0.938 | 0.643 | 0.933 |
| DeepSeek-V4-Flash (41) · native MXFP4 + FP8, TP4, DSpark speculation | 403 | 0.831 ⁴ | 0.938 | 0.720 | 0.871 | 0.958 | 0.657 | 0.883 |
| DeepSeek-V4-Flash (41) · native MXFP4 + FP8, TP4, Marlin experts, no speculation | 403 | 0.814 ⁴ | 0.912 | 0.707 | 0.871 | 0.938 | 0.643 | 0.850 |
| DeepSeek-V4-Flash (41) · native MXFP4 + FP8, TP4, no speculation | 403 | 0.801 ⁴ | 0.912 | 0.680 | 0.886 | 0.938 | 0.586 | 0.850 |
| GLM-5.3-Flash (46) · NVFP4, TP4, no speculation | 403 ³ | 0.794 | 0.738 | 0.760 | 0.914 | 0.958 | 0.600 | 0.867 |
| GLM-5.3-Flash (46) · NVFP4, TP1 × DP4 + EP, no speculation — the fast usable layout | 403 | 0.792 | 0.700 | 0.787 | 0.914 | 0.958 | 0.600 | 0.867 |
| GLM-5.3-Flash (46) · NVFP4, DP4 + EP, 65k tokens of output room | 403 | 0.777 | 0.713 | 0.787 | 0.900 | 0.917 | 0.571 | 0.833 |
Qwen3.8-Flash-Next (46) · NVFP4 (RadixArk), TP4, Marlin MoE, b12x linears, FP8 n-gram tables |
403 | 0.801 ⁷ | 0.800 | 0.733 | 0.886 | 0.958 | 0.586 | 0.917 |
| GLM-5.3-Flash (46) · NVFP4, DP2 × TP2 + EP — the 1,300 tok/s layout | 403 | 0.643 ⁶ | 0.562 | 0.640 | 0.714 | 0.917 | 0.543 | 0.567 |
| Qwen3.8-27B (41) · native BF16, 4 replicas | 403 ⁵ | 0.806 | 0.800 | 0.813 | 0.900 | 0.979 | 0.500 | 0.917 |
| Muse-Glimmer-30B (24) · BF16 | 403 | 0.787 | 0.938 | 0.800 | 0.814 | 0.812 | 0.486 | 0.867 |
| Qwen3.8-27B (41) · FP8, 4 replicas | 403 | 0.779 | 0.863 | 0.720 | 0.843 | 0.979 | 0.471 | 0.867 |
| Nemotron-3-Super (–) · native NVFP4 | 379 ¹ | 0.776 | 0.946 | 0.800 | 0.900 | 0.729 | 0.500 | 0.800 |
| Qwen3.8-27B (41) · NVFP4, RedHatAI | 403 | 0.772 | 0.750 | 0.760 | 0.857 | 0.938 | 0.486 | 0.917 |
| Step-3.7-Flash · NVFP4 | 403 | 0.767 | 0.688 | 0.760 | 0.871 | 0.958 | 0.529 | 0.883 |
| Qwen3.8-27B (41) · NVFP4, unsloth | 403 | 0.752 | 0.738 | 0.760 | 0.814 | 0.938 | 0.471 | 0.867 |
| gpt-oss-120b (16) · native MXFP4 | 403 | 0.742 | 0.731 | 0.933 | 0.923 | 0.857 | 0.385 | 0.700 |
| Qwen3.8-27B (41) · NVFP4, gittensor (the fast build) | 403 | 0.725 | 0.650 | 0.680 | 0.843 | 0.917 | 0.471 | 0.883 |
| gpt-oss-20b (–) · native MXFP4 | 403 | 0.712 | 0.700 | 0.773 | 0.857 | 0.833 | 0.429 | 0.717 |
| Qwen3.6-35B-A3B · FP8 | 403 | 0.702 | 0.537 | 0.627 | 0.871 | 0.958 | 0.543 | 0.800 |
| gemma-4-26B-A4B · BF16, thinking on, T=0 | 403 | 0.628 ² | 0.812 | 0.560 | 0.843 | 0.604 | 0.286 | 0.633 |
¹ The first pass of several runs lost items to the eval runner's default 600-second request timeout — the
hardest items, since they are the ones that run long, so a row missing them is flattered. Completing them
under the same tag and caps moved every affected row down, as predicted: GLM 0.861 → 0.794 (see ³), Qwen FP8
0.789 → 0.779 (maths 0.939 → 0.863), Muse 0.794 → 0.787 (maths 1.000 → 0.938). Nemotron-3-Super is the one row
still short (379 of 403); it was on the box that could not restart. Every eval now runs with an hour per request.
⁷ Qwen3.8-Flash-Next served on this GPU class for the first time tonight (a loader fix for its FP8 n-gram tables,
box/patch_ple.py); 7.7% of its answers hit the 32k caps, so a 65k-room run is queued. Paired against GLM at TP4 it is
23 to 20 — a tie at index 46 — and against DeepSeek's DP4 layout 10 to 27.
⁸ GLM-5.3-Flash at its released FP8 precision (zai-org's checkpoint, 330 GB across four cards, 32 sequences): the direct test of whether the NVFP4 gap was the build or the node. Paired against the NVFP4 TP4 run 17 to 11; against the DP4 + EP layout 19 to 12; against Z.AI's endpoint at the same caps 10 to 16; against DeepSeek's 0.844 15 to 29.
² 28.5% of gemma's answers were truncated at the cap: at T=0 with thinking on it does not converge. The
vendor default is thinking off; both modes are being measured (box/lists/thinkmode6000.txt).
³ GLM without speculation scored 0.872 on the 367 items it finished in its first pass; completing the 36
timed-out items took it to 0.794, because 20 of 80 maths items and 9 of 75 code items ran past 32,768
output tokens at reasoning_effort: max and a truncated answer scores as wrong. That is the cap binding,
not the model failing: the two GLM rows are within noise of each other (paired 13 vs 10 on the items both
scored), and a 65k-token arm is queued to measure what the 32k cap costs.
⁴ DeepSeek-V4-Flash is served at the precision it was trained at, so this row has no quantisation loss in it.
It lost no items to the timeout, but 17% of its code answers ran past the 20,480-token cap (6% of maths
past 32,768): like GLM, it reasons past the caps that were generous for every smaller model. A 65k-token arm
is queued for it too. Statistically it ties GLM — the two are inside each other's intervals.
⁶ The fast expert-parallel layout's outputs are degraded on this vendor build: truncation 16% against 8% at TP4,
2.7% degenerate answers, mean answer 6,320 tokens against 4,138. Every family fell, instruction-following most
(0.567 against 0.867). Same weights, same kernels, different parallel layout — the layout is the variable, and
the isolation probes ran in the last hour on a fourth box: eager mode + Marlin MoE (the DGX Spark recipe): clean (19 ok, 1 degenerate, 0 wrong of 20); 1,125 out tok/s router C1024; Marlin MoE alone: degenerate (9 ok, 11 degenerate, 0 wrong of 20); eager mode alone: clean (18 ok, 1 degenerate, 1 wrong of 20); 1,460 out tok/s router C1024; TP2 × 2 without expert parallelism: not reached before the cut-off — the two-engine layout serves clean output with eager mode alone at 1,460 out tok/s on routing traffic — a 20-item tripwire, not a 403-item run; the layout is recoverable on this build and its full quality run is the next step.
The published intelligence index does predict this. GLM-5.3-Flash at index 46 leads, and it leads on the families that separate models rather than saturate: maths, knowledge and long context. An earlier version of this file claimed the opposite — that small models beat it and the index was useless for our workloads. That claim was an artefact of a broken harness, not a finding, and it is withdrawn. What survives is narrower and more useful: gpt-oss is disproportionately good at code and tool calling for its size, which is what an agent harness spends most of its time doing, and index 16 buys 0.933 on code where index 46 buys 0.864.
The v4.2 chart, sized against 384 GB: every model above GLM-5.3-Flash overflows the node — Kimi K3 (50) is
2.78 trillion parameters (a community W4A4 build exists, at ~1.4 TB), GLM-5.3 (49) is 753B and ~450 GB at
four-bit, Qwen3.8-2.4T-A95B (47) and DeepSeek V4 Pro 0813 (42, 1.65T) are larger still. So 46 stays the
ceiling: 92% of the top open score. Below it, the one fittable model not yet measured is K2 Horizon
375B-A23B (38) — MBZUAI's IFM, released 1 September, Apache-2.0, 23B active. Its FP8 release is 375 GB and
does not fit; a four-bit build (~225 GB) would, and none exists yet; the k2_horizon architecture is custom
code with no engine support confirmed. It is on the roster as blocked on a quantisation. DeepSeek-V4-Flash does fit — 156 GB, native MXFP4 experts and FP8 attention — and scores 0.801 above,
after three failed launches: one hard-coded a MoE backend this build rejects, two blamed the wrong flag for a
DeepGEMM assertion that was the attention output projection needing its sm_120 fallback (rule 6).
Per-family intervals at these counts are roughly ±0.10, so family-level ordering is indicative and the aggregate is where the ±0.045 applies. Rows are comparable only on the items both scored, which is why every paired claim below is made on the common item set rather than on the headline column.
The question behind the economics is whether the endpoint a customer buys at list price scores what the weights
score on this node. So the 403 items run against OpenRouter too — default routing, the vendor's own sampling
recipe, the same per-family caps, from the third box beside the GPU work (box/or_eval.sh; the key lives on the
box, never in the repository or this chat). One model has finished; the others follow in the order of the table.
| model | on this node (best quality-safe config) | OpenRouter endpoint, same 403 items | gap | where the gap is |
|---|---|---|---|---|
| GLM-5.3-Flash | 0.794 · NVFP4, TP4 (0.809 with MTP) | 0.824 | +0.030 (+0.015 vs MTP) | maths 0.812 vs 0.738, code 0.813 vs 0.760, knowledge 0.657 vs 0.600; ifeval and tools slightly lower |
| DeepSeek-V4-Flash | 0.844 · native, DP4 + EP | 0.784 | −0.060 | long context 0.833 vs 0.938, maths 0.875 vs 0.938, knowledge 0.571 vs 0.643, code 0.707 vs 0.747; the endpoint truncates 9.2% of answers against 4.2% here and 3.0% degenerate into repetition against 0.25% |
| DeepSeek-V4-Flash · DeepSeek's own endpoint, provider pinned, same 32k caps | 0.844 · native, DP4 + EP | 0.789 | −0.055 | the endpoint writes 4,717 tokens an answer against our 3,376 and 7.9% of its answers hit the caps against 4.2% of ours |
| DeepSeek-V4-Flash · DeepSeek's own endpoint, 65k tokens of room | 0.844 · native, DP4 + EP, 32k caps | 0.854 | +0.010 (paired 12 to 16 — a tie) | maths 1.000, knowledge 0.686, code 0.773; truncation 2.7%. The 32k gap was a cap effect, not a model gap: given room, the maker's endpoint and the node's native-precision run score the same. our own 65k run is the next row |
| DeepSeek-V4-Flash · the node with 65k tokens of room (378 of 403 items — the 25 longest maths and code items were in flight when the third box stopped) | 0.865 (378) · native, DP4 + EP, 65k caps | 0.865 on the same 378 items (DeepSeek's own endpoint at 65k) | 0.000 (paired 10 to 10) | room removes every truncation (0% against 4.2% at 32k); on the same 378 items the node's 32k run scores 0.868 (paired 8 to 7), so the caps bind only on the unfinished tail. Given room, the node and the maker's endpoint are the same model at the same quality; the frontier's top point holds |
| Qwen3.8-27B | 0.806 · BF16 (0.792 QAT NVFP4) | 0.772 | −0.034 (−0.020 vs QAT) | maths 0.775 vs 0.800, code 0.760 vs 0.813, knowledge 0.486 vs 0.500; default routing lands on FP8 and FP4 hosts — the endpoint scores like our FP8 and RedHat four-bit rows (0.779, 0.772), 7.0% truncated against none for BF16 |
| GLM-5.3-Flash · Z.AI's own endpoint, provider pinned | 0.794 · NVFP4, TP4 | 0.824 | +0.030 | identical to default routing (paired 17 to 17): the list tier already routes to Z.AI-class FP8 serving |
| GLM-5.3-Flash · native FP8 on the node against Z.AI pinned, same 32k caps | 0.809 · FP8, TP4, 32 seqs | 0.824 | -0.015 (paired 10 to 16 — a tie) | truncation 7.2% against the endpoint's 6.2%, mean answer 4,327 tokens against 4,354 — the same profile; the residual gap is inside the noise floor, so at 32k caps the node serves GLM at its maker's quality once it serves the maker's precision |
| GLM-5.3-Flash · Z.AI's own endpoint, 65k tokens of room | 0.777 · NVFP4, DP4 + EP, 65k caps | 0.859 (390 items) | +0.066 at equal room (paired 33 to 7) | maths 14 to 2, knowledge 7 to 1, instructions 7 to 1. Given the same room our four-bit build still truncates 7.9% of answers (mean 7,683 tokens, up from 5,013 at 32k) where Z.AI's truncates 0.8% in 3,740: the NVFP4 build reasons longer and does not converge. This is the quantisation cost for GLM, and the native-FP8 run is now first on the original box |
| DeepSeek-V4-Flash · Baidu, the cheapest FP8 host ($0.05 / $0.10), pinned | 0.844 · native, DP4 + EP | 0.831 | −0.012 (paired 15 to 10 — inside the noise floor) | shorter answers (3,485 tokens) and 3.5% truncation at the same caps; beats DeepSeek's own endpoint at 32k (paired 26 to 9) and costs a quarter of it |
| gpt-oss-120b | 0.742 · native MXFP4 (124 items, the 5090 box) | 0.769 | not comparable yet | our own 403-item run is missing; the API's 0.769 (code 0.787, tools 0.900, knowledge 0.486) is the reference until it exists |
| gpt-oss-20b | 0.712 · native MXFP4 | 0.725 | +0.013 | within noise; the API's knowledge 0.429 matches ours |
| Muse, gemma, MiniMax; GLM at DeepInfra (FP4); DeepSeek at Relace (FP4); Qwen at Darkbloom (FP4) and Parasail (FP8) | see leaderboard | stopped | the key hit its credit limit at 22:33 UTC (HTTP 402); Darkbloom's FP4 Qwen was at 0.727 on 300 items, Relace's FP4 DeepSeek at 0.815 on 130 |
OpenRouter's public endpoint list explains the DeepSeek row and changes the price it should be read against: 29 providers serve DeepSeek-V4-Flash-0731, the $0.065 / $0.18 tier the economics used is FP4 (Relace, Sail Research), Baidu's FP8 is $0.05 / $0.10, and DeepSeek's own endpoint is $0.22 / $0.66. Pinning to DeepSeek itself scored 0.789 at our 32k caps — the same as default routing (paired 26 to 24) — and 0.854 with 65k tokens of room (paired 32 to 6 against its own 32k run, 12 to 16 against our node: a tie). The maker's endpoint reasons longer than our server (4,717 tokens an answer against 3,376) and was being cut off at the caps; only the cheap tier's 3% degenerate output was provider-specific. Read across the DeepSeek rows as a market, not a price: DeepSeek's own endpoint ties the node once given room, at 3.7× the list tier's price (about 4× the node's cost per token at Scan list); Baidu's FP8 host ties the node within noise at a quarter of DeepSeek's price — about 0.8× the node's list-price cost, the one API tier that undercuts the node at equal quality; the FP4 resellers at the list tier lose 0.06 and truncate. Provider choice is worth more than any kernel on this page, and it has to be measured. At DeepSeek's own price the averaged workload costs about $0.13 per million tokens against $0.033 on the node: 4× in the node's favour for the model at its released quality, 10× fully loaded.
The two results point opposite ways, and both are about the deployment, not the weights. GLM's endpoint beats our four-bit build by the size of a quantisation cost, because Z.AI serves the model at training precision. DeepSeek's endpoint loses 0.060 to our native-precision run — three times the noise floor — with twice the truncation and twelve times the degenerate output, which is what a provider running the model too hot or on a lossy build looks like. OpenRouter's default routing picks whichever provider is cheapest and available, and the response does not say which one answered; a customer paying list price gets that provider. "API quality" is a property of the routed deployment, and it has to be measured per provider before it can be compared with a node that serves the weights as released.
The GLM gap is at the edge of the suite's 0.022 noise floor and lands exactly where the quantisation ladder said quantisation lands — maths, code, knowledge — while the endpoint's truncation rate (6.2%) and mean answer length (4,354 tokens) match ours. Z.AI serves the model at its training precision; we serve a post-training NVFP4 build. The native-FP8 GLM run has landed: 0.809 on 403 items — paired against our NVFP4 TP4 run 17 to 11 (+0.015), against Z.AI's pinned endpoint at the same caps 10 to 16 (-0.015), both inside the 0.022 noise floor. It truncates 7.2% of its answers against the four-bit build's 7.9% and writes 4,327 tokens an answer against 4,138: at 32k caps the maker's precision on our box behaves like our four-bit build, not like Z.AI's serving. So the precision cost at 32k is at most 0.015, and most of the 0.066 gap to Z.AI at 65k is room — room the four-bit build could not use (0.777, still 7.9% truncated at 65k) and the FP8 build never got to try before the box's time ran out. The 32 sequences that 330 GB of weights leave are FP8's price: 500 out tok/s on routing traffic, 527 on prompt optimisation and 471 on judging at 32 streams (TPOT 51 ms, TTFT 1.7–2.6 s) — $0.18 per million tokens on the node against $0.10 at the market-median API price, 0.6×. The 128-stream shapes that would have shown how much of the 554k-token KV cache is usable never ran (box lost early, see below).
GLM-5.3-Flash scored 0.800 without its MTP head and 0.740 with it on the 400 W box, and the previous version of this file called that a bug in the speculator. It was not. A greedy sequence test could not settle it — its own control, the same server captured twice, matched on only 4 of 12 — so the question was put to the task suite as a paired comparison on the items both arms actually scored, same 600 W box, same recipe, same seed:
| GLM-5.3-Flash, 367 common items | accuracy | truncated | mean output tokens |
|---|---|---|---|
| no speculation | 0.872 | 0.000 | 1,996 |
| MTP, 3 speculative tokens | 0.864 | 0.003 | 2,254 |
| items only one arm got right | 13 base · 10 MTP |
Thirteen against ten is a coin toss. The earlier gap came from comparing arms scored on different item
sets under a cap that marked truncation wrong — and the MTP arm, being faster, was the one that finished the
36 items the base arm timed out on. Speculation did not cost GLM anything; it bought the hardest items within
the same wall-clock. The logit-level pass (above) is the other half of the answer: two identical servers
differ on 3.8% of top-1 tokens, so no test that demands bit-exact output can attribute anything on this
stack, and box/specdiff.py now refuses to.
Lossless is not free, though. At saturation, speculation costs throughput on this node. GLM's MTP head at 1,024 concurrent streams: 592 output tokens a second against 911 without it, with only 10% of drafted tokens accepted at that batch (the 67% acceptance seen earlier was at low concurrency). DeepSeek's DSpark drafter: 665 against 1,107. A drafter buys per-request latency when the box is lightly loaded and sells aggregate throughput when it is full; for batch and agent-harness traffic on this node, run without it.
The second model says the same thing from the other side. DeepSeek-V4-Flash with NVIDIA's DSpark drafter (7 draft tokens a step, 37% of them accepted) scored 0.831 against 0.801 without it (with the W4A4 expert kernel; the same layout on the Marlin expert kernel scored 0.814 without a drafter), all 403 items both times, paired 19 to 7 in the drafter's favour. A drafter cannot make the model smarter — with probabilistic drafting and rejection sampling the target distribution is preserved by construction — so a 19-to-7 split at temperature 1.0 is a reading of the suite's own run-to-run noise at vendor sampling, not of speculation. The next section measures that noise.
Four configurations were evaluated on both PRO 6000 hosts under byte-identical recipes — same items, same seed, same sampling, same caps, same parser — which makes each pair a same-configuration-twice control:
| same configuration, twice | items in common | run A | run B | aggregate gap | items only A / only B got right |
|---|---|---|---|---|---|
| Qwen3.8-27B NVFP4 (gittensor), b12x | 403 | 0.725 | 0.747 | 0.022 | 11 / 20 |
| Qwen3.8-27B FP8, b12x | 380 | 0.787 | 0.795 | 0.008 | 6 / 9 |
| Muse-Glimmer-30B BF16 | 373 | 0.791 | 0.780 | 0.011 | 13 / 9 |
| gemma-4-26B-A4B BF16, thinking on, T = 0 | 396 | 0.634 | 0.616 | 0.018 | 28 / 21 |
So a repeat of the same configuration moves the aggregate by up to 0.02 and flips 15 to 50 items, with paired splits as lopsided as 11 to 20. Read every comparison in this file against that: DeepSeek's 19-to-7 for its drafter and GLM's 13-to-10 for its MTP head are inside the floor (speculation is lossless, and not better); FP8 against the gittensor four-bit build at 29-to-14 and 0.040 is outside it, but not by a wide margin; RedHat's "parity" with FP8 (0.801 against 0.802) means indistinguishable, not equal; and the order of adjacent rows in the leaderboard is not a finding. The gemma pair is the sharpest lesson: at temperature 0 — greedy — 49 items still changed verdict between two identical servers, which is the logit-level control's 3.8% top-1 disagreement cascading through whole answers. Nothing on this stack reproduces bit-for-bit, and the eval suite inherits that. A third repeat of the Qwen NVFP4 row is queued on the 600 W box to put a second point on the floor.
The first round of quality numbers here was wrong, and the way it was wrong is the most useful thing in this repository. Serving every model with one house default produced a table in which every model that reasons scored below every model that does not — which reads like a finding and is in fact three bugs.
The same weights, the same hardware, the same 403 items. Only the serving changed:
| Qwen3.8-27B NVFP4 | house default | vendor recipe | |
|---|---|---|---|
| overall | 0.558 | 0.732 | |
| instruction following | 0.317 | 0.833 | its chain-of-thought was the graded answer |
| code | 0.413 | 0.733 | |
| maths | 0.525 | 0.625 | |
| tools | 0.829 | 0.900 | |
| long context | 0.917 | 0.979 | |
| truncation rate | 0.248 | 0.139 |
Three independent errors, each worth more than any kernel choice in this repository:
- No reasoning parser. vLLM registers one per family —
qwen3,glm45,muse_glimmer,nemotron_v3,ling3,minimax_m3,inkling,hy_v3,step3p5,poolside_v1,mimo,deepseek_v4,gemma4,openai_gptoss— and we passed none. Without one the chain-of-thought is returned as the answer. It hides well: Qwen3-family templates put the opening<think>in the prompt, so the model emits only a closing</think>and the output reads as ordinary prose. 306 of 403 responses, and 21 of 60 instruction items began "We need answer user's request…". - A token cap. A truncated answer was scored wrong. GLM-5.3-Flash lost 51% of the maths items that way. Cap generation just under the context window and let the time budget be the only limit — running out of time marks an item skipped, which is excluded from the accuracy.
- Sampling, and whether the model is even thinking. Not one vendor recommends greedy or T=0.6. Qwen
wants T=1.0/top_p=0.95/top_k=20/min_p=0 in thinking mode, gemma-4 T=0.0/top_k=64, Ling-3.0 T=0.85,
Hy3 T=0.9/top_p=1.0.
top_kandmin_phave no slot in the OpenAI schema and must go throughextra_bodyor they silently do not apply. And thinking is not on by default everywhere: Hy3 defaults tono_thinkand gemma-4 toenable_thinking: false, while Qwen, Inkling, MiniMax, Nemotron, Ling and Ornith default on — so a naive table compares models in two different modes.
box/lists/profiles.tsv carries the researched recipe per model (parser, tool parser, template kwargs,
sampling), applied by the harness to both the server and the eval client. Every pre-fix run is kept under
results/eval/capped/, no_parser/ and pre_profiles/ so the size of each artefact stays measurable.
The re-run under these recipes is what the table above reports.
Throughput and quality are not a choice to make separately, so here they are together: the same Qwen3.8-27B weights through four quantisers, four TP1 replicas on the 600 W box, router at concurrency 1,024 for speed and the 403-item suite for accuracy, one recipe and one seed throughout.
Quality is given two ways: over every item the run scored, and over the 388 items all four runs scored (the FP8 run lost 15 to the request timeout), which is the only column on which the builds are comparable.
| build | quantiser | kernel the engine used | out tok/s | quality (all scored) | quality (388 common) | maths (common) |
|---|---|---|---|---|---|---|
| NVFP4 · gittensor (ModelOpt) | post-training | B12xNvFp4 W4A4 | 5,161 | 0.725 | 0.762 | 0.785 |
| FP8 · Qwen's own release | vendor | B12xFp8BlockScaledMM | 3,148 | 0.789 | 0.802 | 0.938 |
| NVFP4 · RedHatAI | post-training | auto: FP8 attention + dequant MLP | 2,048 | 0.772 | 0.801 | 0.862 |
| NVFP4 · unsloth | post-training | auto: same | 2,048 | 0.752 | 0.786 | 0.862 |
Three things fall out, and only the first was expected.
On throughput the frontier has exactly two points. The gittensor build (5,161 tok/s) and the official FP8 build (3,148). The other two four-bit builds were served under the auto kernel, which cannot use the W4A4 path for compressed-tensors checkpoints and falls back to FP8 attention with a dequantised MLP — slower than FP8 itself. As measured, choosing them is never right on speed.
One more thing the fast build changes: the prompt. Its chat_template.jinja is a 14 KB rewrite of Qwen's
9 KB template (which is byte-identical across the BF16, FP8, QUASAR and MTP checkpoints): it injects an extra
instruction sentence whenever tools are present, adds <|think_on|>/<|think_off|> toggles and re-derives
the reasoning block from message content. So every comparison against that build so far conflates its
weights with its prompt. An arm serving the gittensor weights under the official template is queued
(box/lists/control600w.txt); until it lands, "gittensor" below means weights and template.
On quality, RedHat's four-bit build is at parity with FP8 — 0.801 against 0.802 on the common items —
while the build every throughput number in this repository was measured on is the weakest of the three:
0.762, and the FP8-vs-gittensor pair is a real difference (29 items only FP8 got right against 14 only
NVFP4 got right, on 388 paired items). We picked the gittensor build for kernel compatibility, not for
measured quality. So the open question is now sharp: does RedHat's build load under the W4A4 kernel? If
it does, it is the Pareto point — FP8 accuracy at 5,000 tok/s — and that run is queued (box/lists/fix600w.txt).
The cost that remains is concentrated in mathematics — with a caveat the numbers themselves raise. Even the parity build gives up 0.076 on maths (0.862 against 0.938); the gittensor build gives up 0.153. Code, tools, long context and instruction following are within noise for all three. But look at how these models answer a maths item at Qwen's own sampling: mean output 9,300 tokens for FP8, 12,100 for RedHat, 13,900 for gittensor, and 14,300 for the native BF16 parent, with 3%, 26%, 35% and 19% of items hitting the 32,768 cap respectively — and a capped item scores as wrong. Two things follow. FP8's low truncation is partly because its 15 longest items were the ones the request timeout removed, so its maths lead will shrink when those are completed. And the native BF16 parent — 0.806 overall, 0.800 on maths, no timeouts — reasons longer than any quantised build and truncates more than FP8, so the parent is not the maths ceiling either. The cleanest reading is that four-bit PTQ makes the model reason longer without converging (35% at the cap against 19% for the parent), which is a real cost, and that a 32k cap is too short to measure how much of that reasoning would have landed. The ladder is being completed at these caps for comparability, and re-run with 65k tokens of room for the arms that hit them.
So: if the workload is routing, tool calls and code, take the four-bit build and the 64% throughput. If it has to do maths, FP8 is not a close call at any concurrency. The remaining question — whether a quantisation-aware-trained build gets FP8 accuracy at W4A4 speed, which would collapse the trade-off entirely — is what the QAT rung of the ladder is running to answer.
The question was never "is four-bit lossy" but "lossy from what, and does the way the four-bit weights were made matter". So the same Qwen3.8-27B was run as its native BF16 release, Qwen's own FP8 release, two independent community post-training NVFP4 builds and a quantisation-aware-trained NVFP4 build (QUASAR-QAT), every rung with the same 403 items, recipe and seed, on the same box (the 400 W one, so its throughput is relative — the 600 W run of the QAT build is queued). Every row is paired against the parent on identical items; the noise floor measured above is a split of up to 11-to-20 between identical runs.
| Qwen3.8-27B build | how the weights were made | kernel | out tok/s, router C1024 (600 W · 400 W) | overall | maths | code | vs BF16 parent: items only parent / only this got right | KL from parent (control 0.006) |
|---|---|---|---|---|---|---|---|---|
| BF16 (Qwen release) | — | BF16 | 2,367 · 1,560 | 0.806 | 0.800 | 0.813 | — | — |
| NVFP4 · QUASAR-QAT | quantisation-aware training | b12x W4A4 | 5,194 · 3,893 | 0.792 | 0.812 | 0.813 | 16 / 10 — inside the noise floor | 0.082 |
| FP8 (Qwen release) | post-training, 8-bit | b12x | 3,148 · 2,071 | 0.779 | 0.863 | 0.720 | 18 / 4 on 385 — outside it, code −0.09 | 0.018 |
| NVFP4 · gittensor (ModelOpt) | post-training, 4-bit | b12x W4A4 | 5,161 · 3,965 | 0.747 | 0.662 | 0.733 | 30 / 6 — far outside | 0.097 |
| NVFP4 · QUASAR-QAT, auto kernel | same weights | CuTeDSL W4A16 | — · 1,160 | — | — | — | slower than BF16: dequant, not compute | — |
The last column is the logit-level divergence of each rung from the BF16 parent (mean KL over ~94 positions, identical contexts; the parent against itself gives 0.006). It says something the task suite cannot: the QAT build's next-token distribution is almost as far from the parent's as the post-training build's (0.082 against 0.097), yet its answers are the parent's. Quantisation-aware training does not preserve the distribution; it preserves the decisions. FP8 sits three times above the floor and still loses paired items on code. So neither instrument alone ranks these builds correctly: the task suite says QAT ≈ BF16 > FP8 > PTQ, the logit pass says FP8 ≫ QAT ≈ PTQ, and what you buy hardware for is the first ordering.
¹ FP8 is the one row still missing items to the request timeout (385 of 403); its maths is flattered by that and its code is not (0.720 on both hosts, 0.813 for the parent).
Three conclusions, each of which changes what to buy or run.
Quantisation-aware training recovers the parent. The QAT build is indistinguishable from BF16 on paired items — 16 against 10 is a split identical configurations produce — with the parent's maths and code, and at 600 W it does 5,194 output tokens a second on the router shape (4,822 on the shared-prefix shape, 4,409 on the judge shape) against the parent's 2,367 and FP8's 3,148. That is the Pareto point this campaign was looking for, now with a number that transfers to a purchase: 2.2× the parent's throughput and 1.65× FP8's, at no measurable quality cost. It is also faster than the gittensor build it replaces (5,161) while scoring 0.045 higher.
Qwen's own FP8 release is not lossless either. 18 against 4 on 385 paired items, driven by code (0.720 against 0.813 on both hosts). Eight-bit post-training quantisation by the vendor costs something real here; "the vendor made it" is not the same as "it was trained that way".
Post-training four-bit by a third party is the expensive one. 30 against 6, maths 0.662 against 0.800, and 35% of maths answers running to the cap against 19% for the parent: the model reasons longer and converges less. This is the build every throughput headline in this file was taken on, and it also ships a rewritten chat template (above), so the template arm will say how much of this is the weights.
This section has already been wrong once. An early, buggy round showed NVFP4 five points behind FP8; when the serving was fixed the aggregate gap collapsed, and I wrote that four-bit was free. A matched pair since — same box, same TP1 × 4 layout, same recipe, same seed — says something more specific:
| Qwen3.8-27B | overall | maths | code | tools | long ctx | knowledge | instructions | truncated |
|---|---|---|---|---|---|---|---|---|
| NVFP4 (community PTQ), 8× RTX 5090 | 0.732 | 0.625 | 0.733 | 0.900 | 0.979 | 0.429 | 0.833 | 0.139 |
| FP8 (official), TP2, 8× RTX 5090 | 0.740 | 0.700 | 0.733 | 0.814 | 0.979 | 0.443 | 0.867 | 0.114 |
| NVFP4 (community PTQ), 4× PRO 6000 | 0.747 | 0.662 | 0.733 | 0.871 | 0.958 | 0.486 | 0.867 | 0.122 |
| FP8 (official), 4× PRO 6000 | 0.787 | 0.871 | 0.720 | 0.857 | 0.979 | 0.471 | 0.917 | 0.062 |
| NVFP4 (community PTQ), 600 W box, 388 paired items | 0.762 | 0.785 | 0.680 | 0.865 | 0.917 | 0.471 | 0.933 | 0.103 |
| FP8 (official), 600 W box, 388 paired items | 0.802 | 0.938 | 0.720 | 0.864 | 0.979 | 0.471 | 0.931 | 0.059 |
Aggregate: 0.008 apart in one pair, 0.040 in the next, 0.040 in the third, where the last is a paired comparison on identical items and comes out 29 to 14 in FP8's favour on the items only one side got right. Maths favours FP8 in all three pairs, by 0.075, 0.209 and 0.153, and the four-bit build also truncates about twice as often, which is what a model that reasons longer without converging looks like.
A third row points at the mechanism. Nemotron-3-Super is natively NVFP4 — pre-trained in the format rather than compressed into it — and scores 0.946 on maths, the highest of anything measured. So the emerging read is not "four-bit is lossy" but "post-training four-bit costs mathematical reasoning, and native four-bit does not". That is a different and much more actionable claim, and it is exactly what the ladder now running is built to settle: native BF16, official FP8, two independent community PTQ builds and a quantisation-aware-trained build, all at TP1 with the same items and seed, plus logit-level divergence of every rung against the BF16 parent. Treat the paragraph above as the current state of a live question, not a conclusion.
Worth separating before reading any quantisation comparison. These are natively quantised — the
low-precision weights are the trained artefact, so there is nothing to recover: gpt-oss (MXFP4 experts),
DeepSeek-V4-Flash (MXFP4 experts + FP8 attention), MiMo-V2.5 (FP8), both Nemotron 3 models
(pre-trained with an NVFP4 recipe), and zai-org's own GLM-5.3-Flash release, which is native FP8 — which
means a community NVFP4 build of it is a re-quantisation of an already-quantised model, not of a BF16
parent. Conversely Google publishes no official 4-bit gemma-4-26B-A4B and advises against serving one.
Two findings from building it that generalise:
- Give reasoning models room. The first run scored 181 of 403 items as wrong because they hit the token
cap mid-thought (52 of 80 in maths). These are hybrid reasoners that think in the visible channel with no
tags to strip. The truncated run is kept in
results/eval/truncated_2048/as the evidence. - Adversarial review of a scorer is not optional. Every family was attacked by an independent reviewer after it was written, and every one had false-positive paths: the maths scorer accepted decimal approximations of irrational closed forms and read "3 or 5" as 35; short-answer scoring accepted any answer whose tokens were a superset of the gold; the multiple-choice extractor manufactured an answer from a trailing capital letter about one time in ten.
Every number here is derived from this repository's own 600 W measurements and a handful of stated
assumptions; box/econ.py regenerates both tables from results/summary_all.tsv and prints them.
Cost bases, GBP ex-VAT. Scan's website price for the four-card RTX PRO 6000 box is £1,666.65 a month ex-VAT (£1,999.98 inc-VAT), electricity included, taken over 730 hours. "Committed" applies the 25% discount for a commitment term. "Fully loaded" is Sqwish's internal GPU decision model (5 September 2026): committed price, minus ERIS at 26.97p per qualifying pound (14.5% of 186%) on the 80% of the bill that qualifies, minus the idle GPU-hours resold on Vast as interruptible capacity at $0.90 per GPU-hour with 74.4% fill and a 25% platform take, plus £15 of stopped-template storage. FX £1 = $1.35 throughout. For reference, renting the same four cards on Vast on-demand today costs 4 × $1.55 per GPU-hour, the median of 36 live listings.
| basis | owner utilisation | GBP / node-hour | USD / node-hour |
|---|---|---|---|
| Scan list, nothing resold, no relief | 100% | 2.28 | 3.08 |
| Scan list, nothing resold, no relief | 70% | 3.26 | 4.40 |
| Scan list, nothing resold, no relief | 50% | 4.57 | 6.16 |
| Scan committed (−25%) | 100% | 1.71 | 2.31 |
| Scan committed (−25%) | 70% | 2.45 | 3.30 |
| fully loaded: committed − ERIS − Vast resale of idle hours | 100% | 1.36 | 1.84 |
| fully loaded, same | 70% | 1.31 | 1.77 |
| fully loaded, same | 50% | 1.24 | 1.67 |
| fully loaded, same | 20% (the model's default) | 0.87 | 1.17 |
| renting the same box on Vast today, on-demand | — | 4.59 | 6.20 |
The fully-loaded line is nearly flat above 50% because resale income falls exactly as owner use rises; the model's own break-even is an 86.6% fill of the idle hours at its 20% default. Both the relief and the resale have to actually happen for that line to be real.
The same hour of output, bought from an API. Our measured throughput at a shape gives tokens per node-hour; the API bill is what OpenRouter's list price on 5 September 2026 charges for that token mix (Qwen3.8-Flash-Next from Artificial Analysis, which is not on OpenRouter). Node cost is $4.40 per active hour at Scan list and 70% utilisation, $1.77 fully loaded.
| model · configuration (600 W) | shape | tokens / node-hour (in + out, M) | API $/M in · out | API bill for that hour | API ÷ node, list 70% | API ÷ node, fully loaded |
|---|---|---|---|---|---|---|
| Qwen3.8-27B · NVFP4 gittensor, b12x W4A4, 4 replicas | router C1024 | 147 + 18 | 0.42 · 3.00 | $117 | 27× | 66× |
| Qwen3.8-27B · FP8, b12x, 4 replicas | router C1024 | 91 + 11 | 0.42 · 3.00 | $72 | 16× | 41× |
| gemma-4-26B-A4B · BF16, 4 replicas | promptopt C1024 | 781 + 56 | 0.07 · 0.34 | $74 ¹ | 17× | 42× |
| gpt-oss-120b · MXFP4, 4 replicas | promptopt C2048 | 1,063 + 71 | 0.037 · 0.17 | $51 ¹ | 12× | 29× |
| Muse-Glimmer-30B · BF16, 4 replicas | router C1024 | 87 + 11 | 0.30 · 1.10 | $38 | 9× | 22× |
| gpt-oss-20b · MXFP4, 4 replicas | router C2048 | 446 + 50 | 0.03 · 0.13 | $20 | 4× | 11× |
| Qwen3.8-27B · NVFP4 QUASAR-QAT, b12x W4A4, 4 replicas | router C1024 | 150 + 19 | 0.42 · 3.00 | $119 | 27× | 67× |
| DeepSeek-V4-Flash · native MXFP4 + FP8, TP1 × DP4 + EP, 512 seqs/engine | router C1024 | 47 + 6 | 0.065 · 0.18 | $4.1 | 0.9× | 2.3× |
| DeepSeek-V4-Flash · native MXFP4 + FP8, TP4 | router C256 | 32 + 4 | 0.065 · 0.18 | $2.8 | 0.6× | 1.6× |
| GLM-5.3-Flash · NVFP4, DP2 × TP2 + EP, 384 seqs/rank — quality rejected | router C1024 | 37 + 5 (diagnostic) | 0.075 · 0.25 | — | — | — |
| GLM-5.3-Flash · NVFP4, TP1 × DP4 + EP, 192 seqs/rank | router C1024 | 31 + 4 | 0.075 · 0.25 | $3.3 | 0.7× | 1.9× |
| GLM-5.3-Flash · NVFP4, TP4 + EP, 512 seqs | router C1024 | 27 + 3 | 0.075 · 0.25 | $2.8 | 0.6× | 1.6× |
| Qwen3.8-Flash-Next · NVFP4, TP4, Marlin MoE (index 46) | router C1024 | 42 + 5 | 0.15 · 0.47 | $8.7 | 2.0× | 4.9× |
| MiniMax-M3 · MXFP4, TP4 | router | not run in the window | 0.30 · 1.20 |
¹ The shared-prefix shape bills all input at full price. Providers discount cached input by 80–90%; at a 90% discount on the cached 86% of input, the API bill falls to about $21 for gpt-oss-120b and $31 for gemma — still an order of magnitude above the node. The two four-card models are shown on the router shape, which has no shared prefix, so their ratios need no such correction.
Every configuration on one chart, priced on the workloads we actually measured. Each quantisation of a model
is its own point, because it is its own product. The x-axis is dollars per million tokens, input and output
together, for the average of the two workloads every configuration was measured on: the router shape (1,024
in / 128 out) and the prompt-optimisation shape (a 3,072-token shared prefix + 512 in / 256 out). The node's
cost is $4.40 an hour (Scan list, 70% utilisation) divided by the requests that hour serves at each shape; the
API bill prices the same requests at OpenRouter list on 5 September, with input, cached input (at each model's
own cache-read price — the shared prefix is a cache hit; a model with no cache price pays full input) and output
priced separately. Both are averaged per request over
the same two shapes, so the filled marker (node) and the hollow marker (API) are the same work at the same mix,
and the gap between them is the ratio in the table. The dashed step is the frontier: nothing sits both cheaper
and better than a point on it. box/frontier.py regenerates the chart and the table from results/.
| configuration | accuracy (items) | API accuracy, same items | workloads averaged | avg tokens / request (in · out) | node $/M tokens | API $/M, market median | API $/M, cheapest tier | median ÷ node | cheapest ÷ node | on the frontier |
|---|---|---|---|---|---|---|---|---|---|---|
| gpt-oss-120b MXFP4 (native) | 0.742 (124) | 0.769 | router + promptopt | 2,304 · 192 | $0.006 | $0.047 | $0.047 | 7.5× | 7.5× | yes |
| gemma-4-26B-A4B BF16 (thinking, T=0) | 0.628 (403) | — | router + promptopt | 2,304 · 192 | $0.007 | $0.091 | $0.091 | 12.1× | 12.1× | |
| gpt-oss-20b MXFP4 (native) | 0.712 (403) | 0.725 | router | 1,024 · 128 | $0.010 | $0.041 | $0.041 | 4.2× | 4.2× | |
| Muse-Glimmer-30B BF16 | 0.787 (403) | — | router + promptopt | 2,304 · 192 | $0.018 | $0.202 | $0.202 | 10.9× | 10.9× | yes |
| Qwen3.8-27B QAT NVFP4 (W4A4) | 0.792 (403) | 0.772 | router + promptopt | 2,304 · 192 | $0.019 | $0.412 | $0.412 | 21.7× | 21.7× | yes |
| Qwen3.8-27B gittensor NVFP4 (W4A4) | 0.725 (403) | 0.772 | router + promptopt | 2,304 · 192 | $0.019 | $0.412 | $0.412 | 21.4× | 21.4× | |
| Qwen3.8-27B FP8 | 0.779 (403) | 0.772 | router + promptopt | 2,304 · 192 | $0.031 | $0.412 | $0.412 | 13.3× | 13.3× | |
| DeepSeek-V4-Flash native · DP4 + EP | 0.844 (403) | 0.784 | router + promptopt | 2,304 · 192 | $0.033 | $0.081 | $0.044 | 2.4× | 1.3× | yes |
| Qwen3.8-27B BF16 | 0.806 (403) | 0.772 | router + promptopt | 2,304 · 192 | $0.042 | $0.412 | $0.412 | 9.9× | 9.9× | |
| Qwen3.8-27B unsloth NVFP4 (W4A16) | 0.752 (403) | 0.772 | router + promptopt | 2,304 · 192 | $0.047 | $0.412 | $0.412 | 8.8× | 8.8× | |
| Qwen3.8-27B RedHat NVFP4 (W4A16) | 0.772 (403) | 0.772 | router + promptopt | 2,304 · 192 | $0.047 | $0.412 | $0.412 | 8.8× | 8.8× | |
| GLM-5.3-Flash NVFP4 · DP2 × TP2 + EP (degenerate output) | 0.643 (403) | 0.824 | router + promptopt | 2,304 · 192 | $0.054 | $0.103 | $0.052 | 1.9× | 1.0× | |
| Qwen3.8-Flash-Next NVFP4 · TP4, W4A4 linears | 0.801 (403) | — | router + promptopt | 2,304 · 192 | $0.054 | $0.175 | $0.175 | 3.2× | 3.2× | |
| Qwen3.8-Flash-Next NVFP4 · TP4, auto linears | 0.801 (403, same kernels in another layout) | — | router + promptopt | 2,304 · 192 | $0.054 | $0.175 | $0.175 | 3.2× | 3.2× | |
| DeepSeek-V4-Flash native · TP4 | 0.801 (403) | 0.784 | router + promptopt | 2,304 · 192 | $0.055 | $0.081 | $0.044 | 1.5× | 0.8× | |
| GLM-5.3-Flash NVFP4 · DP2 × TP2 + EP, eager, Triton MoE* | 0.794 (403, same kernels in another layout) | 0.824 | router | 1,024 · 128 | $0.093 | $0.189 | $0.094 | 2.0× | 1.0× | |
| GLM-5.3-Flash NVFP4 · TP4 | 0.794 (403) | 0.824 | router + promptopt | 2,304 · 192 | $0.096 | $0.103 | $0.052 | 1.1× | 0.5× | |
| GLM-5.3-Flash NVFP4 · DP4 + EP | 0.792 (403) | 0.824 | router + promptopt | 2,304 · 192 | $0.100 | $0.103 | $0.052 | 1.0× | 0.5× | |
| DeepSeek-V4-Flash native · TP4 + DSpark | 0.831 (403) | 0.784 | router + promptopt | 2,304 · 192 | $0.128 | $0.081 | $0.044 | 0.6× | 0.3× | |
| GLM-5.3-Flash FP8 (native) · TP4 | 0.809 (403) | 0.824 | router + promptopt | 2,304 · 192 | $0.182 | $0.103 | $0.052 | 0.6× | 0.3× | |
| GLM-5.3-Flash NVFP4 · TP4 + MTP | 0.809 (403) | 0.824 | router + promptopt | 2,304 · 192 | $0.209 | $0.103 | $0.052 | 0.5× | 0.2× |
* GLM's DP2 × TP2 layout failed its own corruption tripwire. Its historical dashed-ring point borrows TP4 accuracy and must be excluded from the quality/cost frontier; the chart has not yet been regenerated. DeepSeek's landed: 0.844. ¹ gpt-oss-20b has no prompt-optimisation measurement at 600 W, so its point is the router shape alone — the dearer of the two per token, which flatters the API side of its ratio. Multiply any "API ÷ node" by 2.5 for the fully-loaded cost basis ($1.77 an hour). The DP4 + EP layout's own run has since landed at 0.792 (paired against TP4, 16 to 15), and DeepSeek's at 0.844; neither point is provisional any more.
What the chart says. Priced on the same tokens at the same mix against the market-median provider price, the API is 4–22× the node for every model that fits one card, 2.4× for DeepSeek-V4-Flash on its expert-parallel layout, and 1.0–1.1× for GLM-5.3-Flash on the layouts that hold quality (1.3× and 0.5× against the cheapest tier, which the table also carries). The yardstick matters more than any kernel: OpenRouter's endpoint lists (6 Sept, 00:30 UTC) show GLM-5.3-Flash served by 23 providers, 4 of them at $0.075 / $0.25 (Z.AI, Novita, GMICloud, DeepInfra's FP4) and 17 at $0.15 / $0.50 — the list tier is a promotion, the market is at twice it — and DeepSeek-V4-Flash by 15 providers from $0.068 / $0.168 to $0.21 / $0.56 with DeepSeek itself at $0.22 / $0.66, median $0.138 / $0.28. Default routing bills the cheapest, so a customer who pays list today gets the promotion; a customer who needs a named provider, a quality tier or a contract pays the median. Against the median, GLM's two-engine layout (1,300 / 2,105 tok/s) would be 1.9× if it held quality, which is why its TP2 fault is the first item on the next box; GLM at its released FP8 precision is 0.6× at the 32 streams its weights allow. The one-card ratios are smaller than the per-hour table above because cached input is priced at the providers' cache-read rates and the prompt-optimisation shape is mostly cache hits; they are still an order of magnitude. Qwen3.8-27B's ratio is the largest because its API price is high ($3 per million output tokens), not because the node is unusually good at it. The frontier is native precision plus one quantisation-aware four-bit build — gpt-oss-120b, Muse, the QAT Qwen, and DeepSeek on its expert-parallel layout at the top — and every post-training four-bit build sits below it. On blended tokens DeepSeek-V4-Flash's DP4 layout is cheaper than Qwen3.8-27B BF16 and scores higher, because a sparse MoE prefills and reads a cached prefix far faster than a dense 27B: it takes Qwen BF16 off the frontier. GLM-5.3-Flash's qualified layouts sit just below the frontier: DP4 + EP (0.792, $0.100) and TP4 (0.794, $0.096) are dominated by DeepSeek's DP4 layout and by the QAT Qwen; the DP2 × TP2 point (0.643) is excluded by its tripwire failure; native FP8 (0.809 at $0.182, 32 streams) is the highest GLM point and the dearest. Speculation (DSpark, MTP) no longer buys anything on the frontier: DeepSeek's DP4 layout without a drafter is both cheaper (4×) and better (0.844 against 0.831) than the DSpark run, and GLM's MTP head costs 4× per token for +0.015.
Three conclusions.
For anything that fits one card, self-hosting wins by an order of magnitude. On the averaged workload with cached input priced, Qwen3.8-27B, Muse, gemma-4-26B and gpt-oss cost 4–22× more from an API than from the node at Scan's list price and 70% utilisation, and 10–54× fully loaded; on the uncached per-hour table above the ratios are 9–27× and 22–67×. Even renting the same box on Vast on-demand ($6.20 an hour) beats the API by 3–15× for these. This is the class of model — "non-huge" open weights — where the node pays for itself many times over.
For the two frontier-class models that need all four cards, the answer depends on which API price is real. On the averaged
workload at Scan list and 70% utilisation, DeepSeek-V4-Flash on its fastest layout is 2.4× against the market-median provider
price and 1.3× against the cheapest FP4-reseller tier (which scores 0.784 to the node's 0.844); GLM-5.3-Flash is 1.0–1.1× against
the median on the layouts that hold quality and 0.5× against the promotional tier. GLM's two-engine layout would reach 1.9× against the median if it holds quality; the diagnosis probes' verdict: the two-engine layout serves clean output with eager mode alone at 1,460 out tok/s on routing traffic — a 20-item tripwire, not a 403-item run; the layout is recoverable on this build and its full quality run is the next step.
The FlashInfer sparse-MLA path merged on 3 Sept (PR #4802) is the other untested lever. The DGX Spark community recipe for this model (MiaAI-Lab/GLM-5.3-Flash-EXL3-2x-DGX-Sparks, sm_121) points at the next step beyond our port: it serves TP2 with CUDA graphs on through --attention-backend FLASHINFER_MLA_SPARSE_SM120 and a packed fp8_ds_mla KV cache, the native SM120 sparse-MLA path that FlashInfer merged on 3 Sept (PR #4802), rather than the Hopper backend ported here with BF16 KV. That recipe needs a vLLM with the SM120 backend, which the vendor image predates; it is the first thing to build on the next box. Their providers run them on eight-way B200-class hardware at
scale and price aggressively (DeepSeek's own API sits under everyone else). Self-hosting those two is a decision
about fidelity, data and control, not about savings — unless the fully-loaded stack holds, where they are
2.5–3.2× cheaper than the API, or the API prices move (DeepSeek's rose 2.4–4.7× in one step in August).
The node is an aggregate-throughput machine, not a latency machine. Providers quote 70–90 output tokens a second per request (Artificial Analysis: Qwen3.8-Flash-Next 74, MiniMax-M3 89). At saturation our node gives each stream 20 tokens a second at concurrency 256 and 5 at 1,024 for Qwen3.8-27B. Interactive work should run well below saturation; the ratios above are for batch and agent-harness traffic, which is what the shapes model.
Prices move. DeepSeek raised list prices 2.4–4.7× in one step on 16 August 2026; the OpenRouter figures above are a snapshot, and the node's cost is fixed for the term — that asymmetry is itself part of the case.
box/ the campaign scripts, pulled back from the nodes verbatim
ksweep.sh kernel/backend sweep: walks candidate pairs per model, keeps every pair that serves,
derives memory and sequence budgets from the card, resumable
kldiff.sh logit-level pass: two servers side by side, control pair first
evalsuite/ the 435-item task-accuracy suite (runner, families, mock server, statistics)
quality20.py the corruption tripwire
logit_diff.py next-token distribution comparison
pull_image.py lifts a vendor Docker image's Python tree over the registry API, no Docker needed
vllm_sm120_nope.py, dsa_sm120.py, pdl_patch.py, kda_patch.py the sm_120 ports
lists/ per-host sweep lists (model, TP, candidate kernel pairs, extra flags)
results/ per-run probe JSON, per-tag summaries, summary_all.tsv (327 rows), kernel lines per server
5090/ the 8× RTX 5090 tree, kept separate
report/ the full write-up, including economics and the open questions
notes/ failure analyses that did not fit anywhere else
results/summary_all.tsv is one row per (configuration, shape, concurrency) with req/s, in/out/total tok/s
and TTFT/TPOT/ITL/E2E at p50 and p99. results/kernels_by_server.tsv records the kernel line each server
actually selected, which is the only way to know what was measured.
State of the rented boxes, where every script and result lives, how to restart each thread, the pitfalls that cost
time, and the ranked list of open gaps: docs/RESUME.md. Operational helpers (push, pull,
Vast status/destroy, watchers) are in ops/.
# on a fresh sm_120 box with the vLLM cu130 image
uv pip install --system --pre "vllm[b12x]" flashinfer-python==0.6.18 flashinfer-jit-cache==0.6.18 \
--extra-index-url https://wheels.vllm.ai/nightly/cu130 \
--extra-index-url https://flashinfer.ai/whl/cu130 --index-strategy unsafe-best-match --torch-backend cu130
# the matching cubin lives only on FlashInfer's root index; the image ships a mismatched one
uv pip install --system --no-deps flashinfer-cubin==0.6.18 --index-url https://flashinfer.ai/whl/
bash box/ksweep.sh box/lists/<your-list>.txt # throughput + tripwire
MODE=eval bash box/ksweep.sh box/lists/<your-list>.txt # task accuracy on the same servers
bash box/kldiff.sh # logit-level divergenceTreat all of this as evidence about the state of sm_120 software in September 2026, which changes weekly. The measurements are honest about their limits: the first host had PCIe ACS enabled, so its tensor-parallel numbers are pessimistic lower bounds; the second is power-capped; the 5090 host is dual-socket. Where a configuration failed, the reason is recorded rather than the row omitted.