Benchmark · Ling-3.1-flash · 8×B200

Benchmarking Ling-3.1-flash on 8×B200

Ling-3.1-flash keeps a growing KV cache in only 9 of its 72 layers. We measured what that changes on one 8×B200 node: decode from 1K to 120K tokens, cache capacity, prefix reuse, MTP drafts and recall, and where a 14-minute vLLM cold start goes.

inclusionAIMIT
Ling-3.1-flash

560B · 25B active · hybrid MoE · FP8 · MTP

  • 8×B200·47 s·647 GiB·580
restore47 s cold start854 s
ling31-flashRun
13.1 msper token at 120K context, 10.0 ms at 1K
5.2Mtokens of KV cache: 40 requests at 128K
6/6hidden codes found, up to 116K
47 swarmctl up, against an 854 s cold start

01 · THE MODELSeven linear layers, then one with a cache

Ling-3.1-flash is inclusionAI’s newest open-weight model, under the MIT license: a mixture of experts with 560B parameters, 25B active per token. Each MoE layer has 512 routed experts and one shared expert, and the router sends every token to 8 of them. The checkpoint is FP8, 572 GB, and includes one multi-token-prediction (MTP) layer for speculative decoding.

The interesting part is attention. The 72 layers repeat one block of eight: seven Kimi Delta Attention (KDA) layers, then one gated Multi-head Latent Attention (MLA) layer.

Ling-3.1-flash · 72 layers63 KDA · 9 MLA
1–8 9–16 17–24 25–32 33–40 41–48 49–56 57–64 65–72 KDA: linear attention, fixed-size state · 63 layers gated MLA: compressed KV cache · 9 layers

KDA is linear attention with a delta rule. Each head carries a fixed state matrix, 128×128 at Ling’s head size. A new token overwrites what the state currently associates with its key, a rank-one update, and per-channel gates let old content decay. Reading and updating that state costs the same at token 100 and at token 100,000, and the state never grows.

MLA is full attention over a compressed cache. Per token it stores a 512-wide latent and a 64-wide RoPE key, 576 values shared by all heads. Every earlier token stays addressable, so lookups are exact, but this cache grows with the context.

The part of memory that scales with context therefore lives in 9 layers out of 72. That leads to four predictions, and this post tests each one: decode speed should barely depend on context length; prefill should scale about linearly; a large number of long requests should fit in memory at once; and a single fact deep in the context should still be retrievable, because the MLA layers can look it up.

02 · SETUPOne 8×B200 node

All runs used one node and vLLM, on an engine restored from a warmctl snapshot of the warmed-up model; section 10 explains why.

