t0 送出 request
│── transport + queue + Prefill + first decode ──│ t1 收到第一個 token
│── gap 1 ──│ t2
│── gap 2 ──│ t3 ... 完成
| Metric | 怎麼算 | 回答什麼問題 |
|---|---|---|
| TTFT | t1 - t0 |
使用者等多久才看到第一個輸出? |
| ITL | 相鄰兩次 streamed outputs 的時間差 | 輸出過程會不會停頓? |
| TPOT | (E2E - TTFT) / (output tokens - 1) |
一條 request 在首 token 後,平均每個 token 花多久? |
| E2E latency | t_end - t0 |
整條回答多久完成? |
例如一條 request 共輸出 4 tokens,第一個 token 在 120 ms 到達,後面三段間隔是 30、40、40 ms:
TTFT = 120 ms
ITL samples = [30, 40, 40] ms
TPOT = (230 - 120) / 3 = 36.7 ms/token
E2E = 230 ms
vLLM 的 serving benchmark 從 client 端量測:TTFT 是送出 request 到收到第一個 streamed output。一般 decoding 每次通常輸出一個 token,因此 ITL 和 TPOT 很接近;但 speculative decoding 可能一次送出多個 tokens,ITL 記的是兩次串流事件的間隔,TPOT 才會把這段時間攤到所有 output tokens 上。
另外,vLLM 會把所有成功 requests 的 ITL samples 合在一起統計;TPOT 則是先替每條 request 算一個值,再跨 requests 統計。即使名稱相近,樣本單位也不同。
| Metric | 計算方式 | 容易誤解的地方 |
|---|---|---|
| Request throughput | 完成 requests / 秒 | output length 不同時不能直接比較 |
| Output throughput | 生成 tokens / 秒 | 常用來看 Decode 產能,但分子不含 prompt tokens |
| Total token throughput | (input + output) tokens / 秒 |
Prefill-heavy workload 會讓數字看起來很高 |
| Goodput | 在 latency SLO 內完成的 requests / 秒 | 必須同時寫出 TTFT/TPOT/E2E 門檻 |
例如 server 每秒完成很多短回答,request throughput 會很高;換成每條輸出 512 tokens 後,即使 GPU 沒變,requests/s 也會下降。所以 throughput 永遠要和 input、output length distribution 一起讀。
真正有用的結果通常不是「最高 tokens/s」,而是:
在 P99 TTFT 與 P99 TPOT 仍符合目標時,系統最多能承受多少流量?
max_concurrency = 32 表示同時 outstanding 的 requests 最多 32 條;它描述的是系統內同時有多少工作。
request_rate = 10 RPS 表示平均每秒產生 10 條 requests;它描述的是外部流量如何抵達。某些 requests 尚未完成時,實際 concurrency 仍可能持續上升。
因此我會分成兩種測試:
| 測試 | 固定方式 | 用途 |
|---|---|---|
| Saturation sweep | request_rate = inf,逐步提高 max concurrency |
找最大 throughput 與 latency 轉折點 |
| Arrival-rate sweep | 固定流量分布,逐步提高 RPS | 找 production-like traffic 何時開始排隊 |
不能拿 concurrency 32 的結果,直接和 32 RPS 當成同一組負載。
Model:名稱、revision、tokenizer、chat template
Runtime:framework commit、dtype/quantization、TP/PP、backend、主要 flags
Hardware:GPU 型號與數量、CPU、driver、CUDA
Workload:request 數、input/output token 分布、prefix reuse、sampling、是否 ignore EOS
Traffic:request rate、burstiness、max concurrency
Procedure:warm-up、重複次數、成功/失敗數、量測區間
尤其不要只寫「平均 input 512、output 128」。兩組 workload 即使平均相同,長尾分布不同,也可能產生完全不同的 P99 latency 與 KV Cache 壓力。
正式測量前也要先 warm up,避免把模型載入、kernel compilation 或 CUDA Graph capture 的一次性成本混進 steady-state 結果;原始的 per-request latency 與實際 token counts 也應保留,不能只留下平均值。
| 欄位 | 值 |
|---|---|
| Environment | model revision、framework commit、GPU、dtype、parallelism |
| Workload | request 數、input/output length distribution、prefix reuse |
| Traffic | request rate、burstiness、max concurrency |
| Result validity | completed、failed、duration |
| Latency | P50/P99 TTFT、TPOT、ITL、E2E |
| Capacity | req/s、output tok/s、total tok/s、goodput |
| Memory | peak GPU memory、KV Cache capacity |
每個設定至少重跑三次;表格填 median run,另外保留各次結果與 raw per-request data。若 latency 已超過 SLO,即使 throughput 繼續上升,也不把它叫作可服務容量。
Benchmark 不是找一個最大的數字,而是畫出 load 增加時,latency 如何惡化、goodput 在哪裡停止成長。