Neither, in these runs.
Gemma 4 12B, English output going from 256 to 349 tokens (two repetitions each): mean TPOT +1.8% (27.38 โ 27.86 ms), median +1.2%, p99 unchanged (29.39 ms in both). The vLLM benchmark saved mean, median and p99, not p90.
Wall time does not stretch either. Slot occupancy (sum of request latencies รท (duration ร 256)) is 0.992 and 0.995, and the run's duration grows ร1.357 against ร1.362 for the mean request.
Every request has exactly N output tokens, so the mean request takes TTFT + (N โ 1) ร mean TPOT, and throughput follows from that and occupancy. This reproduces the measured throughput ratio to three decimals for all four models. Per output token the time is TTFT/N + TPOT ร (N โ 1)/N, and only the first term shrinks with longer outputs. Its size is what separates the models: at 256 tokens TTFT is 15.7% of a Ministral request (919 ms against a 19.3 ms TPOT), 11.0% for Qwen3.8, 8.9% for Turkish-Gemma and 7.4% for Gemma 4 (559 ms against 27.4 ms).
Change in time per output token, 256 tokens โ scaled length, from the TTFT term and the TPOT term:
- Ministral 3 14B: โ5.1% and โ0.8%
- Qwen3.8-27B: โ3.2% and โ3.0%
- Turkish-Gemma-9b-T1: โ3.3% and +4.3%
- Gemma 4 12B: โ1.8% and +1.7%
So the 5.6-point gap to Ministral splits into 3.2 points of prefill share, which Gemma 4 has less of to dilute, and 2.6 points of mean TPOT; occupancy moves it back by 0.2.
Why Gemma 4's TPOT rises less than Turkish-Gemma's at about the same KV per token (+0.48 ms against +0.95 ms mean TPOT) I have not isolated. One difference in the server logs: Gemma 4 ran on vLLM's TRITON_FLASH_ATTN backend with FlashAttention 4, Turkish-Gemma and Ministral on FLASH_ATTN with FlashAttention 3.
The runs kept per-request end-to-end latencies but not per-request TTFT and TPOT, so the TTFT share above is a mean over 4,096 requests per run, not a distribution. The script is projects/tr-serve/padded_tails.py in the GitHub repository; it reads the same raw files.