GPU Sizing for Concurrent Users
Concurrent requests, context length and a target token rate into a GPU count — with the memory limit and the bandwidth limit computed separately so you can see which one binds.
65 concurrent sequences per GPU, limited by memory. At that batch each stream runs at about 27.6 tok/s.
- Weights on every GPU
- 7.45 GB
- KV cache per token
- 128.0 KB
- KV cache per sequence
- 0.98 GB
- Memory-bound seats per GPU
- 65
- Bandwidth-bound seats per GPU
- 92
- Binding constraint
- memory
- Seats per GPU
- 65
- Per-stream rate at that batch
- 27.6 tok/s
- Aggregate output per GPU
- 1792 tok/s
- GPUs for the stated peak
- 1
Two limits, and the one that binds is not always memory
memory: (W + B·K) × (1 + overhead) ≤ VRAM
speed: bandwidth ÷ (W + B·K) ≥ target tokens/s
Batching an LLM server is unusually forgiving in one respect: a decode step reads the weights once no matter how many sequences are in the batch, so the second concurrent user is nearly free in bandwidth terms. That is why continuous batching works at all. What is not free is each sequence’s KV cache, which must be both stored and re-read every single step. Both limits above are the same expression — weights plus batch times cache — measured once against capacity and once against time.
Reading which one binds is the useful output. If memory binds, you are leaving speed on the table and the fixes are memory fixes: quantise the KV cache, cap the context, or take a card with more VRAM. If bandwidth binds you have spare memory you cannot use, and the fix is a smaller or more heavily quantised model, or accepting a lower per-user rate. A target of twenty tokens a second is already faster than most people read; halving it can double the seats per GPU.
One failure mode has no fix through scale. If a single sequence cannot hit the target rate, more GPUs will not help — every one of them is the same speed, and per-user latency is a property of one GPU’s bandwidth against one model’s weights. Adding hardware buys throughput, never latency.