// serving
LLM Serving Concurrency Calculator
How many concurrent requests a GPU can serve — from the VRAM left after the weights, divided by the KV cache per request.
Max concurrent requests
113seqs
KV cache per request
0.5GB
Aggregate throughput
4,665tok/s
free after weights = 56.6 GB ÷ 0.5 GB/seq = 113 concurrent sequences
Single-stream decode: 95 tok/s. Batching many requests amortizes the weight reads, so aggregate throughput climbs above that — at the cost of KV-cache memory and per-request latency.
Presets verified 2026-09. Models a vLLM-style server: weights load once, remaining VRAM becomes a KV-cache pool shared by all in-flight requests. The concurrency number is memory-limited; real throughput also depends on the scheduler, chunked prefill, and whether requests actually use their full context. Aggregate throughput here is a rough sub-linear estimate, not a benchmark.
The calculation
free VRAM = total VRAM − weights − framework/activation reserve
KV per request = context × 2 × layers × kv_heads × head_dim × bytes
max concurrent = free VRAM ÷ KV per request
The weights load once regardless of load. Everything after that is the KV-cache pool, and it is shared by every request currently generating.
Reading the result
- Max concurrent requests — how many sequences of the chosen context length fit in the pool at once. Treat it as a worst case: real traffic has mixed, mostly-shorter contexts, so a paged server handles more.
- KV cache per request — the pool cost of one sequence. If this is large, either shorten the served context, quantize the KV cache, or pick a model with stronger grouped-query attention.
- Aggregate throughput — a rough sub-linear estimate of the server’s total tokens per second once batching kicks in. Not a benchmark.
Worked example
Llama 3.1 8B at fp16 on one A100 80GB, 4k served context, fp16 KV:
- Weights ≈ 16 GB. Reserve ≈ 2 GB. Free ≈ 55 GB (after vLLM’s ~8% headroom).
- KV per request: 4096 × 2 × 32 × 8 × 128 × 2 ≈ 0.5 GB.
- Max concurrent ≈ 55 ÷ 0.5 ≈ 110 requests.
- Halve it with an fp8 KV cache? Roughly 220.
Notes
Presets carry a verified date. This models a paged-attention server; throughput also depends on the scheduler, chunked prefill, speculative decoding and how bursty your traffic is.
- How does a server like vLLM decide how many requests it can run at once?
- It loads the weights once, reserves a little for activations and framework, and turns the rest of VRAM into a KV-cache pool. Each in-flight sequence draws from that pool in proportion to its context length. When the pool is full, new requests wait in a queue. So concurrency is set by free VRAM divided by KV cache per request.
- Why does aggregate throughput go up with batching but per-request speed does not?
- Generating one token requires reading the model weights from memory. If eight requests generate their next token together, that single weight read serves all eight — the expensive part is amortised. Each individual request still advances at roughly the single-stream rate, but the server's total tokens per second climbs, sub-linearly, until it hits a compute or memory-bandwidth ceiling.
- Does every request really use its full context?
- Rarely. Most requests are far shorter than the max context. Servers use paged KV cache so a 500-token request only occupies 500 tokens' worth of pool, not the maximum. That means real concurrency is usually well above the worst-case number this tool shows for a fixed context.
- Can I fit more requests by quantizing the KV cache?
- Yes. An fp8 or Q8 KV cache halves the per-request cost, roughly doubling concurrency, for a small quality impact. vLLM and TensorRT-LLM both support it.