--- license: mit tags: [inference-engine, moe, fp8, cpu, meituan, longcat, longcat-flash-thinking, systems] --- # dragon.c: A From-Scratch C Inference Engine for **Meituan LongCat-Flash-Thinking** (560B MoE, FP8) on a 31 GB Consumer Laptop **bespoke ontology β€” field engineering record, 2026-07-05** > **πŸ“¦ Source code available on GitHub:** https://github.com/bespokeontology/dragon.c ![dragon.c launch card](launch_card.png) *Built and validated in one night on a Dell laptop (RTX 4070 8GB, 31 GB RAM, Ubuntu 24.04), plus a GPU tier the following session: 50Γ— total speedup, ~6 s/token and falling.* --- ## Abstract We present dragon.c, a from-scratch C inference engine that runs **[Meituan LongCat-Flash-Thinking-FP8](https://huggingface.co/meituan-longcat/LongCat-Flash-Thinking-FP8)** (560B parameters, Mixture-of-Experts) on a consumer laptop with 31 GB of RAM. The engine reads the model's native FP8 safetensors directly via mmap β€” no format conversion, no GGUF, no llama.cpp, no Python in the hot path β€” and streams 531 GB of weights through 31 GB of memory using the OS page cache as the eviction layer. Every mathematical operation was validated brick-by-brick against a PyTorch reference to floating-point precision, culminating in a full 28-layer forward pass whose output logits are IDENTICAL to the reference (same top-5 token IDs, logits within ~0.1). The engine generates coherent English. Through four measured optimization rounds (f32 LRU cache β†’ native-precision compute β†’ AVX2+LUT kernels β†’ a GPU-resident attention tier on the RTX 4070) decode latency improved 50Γ— to ~6 s/token, with output invariant across every optimization. We document every dead-end as a control. The build demonstrates the thesis this project exists to prove: **the deficit in consumer-hardware AI is drivetrain, not engine** β€” organization of computation and data movement, not parameter count. --- ## 1. Hardware and model | | | |---|---| | Machine | Dell laptop, Ubuntu 24.04, 31 GB RAM, RTX 4070 Laptop 8 GB, NVMe SSD | | Model | **Meituan LongCat-Flash-Thinking-FP8** (`meituan-longcat/LongCat-Flash-Thinking-FP8`), 560B MoE, 531 GB on disk, 75 safetensors shards, 43,756 tensors | | Architecture | 28 decoder layers, each with **2 sub-blocks** (so 56 attention units); hidden 6144; vocab 131,072 | | Attention | MLA (Multi-head Latent Attention): 64 heads, qk_nope 128 + qk_rope 64 (head dim 192), v 128, q_lora 1536, kv_lora 512 | | MoE | 512 real experts + 256 zero-compute (identity) experts, top-12, routed_scaling 6.0, expert FFN 2048 | | ScMoE | Shortcut-connected MoE: the MoE is computed on sub-block-0's normed hidden state but its output is added at the END of sub-block-1 β€” a designed overlap window | | Precision | HYBRID: attention/norms/embeddings bf16, router f32, the ScMoE FFNs fp8 β€” both the routed experts AND the per-sub-block dense branches (e4m3, 128Γ—128 blockwise f32 scales stored IN the shards, not in the index) | ## 2. Method: validate every op, advance only on proof The build discipline, applied without exception: 1. Dump ground-truth tensors from a working Python/PyTorch reference (`ref/*.f32`). 2. Write the C implementation of ONE operation. 3. Compare element-wise. Advance only when the diff is at floating-point-noise level. 4. Write the result (and every dead-end) into the permanent record before moving on. This discipline caught real bugs at every stage and β€” critically β€” caught a **corrupt reference** (Β§6) that would otherwise have burned days. ## 3. Phase results (every brick, with measured error) | Phase | Operation | Max abs diff vs reference | Notes | |---|---|---|---| | 1 | safetensors reader (mmap, u64-LE header JSON, byte offsets) | byte-exact | embed row verified byte-for-byte | | 2b | RMSNorm (dim 6144, eps 1e-5) | 2.4e-7 | | | 2c | FP8 e4m3 dequant + 128Γ—128 block scales + matmul | **0.0 (bit-exact)** / 4.3e-7 | dequant is exactly reproducible | | 2d | MLA attention (full: lora projections, interleave, rope, softmax, 64 heads) | 6.9e-3 | the hardest op; see Β§4 | | 2e | MoE (router softmax + bias + top-12 + SwiGLU experts + identity zeros) | 1.68e-6 | | | 2f | Full ScMoE decoder layer (2 attn blocks + MoE + 2 dense MLPs + 4 norms + shortcut + residuals) | 1.9e-6 | whole layer in C | | 3 | Full 28-layer forward, native streaming | logits IDENTICAL (top-5 same IDs, ~0.1) | 74 s cold, pure CPU | | 4 | Generation (chat/think template, vocab decode, KV cache) | output identical across engines | "The user is asking a simple arithmetic question" | ## 4. The three MLA constants nobody tells you about Hand-deriving MLA from the paper failed (diff 1.7). Reading Meituan's `modeling_longcat_flash.py` line-by-line revealed three undocumented-in-practice details, without which the attention is wrong: 1. `mla_scale_q_lora = 2.0` β€” q_pass AND q_rot are multiplied by 2.0. 2. `mla_scale_kv_lora = 3.4641016151377544` (= 2√3) β€” applied to the kv-lora vector AFTER its layernorm. 3. **Interleave-before-rope** (`use_mla=True` path): before rotary embedding, the rope dims are reshaped `[d/2,2]β†’transposeβ†’[d]` (even indices first, then odd). Softmax scale = 192^(-0.5) = 0.07216878. k_rot is computed ONCE per token and SHARED across all 64 heads. With these three, hand-MLA matches the module to 6.9e-3 (bf16 noise). These constants are now permanent record; they never have to be rediscovered. ## 5. The engine (Phase 3): manifest + mmap + page-cache eviction Design (the "game-engine pattern" β€” assets in a PAK file, OS does the paging): - **Manifest**: Python pre-parses all 75 shard headers ONCE into `manifest.bin` β€” 43,756 fixed-width records (name, shard id, dtype, absolute byte offset, shape, scale-tensor location). C mmaps it and bsearches by name. No JSON parsing in C, ever. - **mmap everything**: all 75 shards are mmap'd read-only at startup. `get_tensor` returns pointers into the maps. Weights are NEVER malloc'd/copied (in the final engine β€” see Β§8). - **Eviction = the kernel's page cache.** 531 GB streams through 31 GB because Linux pages weights in on touch and evicts them under pressure. Zero eviction code. The OS is the streaming layer. - **OpenMP** across output rows of every matvec (14 threads). Result: full 560B forward, 74 s cold. Layer-0 through the native read path matches Python to 2.2e-3. ## 6. The control that saved the build: the reference was poisoned While validating the full layer, our composition differed from the saved reference by 3.48 β€” for an hour this looked like a C bug. It was not. Root cause, found by checking `weight.is_meta`: > Meituan's router does `self.classifier.weight` (direct attribute access) instead of calling > `self.classifier(x)`. Our Python-side lazy-loading hook fires on `__call__` β€” so it NEVER fired > for the router. The router weight stayed on the meta device, the module's MoE routing was garbage, > and the garbage was silently baked into the saved reference tensor. Force-loading the router and regenerating gave a clean reference β€” which our C matched to 1.9e-6. **The C was right all along; the reference was corrupt.** Lessons, now permanent controls: - Never trust a module-derived reference until 0 meta params is verified. - Any op that touches `.weight` directly bypasses load hooks. - dragon.c loads every weight explicitly and is structurally immune to this bug class β€” the strongest single argument for owning the engine instead of trusting a framework. Other controls earned earlier and re-confirmed tonight: the BOS token (id 1) NaN-poisons layer 0 and must never be added; the model is a THINKING model β€” raw completion is out-of-distribution (it predicted "Berlin" in the top-5 for "The capital of France is" β€” capitals-space, correct neighborhood; clean Python predicts the identical top-5, proving this is model behavior, not an engine bug); the chat template + `` is the in-distribution format. ## 7. Generation: the dragon speaks Tokenizer stays out of C: Python dumps `vocab.bin` (131,072 length-prefixed decoded strings) once; C prints text directly. Prompt: the official chat template for "What is 2+2?" β†’ `What is 2+2? /think_on `. First generated words from the from-scratch engine: > **"The user is asking a simple arithmetic question"** Fluent, on-topic chain-of-thought. No NaN, no gibberish. This sentence has remained byte-identical across every subsequent engine optimization β€” it is the correctness canary. ## 8. The speed war: three rounds, each measured, each a lesson **Round 1 β€” f32 LRU weight cache + MLA KV cache (dragon_fast.c): 88 s/token. FAILED to speed up.** The KV cache itself is correct (reproduces recompute output exactly β€” "The user…" token-for-token) and kills the O(nΒ²) attention recompute. But the LRU cached weights dequanted to **f32**, which QUADRUPLES fp8 and DOUBLES bf16: the dense MLPs alone become 51 GB of f32 β€” cannot fit 31 GB β€” 41% hit rate β€” thrash. **Measured diagnosis: the bottleneck was never attention. It is WEIGHT BANDWIDTH β€” each token moves ~50 GB of weights.** **Round 2 β€” native-precision compute (dragon_native.c, scalar): 27 s/token (3.3Γ—).** Delete every f32 weight buffer. The matvec reads the mmap'd bf16/fp8 bytes DIRECTLY, dequanting inline per element. Bytes moved drop 2–4Γ—; the dense MLPs in native bf16 are 25 GB, which FITS β€” so the OS page cache holds the hot working set and "load once" happens for free, in hardware. **Round 3 β€” the matmul, written properly (AVX2 + LUT): ~9 s/token (10Γ— total), prefill 2.8 s/token.** - **fp8 via 256-entry lookup table.** e4m3 has exactly 256 possible values. The scalar path was paying a `ldexpf` LIBRARY CALL PER WEIGHT BYTE of a 560B model. Precompute all 256 floats once; dequant becomes a table read (AVX2 `vgatherdps`, 8 lanes). - **bf16 via AVX2+FMA.** bf16β†’f32 is literally a 16-bit left shift β€” free inside SIMD: load 8Γ—u16 β†’ widen β†’ `<<16` β†’ that IS the f32 β†’ `fmadd`. Two accumulators to hide FMA latency. 8 weights per instruction. The 131,072Γ—6144 lm_head uses the same kernel. - 128-column block structure of the fp8 scales folds the scale multiply out of the inner loop. **Round 4 β€” the GPU lights up (dragon_hybrid = dragon_native.c + dragon_gpu.cu): ~6 s/token (50Γ— total).** Profiling showed the 9 s spread across attention 2.6 + dense 2.8 + MoE 3.7 + head 0.3 β€” and that the box is fundamentally DISK-bound: the fixed per-token working set (~48 GB) exceeds 31 GB RAM, so every token re-reads tens of GB from NVMe. The correct GPU move on an 8 GB card is therefore NOT "put the model on the GPU" (impossible) and NOT "stream weights over PCIe" (16 GB/s β€” the trap): it is **VRAM as a permanent third cache tier**. We park the attention weights β€” 42 of 56 sub-blocks, 7.5 GB bf16 β€” in VRAM at startup and never move them again. A warp-per-row bf16 matvec kernel (one warp reduces one output row; `__shfl_down_sync` for the horizontal sum) computes attention on-card; sub-blocks that don't fit fall back to the CPU path transparently. The win is DOUBLE: attention drops 2.6 s β†’ 0.5 s (5Γ—), AND 7.5 GB leaves the RAM working set, so the page cache holds more of the dense/expert tiers and disk reads shrink across the board. | engine | s/token | change | |---|---|---| | recompute (dragon_gen) | ~300+ | correct but O(nΒ²), no caches | | f32 LRU cache (dragon_fast) | 88 | KV cache βœ“; f32 weight cache thrashes | | native scalar (dragon_native) | 27 | zero f32 buffers; page cache = load-once | | native AVX2+LUT | ~9 | the matmul | | **+ GPU attention tier (dragon_hybrid)** | **~6, falling** | **VRAM = 3rd cache tier; attn 5Γ—** | Output identical at every step β€” the generated sentence has never changed through a 50Γ— speedup. Correctness never traded for speed. ## 9. What this proves (the thesis, in working code) 1. **Real answers = the war won.** The existential question β€” can a 560B run correctly on owned consumer hardware with owned code β€” is closed. Everything remaining is tuning, not truth. 2. **The ScMoE shortcut is an owned moat.** The architecture computes the MoE on block-0's output and applies it at block-1's end β€” a designed overlap window. Generic runtimes don't exploit it; an owned engine can compute MoE βˆ₯ attention and hide expert-streaming latency inside attention math. This optimization is only accessible to someone who OWNS the engine. 3. **C, not Python β€” the game-engine discipline.** No game runs Python in the frame loop; inference IS a frame loop (tight, memory-bound, latency-critical). Python found the bugs (prototype); C runs the frame (engine). The Python stack's own flakiness (silent meta-weights, wedged processes, OOM kills) was demonstrated during this build and is documented above. 4. **Bandwidth is the drivetrain.** Every real speedup came from moving fewer bytes or moving them smarter (native precision, page cache, SIMD) β€” never from more FLOPs. The datacenter's answer to this problem is to buy more bandwidth. The drivetrain answer is to stop wasting it. ## 10. Remaining work (all de-risked, all speed/usability) - **fp8-quantize the dense tier**: 25 GB bf16 β†’ 12.7 GB with our own (bit-exact-validated) fp8 path β€” brings the fixed working set under RAM so disk only ever reads experts. Largest remaining lever. - **ScMoE overlap**: thread the MoE against sub-block-1's attention (the moat, Β§9.2). - **Compressed-latent KV cache**: store the 576-dim latent instead of expanded K/V for long context (matters beyond our current 64-token horizon). - Sampling (currently greedy argmax), longer rope table, incremental `vocab.bin` mmap. ## Artifacts here β€” full source included - `src/dragon_hybrid.c` + `src/dragon_gpu.cu` β€” **the engine** (CPU AVX2/LUT + GPU-resident attention tier) - `src/dragon_native.c` β€” CPU-only engine (no CUDA required) - `src/dragon_forward.c` β€” the proven full-forward validator - `src/dragon_read.c`, `src/phase2*.c` β€” the six validation bricks (reader, RMSNorm, fp8, MLA, MoE, full layer) - `tools/build_manifest.py` + `Makefile` β€” `make dragon` / `make dragon-gpu` - `launch_card.png` (the launch card) Β· `dragon_speaks_card.png` (the historic first-words shot) Β· `manifest.bin` (the 43,756-tensor index) ``` python3 tools/build_manifest.py /path/to/LongCat-Flash-Thinking-FP8 . make dragon # CPU-only make dragon-gpu # with the RTX 4070 attention tier ./dragon 16 ``` *β€” [kapitoshkina.ai](https://kapitoshkina.ai) Β· bespoke ontology, 2026-07-05. This is the beginning.*