FP8 Cut Our TPOT by 25%. At High Concurrency, It Also Changed the Answers.

Quantization is usually sold as a free lunch: same quality, less memory, faster decoding. We wanted to check that claim before recommending FP8 anywhere, so we benchmarked it the way it actually ships — the real service, under real concurrency — instead of a single offline pass. Setup We served Qwen2.5-7B-Instruct on an H100 with vLLM 0.31.0, comparing bf16 against online FP8, a calibrated FP8 checkpoint, and AWQ across a concurrency sweep. Every comparison went through the same gates we use for engine upgrades: latency split into TTFT vs. TPOT, output-quality checks with significance testing, and cost converted to dollars per 1M tokens. What we found FP8 did what it promises on latency: TPOT dropped 23–26%. −23 to −26% time per output token, FP8 vs. bf16 97.6% → 75% self-consistency at 64 concurrent requests, bf16 vs. FP8 65 / 70 FP8 outputs that changed with batch size, vs. 35 / 70 for bf16 What it also did was less comfortable. At 64 concurrent requests,

FP8 Cut Our TPOT by 25%. At High Concurrency, It Also Changed the Answers.

Quantization is usually sold as a free lunch: same quality, less memory, faster decoding. We wanted to check that claim before recommending FP8 anywhere, so we benchmarked it the way it actually ships — the real service, under real concurrency — instead of a single offline pass.

Setup

We served Qwen2.5-7B-Instruct on an H100 with vLLM 0.31.0, comparing bf16 against online FP8, a calibrated FP8 checkpoint, and AWQ across a concurrency sweep. Every comparison went through the same gates we use for engine upgrades: latency split into TTFT vs. TPOT, output-quality checks with significance testing, and cost converted to dollars per 1M tokens.

What we found

FP8 did what it promises on latency: TPOT dropped 23–26%.

−23 to −26%
time per output token, FP8 vs. bf16

97.6% → 75%
self-consistency at 64 concurrent requests, bf16 vs. FP8

65 / 70
FP8 outputs that changed with batch size, vs. 35 / 70 for bf16

What it also did was less comfortable. At 64 concurrent requests, self-consistency — how often the service gives the same answer to the same prompt — fell from 97.6% under bf16 to about 75% under FP8.

To find out why, we ran the same prompts at batch sizes from 1 to 128. Rerunning an input at the same batch size gave identical output on both precisions, so the engine itself is deterministic. Changing the batch size is what changed the text: FP8's output changed in 65 of 70 cases, with the first differing token at a median of 19. bf16 changed too, in 35 of 70 cases, but much later, at a median of token 77. Some batch dependence is normal; FP8 nearly doubled it and moved it much earlier in the answer.

BATCH-SIZE PROBE SAME INPUT, RERUN DIFFERENT BATCH SIZE MEDIAN FIRST DIFFERING TOKEN
bf16 identical 35 / 70 changed 77
FP8 identical 65 / 70 changed 19

In other words, FP8 doesn't just make decoding faster. Under load, its answers depend on how busy the server is: cheaper per token, but measurably less consistent with itself.

Why this matters

If you only watch latency, FP8 looks like an obvious win. If you watch latency, quality, and cost together, it's a tradeoff with a real price tag: lower cost per 1M tokens, paid for in output stability. That's exactly the kind of tradeoff that should be decided with data, not with a benchmark table from a launch post.

What this doesn't prove

These numbers are from one model, our prompts, and our serving setup. Quantization behavior varies by model family, and some of our capacity numbers were measured only once. Where the tokens still matched, FP8's next-token distribution barely moved, and its quality drop on our prompt set was too small to be statistically significant. We publish the methodology and the limitations alongside the results because a benchmark you can't reproduce is marketing, not evidence.

What we'd do instead

Gate quantization changes the same way you'd gate an engine upgrade: run the real service against a committed baseline in CI, require statistical significance before calling anything a regression (noise gets marked inconclusive, not regressed), and check quality at the concurrency you actually serve — not at batch size 1.

See it on your own model

Browse the verdicts from these runs in the read-only demo, no account needed. Or run a pilot: we measure your next quantization or engine change on your own service and prompts.

Explore the live demo

Request a pilot

Share