
How I made DeepSeek V4 Flash 12x faster on an M3 Ultra
I work with a Mac Studio M3 Ultra (512GB) serving DeepSeek V4 Flash on antirez/ds4 ("DwarfStar"). A chat turn took between 6 and 20 seconds. Now it takes 1.6s.
Kernels (+21% cold prefill at 64k, bit-exact). DeepSeek V4's sparse attention runs a "lightning indexer" that dominates long-context prefill. Three stacked PRs: threadgroup-tiled scorer (#830), register-blocked K-resident scorer (#831), and a streaming top-512 replacing the bitonic sort + merge cascade (#832). 392 → 475 t/s at 64k. Logits byte-identical at every context frontier, everything behind rollback envs.
Cache, the 10x (this part is useful way beyond DeepSeek or ds4). If you serve any model behind a chat API, check whether your client can actually hit the engine's KV cache, because a stateless client usually can't:
- The live session ends in the exact reply the engine sampled. If your client doesn't resend that reply byte for byte (exact text, or the tool call by id), the prefix never matches and you re-prefill every turn. Replay it verbatim and
cached_tokens≈ everything. - Prewarming:
max_tokens: 0. Send the conversation with zero tokens requested and the engine prefills it and stops exactly at the prompt, so the next real request extends the cache.max_tokens: 1doesn't work: the one sampled token becomes part of the session and every later request misses. Great for warming a room/session before anyone asks anything, or re-warming after your slot got evicted.
Recipe with measurements: ds4#816.
Also you can read the things I tried that didn't work (single-stream decode is a wall, and I learned two Metal scheduling laws killing it) here:
https://adriangalilea.com/deepseek-on-a-mac-studio
EDIT: Regarding cache, I failed to mention there was an engine bug that was part of the 10x: the disk cache's eviction policy scored the only checkpoint a chat client can reuse as the first victim, so once the disk filled, every request prefilled from zero. Fixed in ds4#814.