V100 Builds · released 2026-10-21
DeepSeek-V4.1-Flash-1017 EXL3
DeepSeek-V4.1-Flash at its native 1M context on 8× V100. EXL3 experts, KL 0.0358 vs the fp32 reference.
- native context
- 1M native context64K / 256K / 512K needles pass
- KL vs fp32
- 0.0358 KL vs fp32DeepSeek's native reference, 95.79% top-1
- tok/s prefill
- 2,985–3,231 tok/s prefillsolo, 8K to 128K context
- tok/s decode
- 64.9 tok/s decodesingle stream, code, DSpark on
DeepSeek-V4.1-Flash-1017 is a 384-expert MoE with a 1M-token context, Engram lookup tables and a built-in DSpark drafter. The official checkpoint is 510 GB of FP8 dense weights and MXFP4 experts. That does not fit 256 GB of Volta. The only SM70 support was an open 1Cat-vLLM PR that ran it eager, experts spilled to host RAM, at 3.5-3.9 tok/s.
I built an EXL3 expert pack that fits, picked per expert from public packs with nothing re-quantized, and ported what the engine needed to serve it: EXL3 MoE kernels, graph-captured attention over a packed FP4 KV cache, Engram from host RAM, DSpark, then a day of prefill work. It runs the full 1,048,576-token context on one 8× V100-SXM2-32GB box.
Fidelity is measured against DeepSeek's own reference code run in fp32 on CPU: KL 0.0358 and 95.79% top-1 on the current build. Solo prefill is 2,985-3,231 tok/s from 8K to 128K. With DSpark speculative decoding, a single stream decodes code at 64.9 tok/s and chat at 35.0, and two streams reach 95.5 tok/s on code. In my own day-to-day coding sessions on the live server it averages about 80 tok/s. It also takes images: the vision tower runs from host RAM, so the 1M context is unchanged.
- runs on
- 8× V100Tesla V100 32GB
- engine
- 1Cat-vLLM (SM70) · 1Cat-vLLM 1.5.1 + PR #1031 @ a36df7c
- links
- Hugging Face: franken-v100 packRecipe scripts1Cat-vLLM PR #12431Cat-vLLM PR #1031 (V4.1 bring-up, PLI Labs)1Cat-vLLMBase model0xSero 2.7 bpw packHeNryous 2.75 bpw packMia-AiLab EAQ 2.9 bpw pack
- stack
- 1Cat-vLLM (SM70), PR #1243 on #1031
- EXL3 routed experts (exllamav3 trellis, mul1 codebook, K2-K5 per expert)
- PP2×TP4, experts parallel inside each TP group
- Packed FP4 compressed KV cache
- DSpark speculative decoding (k=5)
- Fused, graph-captured decode indexer
- Vision tower streamed from host RAM (image input)
- CUDA 12.8, Triton and WMMA kernels
01
Research log
Start
First time running DeepSeek locally. 1Cat 1.5.1 supports V4-Flash, not V4.1; V4.1 lives in open PR #1031, which is 1.5.1 plus 5 commits. Pulled the 510 GB official checkpoint and built the SM70 tree against CUDA 12.8.
First tokens: 2.82 tok/s
Served the official MXFP4 weights with experts spilled to host RAM, 32K context, one sequence. Chat and a tool call were correct; decode was 2.82 tok/s. Spilling the least-routed experts first took it to 4.07.
Graphs, staging, 1M
Found CUDA graphs had been silently disabled; PIECEWISE graphs doubled decode to 8.53 tok/s. Staging spilled experts into HBM gave 10.20. Moving to DeepSeek's 1M context cost speed (9.02); a bit-exact fused Sinkhorn kernel got it to 11.85.
EXL3 experts in VRAM
Wrote the mul1 codebook, K5 and per-expert-K paths for the SM70 EXL3 MoE kernel and loaded 0xSero's 2.7 bpw pack expert-parallel. No more spill: 16.54 tok/s, TTFT about 0.2 s instead of 2.4 s, at 256K context.
Packed FP4 KV, native 1M
Stored the compressed KV packed instead of as fp16. Greedy output stayed byte-identical and the KV pool reached 1,427,403 tokens, so 1M fit. A 533,739-token needle passed.
30.1 tok/s, exact
Fused hyper-connection kernels, split-K decode attention, per-layer graphs with device-side builders, async scheduling, deferred zero-copy Engram and a 1530 MHz clock lock. 30.1 tok/s single stream at KL 0.0000 vs the exact kernels, 74.0 aggregate at four streams.
CPU oracle and the franken pack
Built an fp32 CPU oracle from DeepSeek's reference code and measured packs against it: 0xSero 0.0663, HeNryous 0.0421, franken 0.0364. Same decode speed for all three. Fixed the DSpark PP bookkeeping and drafter graph bugs, and trimmed the stage-2 budget to 22.0 GiB so the drafter and 1M KV fit together.
Published
Batch-invariant GEMM buckets, and DSpark at two sequences once the drafter's all-reduces moved to NCCL. Uploaded franken-v100 to Hugging Face and opened PR #1243 against 1Cat-vLLM.
Memory that stays put
Every OOM so far was memory allocated after vLLM's profiler ran. Added demand-mapped KV through CUDA VMM, one shared pool for the decode graphs and fail-fast workers. A 30-minute agent-style soak passed with 70+ completions and no errors.
Prefill set
Exact decoder replay (layers 21-39 only on each request's last 3,072 rows), fused WMMA prefill attention at 1.45 ms per layer instead of 9.46, a tiled EXL3 prefill MoE kernel and Engram lookahead. Solo prefill went from 527 / 626 / 617 to 989 / 1,636 / 2,274 tok/s at 8K / 32K / 128K, KL 0.0358.
Engram in RAM
Moved the Engram tables from a ZFS dataset into hugepage RAM, split across both NUMA nodes. Solo prefill reached 2,186 / 2,841 / 2,376 tok/s.
Layer-sliced prefill
A long prefill now runs in slices of a few layers between decode steps. A stream decoding during a 32K prefill went from 6.0 to 52.6 tok/s, with sliced and unsliced prefill bit-identical.
Fused indexer kernels
Fused kernels for indexer candidate scoring, scan-and-mask and top-512. Solo prefill 2,985 / 3,231 / 3,194 tok/s, 56.9 tok/s for a stream decoding through a 32K prefill. Oracle KL unchanged at 0.0358.
DSpark fix and fused decode, current build
Scaled the DSpark taps before the fp16 cast so attention-sink tokens no longer overflow, and made the decode indexer a fused, graph-capturable kernel. Single-stream code decode went from 43.8 to 64.9 tok/s, and decode at 128K context from 28 to 53. KL unchanged at 0.0358.
Image input
Turned on the vision tower and aligner, which the port had skipped, with the weights in host RAM so the 1M context stays. Image tokens route through the MoE gate's vision bias and skip Engram, as in DeepSeek's reference. Also fixed a crash when a prefix-cache hit landed on a staged prefill. KL unchanged at 0.0358; 6 / 6 image tests answered correctly.
built on the work of
- 0xSero: his 2.7 bpw pack was the first DeepSeek-V4.1 pack that ran on 8× V100 and the baseline for two days of engine work. The first franken plan borrowed 204 of his K4 experts.
- HeNryous and the sudoingX lineage: the base pack and its sensitivity-informed bit allocation.
- Mia-AiLab: the EAQ 2.9 bpw pack the upgrades come from.
- 1CatAI: the SM70 vLLM fork that makes Volta a real target. PLI Labs' PR #1031 brought DeepSeek-V4.1 up on it.
- DeepSeek: the model, the reference inference code the oracle is built on, and DeepInfer, where the drafter-graph shape, batch invariance and the self-consistency gate came from.
02
Get it running
you'll need
- 8× Tesla V100-SXM2-32GB with NVLink, used as two quads of four (PP2×TP4, cut at layer 20).
- Host RAM for the Engram tables. The current build loads them RAM-resident, 45.78 GiB per stage-0 rank, and refuses to start unless the tables plus 32 GiB are available. My box has 372 GB and 64 cores.
- Disk: 218.6 GB for the pack, plus the two official Engram shards (101.5 GB each). Put the Engram shards on a small record size (ZFS
recordsize=16Khere): Engram reads 256-byte rows at random. - CUDA 12.8, Python 3.12, torch 2.10 cu128. Passwordless sudo lets the launcher lock SM clocks at 1530 MHz and set the CPU governor to performance.
- 1
Check the hardware
You need 8× V100-SXM2-32GB on NVLink, two quads of four. Stage 1 takes 27.77 GiB of weights per GPU and stage 2 25.29 GiB plus the drafter, so 16 GB cards are out. Plan for host RAM above the Engram tables plus 32 GiB, and disk for 218.6 GB of pack plus 203 GB of Engram shards.
shellnvidia-smi topo -m && free -g - 2
Download the pack and the Engram shards
The pack repo holds the EXL3 experts and every official non-expert tensor. The Engram tables are unmodified, so they come from DeepSeek's repo: download shards 47 and 48 into the same directory. Then run verify_engram.sh from the engine repo: it checks both shards against the Hub's sha256 and writes the
.sha256-oksidecars the launcher's preflight wants.shellhf download philbert440/DeepSeek-V4.1-Flash-1017-EXL3-franken-v100 --revision 99d85a463b446e4ff07e173be6a8faf9b920b97d --local-dir ds41-franken-v100 hf download deepseek-ai/DeepSeek-V4.1-Flash-1017 model-00047-of-00048.safetensors model-00048-of-00048.safetensors --revision 1bae0e1088993b9b82de08f59de5be5a34e42170 --local-dir ds41-franken-v100 DS41_MODEL=$PWD/ds41-franken-v100 deepseek-v4.1-v100/v100/verify_engram.sh - 3
Install the engine
Install the prebuilt SM70 wheel from the deepseek-v4.1-v100 release: the engine as served on 2026-10-25, image input included, with the three prebuilt DS41 extensions bundled. You still need the CUDA 12.8 toolkit, a C++ compiler and ninja at runtime, because the Engram reader and the TileLang kernels compile on first start. To build from source instead, clone the tag and follow the repo README. PR #1243 is the engine as of 2026-10-21, without the later prefill, decode and DSpark fixes.
shellgit clone https://github.com/philbert440/deepseek-v4.1-v100 # wheel + SHA256SUMS from the ds41-vision-20261025b release sha256sum -c SHA256SUMS uv venv --python 3.12 .venv uv pip install --python .venv/bin/python ./1cat_vllm-1.5.2.dev1149+ds41vision1025b-cp312-cp312-linux_x86_64.whl ninja --torch-backend=cu128Release ds41-vision-20261025b (wheel)deepseek-v4.1-v100: build from sourcePR #1243 (2026-10-21 engine)
- 4
Launch
v100/serve_ds41.sh is the live configuration: PP2×TP4 cut at layer 20,
--max-model-len 1048576,--max-num-batched-tokens 1024,--gpu-memory-utilization 0.943, DSpark with 5 draft tokens,--max-num-seqs 2, and everyVLLM_DS41_*knob the published numbers were measured with. Copy the env example and set your paths and GPU quads, then dry-run: preflight checks that the GPUs are free, each quad is all-NVLink, and the shards, port and memory are in place, without launching.DS41_DSPARK=0switches to plain decode. With passwordless sudo the launcher sets the CPU governor and locks SM clocks at 1530 MHz. With Engram loaded into RAM, a boot takes about 12 minutes.shellcd deepseek-v4.1-v100 cp v100/ds41.env.example ds41.env # DS41_MODEL, DS41_PYTHON, DS41_GPUS_A / DS41_GPUS_C source ds41.env v100/serve_ds41.sh --dry-run --strict v100/serve_ds41.sh # detached tmux session; --foreground to stay attachedserve_ds41.shds41.env.exampleHF recipe (2026-10-21 launcher)
- 5
Smoke test
Served model name is
deepseek-v4.1-flash, onDS41_PORTfrom ds41.env. Healthy looks like/health200,391for the prompt below, and aget_weathercall with{"city": "Toronto"}and finish_reasontool_callsfrom v100/smoke.py, which also reports streamed decode tok/s. Thinking is off by default; passchat_template_kwargs: {"thinking": true}and it arrives in thereasoningfield. Images go in as OpenAIimage_urlcontent parts (data URLs work), also inside tool results, up to 64 per prompt; each image becomes up to 1,024 prompt tokens.shellcurl -s http://127.0.0.1:$DS41_PORT/v1/chat/completions -H 'Content-Type: application/json' -d '{"model":"deepseek-v4.1-flash","messages":[{"role":"user","content":"What is 17 * 23? Answer with just the number."}],"max_tokens":400,"temperature":0}'
03
Downloads
| Variant | Format | Runs on | Size | DL / 30d |
|---|---|---|---|---|
| franken-v100, ~2.8 bpw routed experts philbert440/DeepSeek-V4.1-Flash-1017-EXL3-franken-v100 | EXL3 ~2.8 bpw routed experts + official FP8 / BF16 / MXFP4 dense and drafter | 8× V100 | 218.6 GB (+ 203 GB official Engram shards) | 186 |
04
Inference stack
PR #1031 (PLI Labs) is the V4.1 bring-up on 1Cat 1.5.1. PR #1243 stacks on it and carries the engine as of 2026-10-21: EXL3 MoE kernels, graph-captured decode attention, fused hyper-connection kernels, the Engram host service, DSpark, batch-invariant GEMMs.
The current build adds decoder replay, fused prefill attention, a tiled EXL3 prefill MoE kernel, RAM-resident Engram, layer-sliced prefill, fused indexer kernels, a graph-capturable fused decode indexer, the DSpark fp16 tap fix, a sliced-prefill fix for prefix-cache hits and image input. None of that is in PR #1243; deepseek-v4.1-v100 carries it.
deepseek-v4.1-v100 is the engine as served on 2026-10-25: #1031's tree imported unmodified, then the engine squashed on top. Its tree equals engine commit 714597f124 except for publication edits (host names in comments, extension and bench-script default paths, the Engram reader also finding its sources inside the package, internal gate drivers removed). No kernel or model logic differs. The two engine commits after it, the sliced-prefill fix and image input (engine commit 71c3e6e14f), are replayed as they are. The release ds41-vision-20261025b carries the current prebuilt SM70 wheel (up to 64 images per prompt); ds41-final-20261025 is the text-only one.
Every addition sits behind a VLLM_DS41_* knob. Each one was gated against the fp32 oracle before it went live.
CUDA 13 dropped Volta, so the stack stays on CUDA 12.8.
upstream PRs carried · 1CatAI/1Cat-vLLM
- #1243[Model][SM70] DeepSeek-V4.1-Flash-1017 on 8x V100: EXL3 experts, graph attention, DSpark speculative decoding, 1M context (stacks on #1031)
05
Recipe
5.1The pack: per-expert selection, nothing re-quantized
The base is HeNryous' 2.75 bpw pack (sudoingX lineage, sensitivity-informed per-expert bits, native-1017 calibration). It measured best of the public packs on my oracle panel.
frankenplan.py upgrades experts to the next wider K available (K2→K3) from Mia-AiLab's EAQ 2.9 bpw pack, in descending routing frequency, until each pipeline stage's byte budget is used. Budgets per GPU are 24.37 GiB on stage 1 (layers 0-19) and 22.0 GiB on stage 2 (layers 20-39). Stage 2 is tighter because it also holds the DSpark drafter and the 1M-token KV cache. A 23.0 GiB stage-2 variant scored the same KL (0.036) but only fits plain decode.
Routing frequencies come from histograms over a mixed workload (route_workload.py). The first franken plan also borrowed 204 K4 experts from 0xSero's pack; the published one fills its budget from HeNryous and Mia alone.
Dense, attention, Engram, head and the three MTP blocks stay as the official FP8 / BF16 / MXFP4 tensors. make_franken_hybrid.py assembles symlinks plus a merged index and plan, and repack_upload.py wrote the published shards byte-exact from the donors.
5.2The engine port
PP2×TP4, one pipeline stage per NVLink quad. DeepSeek's 2304-wide experts don't split across 4 ranks at the kernel's 128-column Hadamard blocks, so experts run expert-parallel inside each TP group: each rank owns whole experts, balanced by routing histogram. No new collective, since the MoE output was already all-reduced.
The EXL3 trellis is decoded inside the MoE GEMV, nothing dequantized to memory: mul1 codebook, K2-K5 per expert from one flat buffer. A grouped kernel decodes each expert once per ≤8 routed slots and takes over from 2 rows. Dense weights run FP16 with FP32 accumulation and an exact norm chain.
The compressed KV is stored packed, FP4 E2M1 plus an E4M3 scale per 16 values, 288 B per latent. Storage is lossless (greedy output byte-identical to the fp16 cache), and it is what made 1M fit. Engram's 256-byte rows were first served from disk through a deferred zero-copy path; the current build holds the tables in hugepage RAM and the gather is a memcpy.
Decode runs per-layer CUDA graphs with device-side metadata builders; the drafter has its own plain graphs per batch size. Prefill got decoder replay (layers 21-39 run only each request's last 3,072 rows, exact), fused WMMA sparse attention, a tiled EXL3 prefill MoE kernel, PP prefill pipelining, layer-sliced prefill between decode steps, and fused indexer kernels for candidate scoring, scan-and-mask and top-512.
5.3How fidelity is measured
V100 has no FP8, so there is no GPU reference to compare against. oracle_cpu.py runs DeepSeek's own inference/model.py on CPU in fp32, with every tilelang kernel replaced by exact torch math: act_quant with power-of-2 scales, FP4 ties-to-even, FP8/FP4 GEMMs as dequant plus fp32 matmul, sparse attention with sink, Sinkhorn.
The panel is 8 domains, 3,134 positions, prompt plus the model's own greedy reply. I report KL on the reference's top-20 support, top-1 agreement and the NLL gap. The panel is small and writing-heavy and reads about 2× the KL the pack cards report on their own panels, so compare packs with each other.
Every engine change also has to pass self-consistency (step-wise decode vs one-pass prefill of the same tokens, mean KL ≤ 0.05), batched-vs-single exactness, bit-identity where slicing changes the schedule, needles, the prefix cache gate and a tool-call smoke. Perf A/Bs ran on a loopback-only port with the access log checked. Numbers taken while other clients hit the server were thrown out.
06
Results
Natural chat-template prompts, temperature 0, stopping at the model's own EOS, 1M context, DSpark k=5. Two streams is the aggregate. AL is tokens produced per verify step, the bonus token included. replay_bench's short completion-style prompt, which has no BOS, decodes at 69.5 tok/s steady; it never hit the fp16 tap bug, which is why the old 69.2 headline looked fine. In real use the number is higher: my own agentic coding sessions through dsh on the live server average about 80 tok/s, Over those sessions the server logged an AL of 4.3, the same as the code benchmark and nearly twice chat's.
| Content | 1 stream | AL | 2 streams | Previous build, 1 stream |
|---|---|---|---|---|
| Code | 64.9 tok/s | 4.38 | 95.5 tok/s | 43.8 tok/s |
| Structured JSON | 65.9 tok/s | 4.35 | 103.3 tok/s | 44.4 tok/s |
| Chat | 35.0 tok/s | 2.27 | 57.3 tok/s | 29.1 tok/s |
| Prose | 34.5 tok/s | 2.25 | 52.3 tok/s | 26.3 tok/s |
measured on: My 8× V100-SXM2-32GB box, franken-v100, current build (2026-10-25), loopback-only server
Synthetic test images with known content, OpenAI image_url parts, temperature 0. Time is the whole request. The vision tower's output is within 1.5e-2 relative L2 of an fp32 run of DeepSeek's reference tower (the reference's own bf16 path: 2.7e-2). Text gates on the same build: KL 0.0358, self-consistency worst mean 0.0237, KV pool 1,055,580 tokens.
| Image | Prompt tokens | Answer | Time |
|---|---|---|---|
| Red circle, 800×600 | 340 | A red circle. | 1.1 s |
| Text "VOLTA 4417", 800×600 | 330 | VOLTA 4417 | 0.8 s |
| Five blue rectangles, 800×600 | 336 | 5 | 0.8 s |
| Text "GERTY 2400", 2400×1600 | 991 | GERTY 2400 | 5.3 s |
| Screenshot inside a tool result | 635 | PORT 8041 | 1.2 s |
| Three images in one prompt | 980 | VOLTA 4417 / PORT 8041 / circle | 2.2 s |
measured on: My 8× V100-SXM2-32GB box, franken-v100, current build with image input (2026-10-25)
8 domains, 3,134 positions, top-20 support. Plain decode, no DSpark. The franken tok/s were measured on the first franken plan (with 0xSero K4 experts, 23.0 GiB stage-2 budget); the published pack's KL row is its own.
| Pack | Routed bpw | KL | Top-1 | NLL gap | 1 stream | 4 streams |
|---|---|---|---|---|---|---|
| 0xSero 2.7 bpw | 2.70 | 0.066 | 94.2% | +0.052 | 30.68 tok/s | 59.7 tok/s |
| HeNryous 2.75 bpw | 2.75 | 0.042 | 95.5% | +0.028 | 30.56 tok/s | 71.7 tok/s |
| franken-v100 | ~2.8 | 0.0365 | 95.6% | +0.019 | 30.56 tok/s | 63.0 tok/s |
measured on: My 8× V100-SXM2-32GB box, PP2×TP4, 1Cat-vLLM SM70 port as of 2026-10-20
Same oracle panel. Writing is the weak spot for every pack I measured.
| Domain | KL | Top-1 | Positions |
|---|---|---|---|
| Code | 0.0113 | 98.82% | 847 |
| Math | 0.0141 | 96.99% | 432 |
| Agentic | 0.0284 | 95.00% | 440 |
| Multilingual | 0.0372 | 97.48% | 318 |
| Knowledge | 0.0396 | 94.50% | 418 |
| Chat | 0.0650 | 93.52% | 432 |
| Writing | 0.1113 | 88.66% | 247 |
| All | 0.0358 | 95.79% | 3,134 |
measured on: My 8× V100-SXM2-32GB box, published pack, current build (2026-10-25)
replay_bench.py: prompt tokens / TTFT, max_tokens 1, unique random prefix per request so the prefix cache cannot hit. Each row adds to the one above.
| Build | 8K | 32K | 128K |
|---|---|---|---|
| Start of day (all prefill knobs off) | 527 | 626 | 617 |
| + replay, fused attention, tiled MoE, Engram lookahead | 989 | 1,636 | 2,274 |
| + RAM-resident Engram | 2,186 | 2,841 | 2,376 |
| + layer-sliced prefill | 2,205 | 2,819 | 2,370 |
| Current: + fused indexer kernels | 2,985 | 3,231 | 3,194 |
measured on: My 8× V100-SXM2-32GB box, franken-v100, 1M context, DSpark on, loopback-only server; successive builds of 2026-10-24
replay_bench.py hol: one greedy stream decoding, then a 32K prompt arrives. tok/s of each side while both run. The current slicer gives the faster decoder more of each step. A 35K prompt arriving mid-decode on the current build prefills at 1,550 tok/s while the resident stream keeps 38.9 tok/s (43.1 alone); the longest stall is 0.38 s.
| Build | Prefill tok/s | Decoder tok/s during prefill |
|---|---|---|
| Start of day | 696 | 2.04 |
| RAM-resident Engram, unsliced | 2,263 | 6.01 |
| Layer-sliced prefill | 1,398 | 52.6 |
| Fused indexer kernels (2026-10-24) | 1,616 | 56.9 |
| Current (2026-10-25) | 1,460 | 56.0 |
measured on: My 8× V100-SXM2-32GB box, franken-v100, 1M context, DSpark on, loopback-only server; builds of 2026-10-24 and 2026-10-25
lc_decode.py, DSpark on. No cliff with context: decode at 128K matches 8K. The fp16 tap fix doubled it; with only the fused decode indexer, the same night's numbers were 24.4 and 28.3 tok/s.
| Context | Decode tok/s | Prefill tok/s on the same prompt | Time to first token |
|---|---|---|---|
| 8K (8,192 tokens) | 51.0 | 2,576 | 3.2 s |
| 128K (131,072 tokens) | 52.6 | 3,207 | 40.9 s |
measured on: My 8× V100-SXM2-32GB box, franken-v100, current build (2026-10-25)
Plain decode, no DSpark. First two rows are smoke.py's 256-token stream; the rest are bench_decode.py medians.
| Build | Context | Decode tok/s |
|---|---|---|
| #1031 as-is: MXFP4, experts spilled to host, eager | 32K | 2.82 |
| + least-routed experts spilled first | 32K | 4.07 |
| + CUDA graphs actually on | 32K | 8.53 |
| + spilled experts staged to HBM | 32K | 10.20 |
| + fused Sinkhorn, at 1M | 1M | 11.85 |
| EXL3 experts in VRAM (0xSero pack), no spill | 256K | 16.54 |
| + packed FP4 KV | 1M | 16.72 |
| + graph attention, device builders, exact norm | 1M | 26.74 |
| + async scheduling, deferred Engram, 1530 MHz lock | 1M | 30.1 |
measured on: My 8× V100-SXM2-32GB box, PP2×TP4, successive 1Cat-vLLM SM70 builds, 2026-10-18 to 2026-10-19
| Gate | Result | Build |
|---|---|---|
| KL vs fp32 native reference | 0.0358, top-1 95.79% (3,134 positions) | Current |
| Self-consistency (decode vs prefill) | PASS, worst mean KL 0.0237 | Current |
| Sliced vs unsliced prefill | Bit-identical, 0 / 56 mismatches | Current, 512K |
| KV pool at 1M context | 1,055,580 tokens | Current |
| Tool call (get_weather) | Correct call, finish_reason tool_calls | Current |
| Image answers | 6 / 6 correct, incl. 2400×1600, a tool-result image and three images in one prompt | Current |
| Prefix-cache hit during a staged prefill | PASS (55K cached + 3.9K new while another stream decodes) | Current |
| Fused indexer GPU tests | 8 / 8 (two diffs are near-ties) | Current |
| Needle 64K / 256K at the 1M config | PASS, 599 / 558 tok/s prefill | 2026-10-20, DSpark |
| Needle 512K (533,739 tokens) | PASS, 418 tok/s prefill | 2026-10-19, 0xSero pack |
| Batched vs single greedy | x2 6/6, x3 9/9 identical | 2026-10-21 default |
| Prefix cache, 16K prompt | 16 s cold → 1 s hit, same continuation | 2026-10-21 default |
measured on: My 8× V100-SXM2-32GB box, franken-v100; the build is named per row
07
Findings
- CUDA graphs were silently off at the start. The engine asked for FULL_AND_PIECEWISE, the attention backend reported NEVER, and vLLM fell back to no graphs. Forcing PIECEWISE took decode from 4.04 to 8.53 tok/s with byte-identical output.
- The EXL3 trellis decode is ALU-bound on V100, not bandwidth-bound. MoE cost scales with unique experts touched per step. Split-K bought -18% at one route per rank and nothing at two or more; a persistent stream-K decode kernel came out at 0.55-0.85x of the grouped kernel.
- DSpark with the eager proposer was net-negative: 18.7 vs 30.5 tok/s plain, with normal acceptance. The drafter graphs gave 11% acceptance until I found that each drafter layer has its own KV group and block table. The B>1 crash turned out to be vLLM's custom all-reduce inside the drafter graph; running only the drafter's all-reduces on NCCL fixed it.
- DSpark drafts were all zeros for the first ~100 steps of every chat request. The drafter's taps were captured in fp16, and the attention-sink tokens at the start of a chat (BOS, the user tag, the first word) overflow 65,504. The resulting NaNs sat in the drafter's 128-token window until those positions scrolled out. Completion-style prompts have no BOS, so benchmarks never showed it. Scaling the taps down before the fp16 cast fixed it: steps with NaN drafts went to zero, first-draft acceptance on code went from 0.49 to 0.90, and single-stream code decode from 43.8 to 64.9 tok/s.
- The same bug explains an earlier ceiling. First-draft acceptance had topped out near 0.49 even on easy content and came in streaks, 0.20 after a step that accepted nothing and 0.67-0.91 after one that accepted something. A trace had ruled out an off-by-one in the PP bookkeeping. It was the NaN window: while it was in place, nothing the drafter proposed could be accepted.
- Batched decode flipped tokens that single-request decode picked by a 0.19-nat margin, by 0.2-0.7 nats per copy. Cause: cuBLAS picks its kernel by row count, amplified through 40 MoE layers at 2.8 bpw. Padding GEMM rows to fixed buckets (≤16 → 16, else multiples of 64) took mixed-step KL from 0.12 to 0.013 at no measured speed cost.
- The port's hidden-state drift vs the reference was the 2.7 bpw experts, not missing activation quantization. Per-layer cosine fell smoothly from 0.999 at layer 0 to 0.87 by layer 30. An oracle without activation QAT matched the port worse (0.875 vs 0.898).
- Capping prefill tokens per step was a poor fix for head-of-line blocking. On a cold-Engram bench, a 128-token cap lifted the co-running decoder from 0.8 to 3.20 tok/s and cut prefill from 480 to 307 tok/s. Chunk cost is mostly fixed: a 1024-token chunk already touches 86 of 94 local experts. Layer-sliced prefill is what fixed it.
- A decode-priority lane on its own was rejected: no decoder gain, prefill down 25-30%. Prefill chunks of 2048 did not fit 1M; the window and state groups cap context at about 791K there.
- Engram on a 16K-record ZFS dataset capped cold reads at about 2.0 s per chunk's 49K records, regardless of thread count. Holding the tables in RAM cut a 1024-token chunk's gather to 0.9 ms from about 400 ms of cold pread per rank.
- Binding workers to their NUMA node changed nothing measurable (4.04 vs 4.03 tok/s). Locking SM clocks at 1530 MHz did: 26.90 to 27.68 tok/s median, minimum 23.05 to 26.92, because auto-boost dipped between latency-bound decode bursts.
- The checkpoint always had a vision tower; the V100 port just skipped it. Running it without costing context meant keeping its 926 MiB of weights in pinned host RAM and streaming them through two small GPU buffers per image, because the 1M KV pool leaves about 8 MB free per GPU. One surprise: PyTorch attention takes the math path on Volta and builds the full score matrix, 4.2 GiB for a large image. Chunking the queries keeps it near 128 MB with bit-identical output.
- prompt_logprobs on long prompts runs out of memory in the 1M DSpark configuration. There is no slack for full-vocabulary chunk logits.