Milestone: mxfp4 kernels — replace the compute sink with real math
The structural milestone (see #1) is done: pointer map, trunk streaming, 3-phase cache, and the memory gate are validated on the 304B checkpoint (gate forecast 12.5 GB vs measured 11.92 GB; 0 dropped experts over 1,290 fetches). This milestone replaces the skeleton's checksum sink with real mxfp4 math, pipelined so reads and compute overlap.
Why now — the measured evidence
- Threads sweep (4 → 20): 7.53 → 7.25 s/token. Flat. The wall is the synchronous loop + single-threaded compute sink, not read parallelism.
- GB/token = 4.06, of which ~3.2 GB is expert bytes at FP8. The pool is 137 GB.
- Replay on the real trace: compulsory ceiling 4.11%; LRU hits 0.00% at 2 GB — policy lesson already banked.
Consequence: two independent levers, both in this milestone:
- mxfp4 halves the expert bytes → ~68 GB pool, ~1.6 GB/token expert reads (the read-speed lever, invariant: 4-bit where streamed).
- Real threaded kernels + read/compute overlap → kills the sink wall (the threads sweep proves there is headroom).
Scope
1. Quantize pass (tools/convert-ds4f.py quantize)
- Input: packed
pool.bin (F8_E4M3 + per-tensor scales, copied as-is in the current convert) + tensor metadata (shapes from the safetensors index).
- Output:
pool-mxfp4.bin (E2M1, 4-bit, per-32-element block scale, MX-standard; scale = 8-bit E8M0 per block) + pool-mxfp4.json (block layout + per-expert error stats) + manifest update.
- Deterministic; block-aligned; refuse on shape/dtype surprises (no guessing — same rule as the converter).
- Quality gate: report per-expert max-abs and relative error vs the FP8 originals in the manifest. Numbers, not vibes.
- Trunk (5.26 GB dense) stays at native precision — precision asymmetry invariant: full where resident, 4-bit where streamed.
2. Kernels (src/kernels.c + include/ds4f/kernels.h)
- Scalar-correct mxfp4 first: unpack 32×4-bit block → fp32 × block scale → accumulate fp32. Portable C99.
- Matvec path (M=1 decode): hidden/latent dims from config; per-expert w1/w2/w3 with their scales.
- Router matvec: the resident high-precision router matrix (in trunk,
layers.N.ffn.gate*) — small (hidden × 256), needed to produce real top-k.
- SIMD after scalar is proven: AVX2 (x86) and NEON (arm64) paths, verified bit-identical against scalar on fixtures.
- Threaded compute: per-expert matvecs across the topk batch.
3. Pipeline (src/main.c / trunk.c pattern reuse)
- The trunk already has the async-reader pattern (ring + condvar). Extend it to experts: fetch layer L+1's top-k experts while computing layer L.
- Decode loop becomes: bind trunk L (pinned or ring) → route (resident router) → overlapped expert fetch/compute → advance.
- Multi-threaded checksum sink stays available via
--sink for comparison runs.
4. Validation ladder (tests/)
- Fixture: hand-built mxfp4 block with known values → decode → fp32 (bit-exact expected).
- Quantize round-trip on synthetic FP8 tensors: error bounds asserted (not just reported).
- Engine e2e with quantized synthetic pool: same request trace as FP8 run (routing independent of cache AND of dtype — invariant 2).
- SIMD vs scalar equivalence on fixtures.
5. Acer validation run (paste back into this issue)
quantize the real pool (~68 GB out), then rerun the laptop-preset sweep.
- Expected: GB/token ~2.1 (expert bytes halved), sec/token meaningfully lower (threaded + overlapped), RSS similar, 0 dropped.
- If sec/token still flat, the wall moved — report it, don't tune around it.
Order of work
- quantize tool + manifest shapes (shapes already available in the converter's index)
- scalar mxfp4 decode + matvec + router (fixture-gated)
- pipeline restructure (async expert fetch)
- SIMD (AVX2/NEON) + equivalence gate
- real-pool quantize + acer sweep
Acceptance
Open decisions (flag in comments)
- Expert tensor shapes (w1/w2/w3 dims) — resolve from the safetensors index during quantize; post the resolved shapes here before locking the kernel dimensions.
- Block size 32 (MX default) vs 64 — 32 unless the error stats say otherwise.
- Router placement: keep in trunk (resident when pinned) — confirm the gate tensor name from the index.
Milestone: mxfp4 kernels — replace the compute sink with real math
The structural milestone (see #1) is done: pointer map, trunk streaming, 3-phase cache, and the memory gate are validated on the 304B checkpoint (gate forecast 12.5 GB vs measured 11.92 GB; 0 dropped experts over 1,290 fetches). This milestone replaces the skeleton's checksum sink with real mxfp4 math, pipelined so reads and compute overlap.
Why now — the measured evidence
Consequence: two independent levers, both in this milestone:
Scope
1. Quantize pass (tools/convert-ds4f.py
quantize)pool.bin(F8_E4M3 + per-tensor scales, copied as-is in the current convert) + tensor metadata (shapes from the safetensors index).pool-mxfp4.bin(E2M1, 4-bit, per-32-element block scale, MX-standard; scale = 8-bit E8M0 per block) +pool-mxfp4.json(block layout + per-expert error stats) + manifest update.2. Kernels (src/kernels.c + include/ds4f/kernels.h)
layers.N.ffn.gate*) — small (hidden × 256), needed to produce real top-k.3. Pipeline (src/main.c / trunk.c pattern reuse)
--sinkfor comparison runs.4. Validation ladder (tests/)
5. Acer validation run (paste back into this issue)
quantizethe real pool (~68 GB out), then rerun the laptop-preset sweep.Order of work
Acceptance
quantizedeterministic, block-aligned, error stats in manifest--pool pool-mxfp4.binruns end-to-end with real routingOpen decisions (flag in comments)