Setup
GPUs8× NVIDIA B200, 179 GiB each, NVLink between all eight (NV18)
Host2× Intel Xeon Platinum 8580 (160 vCPU), 1.7 TiB RAM, network SSD
OS and driverUbuntu 24.04.5, kernel 6.11.0-1016-nvidia, NVIDIA driver 580.173.02
EnginevLLM 0.32.0rc1 nightly (3f1bcfd8), with the BailingMoeV3 tensor-parallel fix (vllm#61642)
ModelinclusionAI/Ling-3.1-flash at a4ccd6b4, FP8 weights, BF16 KV cache
ServingTP8 with expert parallelism; FP8 MoE on DeepGEMM (FlashInfer’s TRT-LLM router takes at most 32 experts per group, Ling has 64); MTP with 3 draft tokens; 128K context; 64 GiB of KV cache per GPU; up to 64 sequences; 8,192-token prefill chunks
warmctlv2.0.0-beta.6, snapshot ling31-flash:8xb200-180gb-580.173.02, 647 GiB
Loadvllm bench serve: random-token prompts, fixed output length (--ignore-eos), medians per run

Random prompts are the worst case for speculative decoding. Section 07 measures MTP on real text separately.

03 · DECODEFlat past 32K

one request · 256 output tokenstime per output token
0 2 4 6 8 10 12 14 10.0 ms 1K 11.0 ms 8K 13.0 ms 32K 13.1 ms 64K 13.1 ms 120K ms per output token

One request, 256 output tokens. Time per output token is 10.0 ms at 1K tokens of context and 13.1 ms at 120K. The increase happens below 32K: from 32K to 120K, a context 3.7× longer, it moves from 13.0 to 13.1 ms, and the inter-token latency stays between 13.0 and 14.0 ms across the whole range.

With full attention in every layer, each decoded token reads the entire KV cache, so the time per token rises with the context. Here only nine layers read a cache, and an MLA layer holds 1,152 bytes per token; the rest of the step is MoE and KDA work, which does not depend on context. We have no clean explanation for the step between 8K and 32K yet; 64K and 120K land on the same value.

04 · PREFILLFaster per token as prompts grow

one request · linear x axistime to first token
0 0.5 1 1.5 2 2.5 0.47 s 1K 0.52 s 8K 1.03 s 32K 1.47 s 64K 2.35 s 120K time to first token, s

Time to first token is 0.47 s at 1K and 2.35 s at 120K. Divided by prompt length, that is 2,200 tokens/s at 1K and 51,164 tokens/s at 120K: short prompts are dominated by fixed per-request cost, long ones by compute, and the cost per token keeps falling up to the 128K limit. With quadratic attention the curve would bend the other way, with prefill tokens per second dropping as prompts get longer.

one requestprefill tok/s
0 10.0k 20.0k 30.0k 40.0k 50.0k 60.0k 2.2k 1K 15.8k 8K 31.8k 32K 44.7k 64K 51.2k 120K prefill tok/s

One catch. The first 32K prompt took 5.4 s, the second 1.0 s. The warmup grid of the profile prefills 512, 2,048 and 8,192 tokens; the first longer prompt JIT-compiled kernels for its shape on the spot. A long prefill in the warmup grid moves that compile into the snapshot, so the first long request after a restore does not pay for it. The tables use the second request.

PromptTTFTPrefillTPOTITLtok/s per user
1K0.47 s2,200 tok/s10.0 ms13.0 ms100
8K0.52 s15,783 tok/s11.0 ms13.1 ms91
32K1.03 s31,845 tok/s13.0 ms13.3 ms77
64K1.47 s44,680 tok/s13.1 ms13.6 ms76
120K2.35 s51,164 tok/s13.1 ms14.0 ms76

05 · MEMORY5.2 million tokens of cache

The profile gives vLLM 64 GiB of KV cache per GPU. vLLM reports room for 5,247,384 tokens, which it translates into 40 concurrent requests at the full 131,072-token context.

64 GiB of KV cache per GPU · 8×B2005,247,384 tokens
128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K 128K each square: one request holding a full 131,072-token context

The arithmetic: with a BF16 cache, an MLA layer stores 576 values × 2 bytes = 1,152 bytes per token, and the latent is replicated on every tensor-parallel rank. Nine such layers make 10.1 KiB per token per GPU. vLLM’s figure works out to 12.8 KiB: the hybrid allocator pads layers so that the KDA states and the MLA pages share one page size, and it warns that this can cost up to 11%. Were all 72 layers MLA, the same 64 GiB would hold about 829K tokens, 6× fewer.

The profile admits up to 64 sequences. At the full 128K context the cache caps that at 40; with 32K prompts all 64 fit with room to spare, 40% of the cache.

06 · AGENT TURNSPrefix caching with a recurrent state

Coding agents resend a long, growing history with a few new tokens each turn. With full attention, reusing the cache of a shared prefix is routine. A hybrid model also needs the KDA state at the exact end of the prefix, which vLLM keeps when mamba-cache-mode is align. We sent six requests that share a 60K-token prefix, each with 1K new tokens. The median time to first token is 0.66 s, against 1.47 s for a 64K prompt the engine has not seen; the first of the six computes the whole prefix and is slower.

07 · SPECULATIVE DECODINGMTP on real text

Ling has one MTP layer; the profile runs it three times per step to draft three tokens, and the main model verifies them in a single forward pass. How much that buys depends on how predictable the text is. We asked for long answers in prose and in code, one request at a time, and read the acceptance from vLLM’s counters.

one request · MTP with 3 draft tokensdecode tok/s
random-prompt benchmark 114 tok/s prose 184 tok/s code 225 tok/s
TextDrafts acceptedTokens per stepDecode tok/s
prose50%2.51184
code68%3.05225

Prose accepts 50% of the drafts, 2.5 tokens per step, and decodes at 184 tokens/s; code accepts 68% at 225 tokens/s, time to first token included. The random-prompt runs in this post decode at 114 tokens/s per request. Benchmarks with random prompts, ours included, understate what an MTP model does on real text.

08 · RECALLDoes the state forget?

A fixed-size state cannot hold everything, so recall is the first question about linear attention. We hid a vault code at 10%, 50% and 90% depth of synthetic documents of 34K and 116K tokens, thousands of numbered filler sentences, and asked for the code with thinking off. Ling returned it 6 of 6 times; at 116K the answer takes about 4 s, nearly all of it prefill.

DocumentCode at depthAnswerTime
34K10%found4.4 s
34K50%found1.6 s
34K90%found1.5 s
116K10%found4.0 s
116K50%found4.0 s
116K90%found4.0 s

This is what the nine MLA layers are for: exact access to any earlier token, for about 10 KiB of cache per token. One planted fact per document is the easy end of long-context retrieval; multi-hop questions and long reasoning chains are a separate test.

09 · UNDER LOADThroughput for reference

1k-token prompts · 512-token answersoutput tok/s
0 200 400 600 800 1.0k 1.2k 1.4k 95 1 concurrent 373 8 concurrent 799 32 concurrent 1.3k 64 concurrent output tok/s

With 1K prompts and 512-token answers, output throughput rises from 114 tokens/s for one request to 1,276 at 64, the profile’s limit on concurrent sequences, with time to first token under 1 s. Sixty-four parallel 2K-token generations reach 2,496 output tokens/s. With 32K prompts the node processes 47,189 tokens/s at 64 concurrent requests, prefill and decode together, while each request still streams a token every 40 ms between prefill chunks.

Tokens in → outConcurrentOutput tok/sTotal tok/sTTFT p50ITL p50
1k → 5121952850.50 s12.9 ms
1k → 51283731,1190.56 s18.9 ms
1k → 512327992,3980.54 s25.0 ms
1k → 512641,2763,8290.98 s28.9 ms
1k → 2k642,4963,7441.02 s30.8 ms
32k → 256812816,5523.56 s20.0 ms
32k → 2563230839,7433.88 s29.6 ms
32k → 2566436647,1894.52 s39.9 ms

10 · STARTUPWhere a 14-minute cold start goes

8×B200 · from process start to the first token · one scaleseconds
vLLM cold start processes and engine init: 42 s weights: 572 GB, 68 GiB per GPU: 77 s 77 torch.compile: 122 s 122 profiling run, MTP head: 48 s Triton JIT warmup, 156 kernels: 57 s 57 DeepGEMM JIT, 2,883 MoE kernels: 397 s 397 FlashInfer autotune: 99 s 99 CUDA graphs, API server: 12 s 854 s warmctl up container, file trees: 6.5 s CRIU restore: 9.3 s CUDA state, 8 GPUs in parallel: 11.4 s shared GPU memory: 0.8 s weights reload, 546 GiB: 18.1 s canary: 1.1 s 47.2 s
vLLM cold startprocesses and engine init · 42 sweights: 572 GB, 68 GiB per GPU · 77 storch.compile · 122 sprofiling run, MTP head · 48 sTriton JIT warmup, 156 kernels · 57 sDeepGEMM JIT, 2,883 MoE kernels · 397 sFlashInfer autotune · 99 sCUDA graphs, API server · 12 s
warmctl upcontainer, file trees · 6.5 sCRIU restore · 9.3 sCUDA state, 8 GPUs in parallel · 11.4 sshared GPU memory · 0.8 sweights reload, 546 GiB · 18.1 scanary · 1.1 s

vLLM’s own log of the build shows where 854 s go before the first token. Loading 572 GB of weights takes 77 s. Compilation takes most of the rest: torch.compile 122 s, a Triton JIT warmup of 156 kernels 57 s, FlashInfer autotuning 99 s, and the largest item, 397 s of DeepGEMM compiling 2,883 FP8 MoE kernels for every shape the engine will run. Every restart, scale-out and rollout of every node pays it again.

warmctl runs that once, then snapshots the warm engine: the process memory of all eight ranks (CRIU), the CUDA state of every GPU (cuda-checkpoint), the compiled kernels and CUDA graphs, and the weights as the engine laid them out, 647 GiB in all. warmctl up restores it in 47.2 s from page cache: 16 s to bring the processes back, 11 s for GPU state, 18 s to reload 546 GiB of weights, then a canary token compared bit for bit with the original engine before the port opens. With a cold page cache on this VM’s network disk the same restore took 382 s, bound by reading 643 GiB at 2 GB/s; local NVMe or a fast shared filesystem gets close to the warm number, as our GLM-5.3-Flash benchmark showed with a share read at 7 GiB/s per node.

The snapshot is in the warmctl catalog. On an 8×B200 host with an NVIDIA 580 driver:

$ curl -fsSL https://warmctl.io/install.sh | sh
$ warmctl up ling31-flash

up pulls the snapshot for the host’s GPUs and driver and serves an OpenAI-compatible API on port 8000, with reasoning and tool calls enabled:

$ curl -s localhost:8000/v1/chat/completions -H 'Content-Type: application/json' -d '{
    "model": "ling31-flash", "temperature": 0, "chat_template_kwargs": {"enable_thinking": false},
    "messages": [{"role": "user", "content": "What is the capital of France? One word."}]}' | jq -r '.choices[0].message.content'
Paris

The profile in the repository holds the vLLM flags, the warmup grid and the canary policy.