Online FP8 quantization in vLLM on an RTX 5090: when should you use it? — Qwen3-8B measured head to head
on this page
Introduction
In our three-way LLM serving benchmark, we compared vLLM, LMDeploy and Ollama. This time, we stayed on vLLM and pitted BF16 against online FP8 quantization. Rather than taking the conventional wisdom that “FP8 is faster” at face value, we checked it on a gcube RTX 5090 container and confirmed the results were reproducible across two independent runs.
The bottom line first: FP8 isn’t always faster. With few concurrent requests, its time per output token (TPOT) is actually worse than BF16’s. FP8’s real advantage — more room for the KV cache — only shows up once concurrency climbs.
Why we ran this experiment
Our earlier attempt at online FP8 quantization (Gemma 3 27B, 58 GB in BF16) failed with an OOM on a 32 GB GPU. The cause is simple. vLLM’s online FP8 conversion needs the original BF16 layers and the converted FP8 layers to sit in VRAM at the same time for a moment, so it gets risky once the model takes up more than 60% of GPU memory.
With that lesson in mind, we scaled down to Qwen3-8B (16 GB in BF16) and compared BF16 and FP8 head to head under identical conditions.
Environment
| Item | Value |
|---|---|
| GPU | RTX 5090 32 GB (gcube container) |
| Model | Qwen/Qwen3-8B |
| vLLM | 0.16.1 (dev) |
| Quantization | quantization='fp8' (online, dynamic) |
| Execution mode | enforce_eager=True |
Practical tip: With this vLLM version, loading online FP8 without
enforce_eager=TruemakesVLLM_COMPILEmode initialization run until it times out and dies. This option matters more than compile-time optimizations.
1. VRAM and memory footprint
| Item | BF16 | FP8 (online) | Difference |
|---|---|---|---|
| Weights alone | ~15.3 GiB | 8.8 GiB | −42% |
| Total VRAM usage | 27.82 GiB | 28.18 GiB | About the same (same gpu_memory_utilization=0.85 cap) |
| GPU KV cache capacity | 71,696 tokens | 118,784 tokens | +66% |
| Max concurrency (at 4,096 tokens per request) | 17.5x | 29.0x | +66% |
Total VRAM usage is almost the same, because as long as there’s a gpu_memory_utilization cap, the KV cache fills whatever memory is left. FP8’s real effect is that the KV cache grows by as much as the model shrinks — in other words, you gain headroom to handle more requests at once.
2. Throughput benchmark — the winner flips with concurrency
We ran vllm bench serve at concurrency 8, 32 and 64, with 128 input and 128 output tokens. (At concurrency 8, we sent warm-up requests first and then measured, to avoid cold-start distortion.)
| Concurrency | Metric | BF16 | FP8 | FP8 vs BF16 |
|---|---|---|---|---|
| 8 | Throughput (tok/s) | ~625 | ~464 | ❌ −26% |
| TTFT (ms) | ~58 | ~48 | ✅ −17% | |
| TPOT (ms) | ~12.4 | ~17.0 | ❌ +37% | |
| 32 | Throughput (tok/s) | ~1,711 | ~1,718 | About the same |
| TTFT (ms) | ~222 | ~135 | ✅ −39% | |
| TPOT (ms) | ~17.1 | ~17.6 | About the same | |
| 64 | Throughput (tok/s) | ~3,058 | ~3,176 | ✅ +4% |
| TTFT (ms) | ~240 | ~170 | ✅ −30% | |
| TPOT (ms) | ~19.1 | ~18.9 | About the same |
The pattern is clear.
- FP8 always wins on TTFT. The weights are smaller, so the load and compute path is shorter.
- At concurrency 8, FP8 clearly loses on TPOT (per-token generation speed). With small batches, the dequantization overhead of the FP8 kernels outweighs any throughput gain.
- From concurrency 32 the gap disappears, and at 64 FP8 starts to pull ahead on throughput too. The larger KV cache lets it run bigger batches.
We reproduced these results in two independent runs on a gcube RTX 5090. The VRAM and KV cache figures matched exactly, throughput was within 1%, and TTFT/TPOT were within 4%. The pattern of FP8 losing at low concurrency appeared in both runs — it’s not a fluke but a real characteristic of vLLM’s CUTLASS FP8 kernels.
3. Quality — does it really drop?
We sent seven prompts (code generation, math, Korean marketing copy, a haiku and more) to both BF16 and FP8 at temperature 0 and compared the outputs.
- The outputs weren’t 100% identical token for token (expected with quantization), but the reasoning and final answers were logically consistent.
- The only place the wording diverged was creative prompts that vary a lot anyway, such as marketing copy, and even there it’s hard to say quantization was the cause.
Conclusion — when to use FP8
| Situation | Recommendation |
|---|---|
| Low traffic (fewer than 10 concurrent requests) and latency matters | Stay on BF16 (avoid the TPOT penalty), or use FP8 if only TTFT matters |
| High traffic (30+ concurrent requests) and throughput matters | FP8 — the extra KV cache headroom wins on both throughput and TTFT |
| GPU memory is tight and you need bigger batches | FP8 — half the weights, much more room for batching |
| The model takes up 60%+ of GPU memory (e.g. a 20 GB+ model on a 32 GB GPU) | Consider offline pre-quantization (llm-compressor) instead of online FP8 — OOM risk |
Online FP8 quantization isn’t a switch that “makes everything faster once you turn it on.” It’s an optimization you decide on based on your real traffic pattern (concurrency).
All figures in this post were measured on a gcube RTX 5090 container, and we repeated the same procedure in a separate container to verify reproducibility.