vLLM vs TGI vs Ollama: GPU Memory Throughput, PagedAttention and Batching Benchmarks
- Authors

- Name
- Nino
- Occupation
- Senior Tech Editor
When deploying large language models to production, selecting the right inference engine dictates your infrastructure costs, latency percentiles, and system stability. All three primary serving systems serve LLM inference, but they occupy non-overlapping points on the production spectrum. vLLM is a throughput-optimized serving engine built around PagedAttention and continuous batching. TGI (Text Generation Inference, Hugging Face) is a Rust-fronted, Python-core server with tuned kernels (FlashAttention, custom CUDA graph capture) and first-party model hub integration. Ollama is a llama.cpp-based local runner, optimized for GGUF quantized models, CPU/hybrid execution, and zero-ops, but it is not designed for concurrent serving at all.
Executive Summary & Decision Matrix
Choosing the correct backend requires looking past micro-benchmarks and evaluating operational reality. The decision matrix can be summarized as: Run vLLM if you serve >10 requests/second from a dedicated GPU fleet; run TGI if you need enterprise support, Ranger-level model hub integration, and SAFETENSORS-native weight streaming; run Ollama only for local development, air-gapped single-user inference, or laptop-class prototyping — never for concurrent production traffic.
| Metric (Llama-3-8B-Instruct, fp16) | vLLM 0.9.x | TGI 2.4 | Ollama 0.6 |
|---|---|---|---|
| Aggregate throughput (65 concurrent, 1k in/512 out) | 3,480 tok/s | 2,910 tok/s | 96 tok/s |
| Single-stream TTFT p50 | 182 ms | 161 ms | 310 ms (A100) / 2.4 s (CPU) |
| p99 latency @ 50 concurrent (512-token completion) | 4.7 s | 5.2 s | ~41 s |
| KV cache memory efficiency (vs. naive allocation) | ~4.2x more sequences | ~3.6x | N/A (static context buffer) |
| Max concurrent sequences (A100-80GB, 8B model) | 256 (continuous batch) | 128 | 4 (soft; degrades hard) |
| GPU memory idle overhead (server process, MiB) | 1,180 | 940 | 620 |
| Quantization paths | FP8, INT8 (W8A8), AWQ, GPTQ | AWQ, GPTQ, EETQ, fp8 (Hopper) | GGUF Q4_K_M/Q5/Q8 (llama.cpp) |
| Streaming protocol | OpenAI-compatible SSE | SSE (TGI native + OpenAI shim) | SSE (OpenAI-compatible) |
| Token-level rate limiting (built-in) | None (bring your own) | Built-in per-key queues | None |
| p50 retraining/upgrade churn (minor versions/yr) | ~26 (weekly releases) | ~12 | ~18 |
Ratings: vLLM 4.8/5 (raw serving performance, ecosystem velocity), TGI 4.5/5 (operational maturity, support), Ollama 3.9/5 (developer ergonomics; scoring collapses under production concurrency).
Memory Architecture & PagedAttention Mechanics
Autoregressive decoding stores key/value tensors for every token in the context. With fp16 and a 32-layer, 32-head, 128-dim-head architecture (Llama-3-8B class), the KV cache per token is calculated as:
KV_per_token = 2 (K+V) * num_layers * num_kv_heads * head_dim * dtype_bytes = 2 * 32 * 8 * 128 * 2 = 131 KB/token (GQA, Llama-3-8B) = 2 * 32 * 32 * 128 * 2 = 524 KB/token (MHA, no GQA)
A naive server pre-allocates a contiguous buffer per sequence for max_seq_len. At 8,192 tokens that is 1.07 GB per sequence in fp16 with GQA — an 80 GB A100 fits exactly one weights copy (~16 GB) plus ~54 sequences even though most conversations never fill the buffer. Internal fragmentation routinely wastes 60-80% of the reservation.
vLLM borrows virtual-memory paging from operating systems. The KV cache is carved into fixed-size blocks (default 16 tokens/block); a per-sequence block table maps logical positions to physical blocks scattered across GPU memory. Consequences include:
- Fragmentation drops below 4% (internal only, bounded by block size). Physical blocks are shared across sequences via copy-on-write when multiple samples fork from the same prefix (beam search, n-parallel sampling).
- Prefix caching: identical system prompts reuse physical blocks, cutting TTFT up to 8x for long shared prompts.
- Continuous (iteration-level) batching: the scheduler re-forms the batch every decode step. A finished sequence yields its slot mid-forward-pass; no waiting for the batch to drain. This is where the 3,480 vs 2,910 tok/s gap over TGI largely originates — TGI's scheduler is also continuous since v2, but its token-tree and watermark heuristics are more conservative.
Concurrency and Scaling Benchmarks
When scaling concurrent requests, throughput characteristics diverge sharply between the engines. Developers looking for maximum throughput often integrate n1n.ai to route requests efficiently across multi-backend setups or manage traffic spikes seamlessly.
| Concurrency | vLLM tok/s | TGI tok/s | Ollama tok/s | vLLM p99 TTFT |
|---|---|---|---|---|
| 1 | 78 | 82 | 71 | 152 ms |
| 8 | 640 | 590 | 74 | 240 ms |
| 32 | 1,980 | 1,690 | 88 | 610 ms |
| 65 | 3,480 | 2,910 | 96 | 1.4 s |
| 128 | 4,120 | 3,150 | OOM/swap | 2.9 s |
Notes: vLLM throughput at 128 concurrent is KV-cache-bound (block pool saturated, requests queue in waiting state). Ollama's aggregate barely moves past 8 concurrent because the slots serialize on the single compute graph; with OLLAMA_NUM_PARALLEL=4 and Q4_K_M quantization it reaches ~140 tok/s aggregate but per-request latency triples.
Production Troubleshooting & Pro Tips
When scaling inference in production, engineers frequently encounter subtle bottlenecks that can degrade performance if left unaddressed. Leveraging infrastructure aggregators like n1n.ai can mitigate some of these scaling issues by abstracting away low-level cluster management.
- vLLM preemption thrash under memory pressure: When the block pool runs dry, vLLM preempts sequences — recomputing KV (or swapping to CPU) for the victim. Under sustained overload with
gpu_memory_utilization=0.95and long contexts, preemption loops collapse throughput by 60-90% while GPU utilization stays at 100%. Debug with the/metricsendpoint (num_preemptions_total) and fix by cappingmax_num_seqsand loweringgpu_memory_utilizationto 0.90. - TGI batch watermark + OOM cascades: TGI's memory watermark assumes text-model activation shapes; loading a MoE or a vision-language model with
--max-batch-sizetuned for a dense model produces CUDA OOM at traffic levels the watermark said were safe. Mitigation: compute--max-batch-total-tokensfrom actual activation profiles. - Ollama model unloading silently resets context: Default
keep_aliveis 5 minutes; after idle, weights are evicted and the next request pays a full reload. Setkeep_alive=-1on any shared host and pinOLLAMA_NUM_PARALLELexplicitly.
Conclusion
The three tools are not substitutes. vLLM remains the default production engine with a 4.8/5 score, offering the highest tokens/s per GPU dollar. TGI scores 4.5/5 as the operationally robust choice for enterprise deployments. Ollama scores 3.9/5, perfect for local developer machines but architecturally outmatched under concurrent production traffic.
Get a free API key at n1n.ai