ai newsSa., 17. Okt.

Your GPU Benchmark Is Lying: Measuring LLM Inference Under Thermal Throttling the Right Way

Tuần này trên Dev.to có một bài khá thú vị: Gemma 4 decode trên cloud T4 chậm đi khoảng 7% khi card nóng lên. Đọc xong mình nhớ lại chuyện team mình từng gặp. Bọn mình benchmark một model 8B trên con GPU thuê theo giờ, chạy 30 giây thì được 42 tokens/s. Dựa vào con số đó, team tính capacity cho pro

dev.toSamstag 03:24 · 17.10.6 Min. Lesezeit
Bild: dev.to

Tuần này trên Dev.to có một bài khá thú vị: Gemma 4 decode trên cloud T4 chậm đi khoảng 7% khi card nóng lên. Đọc xong mình nhớ lại chuyện team mình từng gặp. Bọn mình benchmark một model 8B trên con GPU thuê theo giờ, chạy 30 giây thì được 42 tokens/s. Dựa vào con số đó, team tính capacity cho production. Lên production, chạy liên tục cả ngày thì throughput thực tế chỉ còn khoảng 37–38 tokens/s, và hệ thống thiếu capacity gần 10%. Lỗi không nằm ở model hay ở llama.cpp. Lỗi nằm ở cách bọn mình đo. Bài này chia sẻ cách mình benchmark LLM inference bây giờ, để con số đo được gần với thực tế khi chạy lâu dài.

GPU hiện đại không chạy ở một xung nhịp cố định. Lấy NVIDIA T4 làm ví dụ: TDP chỉ có 70W, boost clock tối đa 1590 MHz, và card được làm mát thụ động. Card không có quạt riêng mà phụ thuộc vào luồng gió của server. Khi bạn mới bắt đầu chạy, card còn mát, driver đẩy clock lên cao. Sau vài phút, nhiệt độ và công suất chạm ngưỡng, driver bắt đầu hạ clock. Hiện tượng này gọi là throttling.

Với LLM, giai đoạn decode chủ yếu bị giới hạn bởi memory bandwidth, nên clock SM giảm thì tốc độ không giảm tỷ lệ thuận. Giai đoạn prefill thì bị giới hạn bởi compute, nên ảnh hưởng nặng hơn nhiều. Vì vậy, nếu bạn chỉ đo một con số chung chung kiểu "tokens/s" trong 30 giây đầu, bạn đang đo GPU ở trạng thái đẹp nhất. Production thì không bao giờ ở trạng thái đó.

flowchart LR A[Bắt đầu chạy<br/>GPU mát] --> B[Boost clock tối đa] B --> C[Nhiệt độ + công suất tăng] C --> D{Chạm power cap<br/>hoặc thermal limit?} D -- Có --> E[Driver hạ SM clock] E --> F[Steady state<br/>throughput thấp hơn] D -- Không --> B Bước 1: Quan sát GPU trong lúc benchmark Trước khi đo tokens/s, cần biết GPU đang làm gì. nvidia-smi có sẵn chế độ log liên tục. Mở một terminal riêng và chạy:

# Log mỗi giây ra CSV, chạy song song với benchmark nvidia-smi \ --query-gpu = timestamp,temperature.gpu,clocks.sm,clocks.mem,power.draw,power.limit,clocks_throttle_reasons.active \ --format = csv,nounits -l 1 > gpu_log.csv & # Xem chi tiết lý do throttle tại thời điểm hiện tại nvidia-smi -q -d PERFORMANCE # Xem clock tối đa mà card hỗ trợ để so sánh nvidia-smi -q -d CLOCK | grep -A3 "Max Clocks" Enter fullscreen mode Exit fullscreen mode Với driver 535 trở lên, NVIDIA đổi tên trường thành clocks_event_reasons.active. Tên cũ vẫn dùng được trên đa số bản driver, nhưng nếu gặp lỗi Field... is not a valid field thì bạn đổi sang tên mới. Giá trị clocks_throttle_reasons.active là một bitmask. Ví dụ 0x0000000000000004 là SW Power Cap, 0x0000000000000020 là SW Thermal Slowdown.

Khi đọc file gpu_log.csv, mình thường thấy cùng một pattern: phút đầu tiên clocks.sm đứng ở mức 1590, đến phút thứ 3–5 thì tụt dần về 1200–1350 và đứng yên ở đó. Mức đứng yên này mới là con số bạn cần dùng để tính capacity.

llama-bench của llama.cpp tiện để so sánh nhanh, nhưng mặc định chỉ lặp 5 lần ( -r 5 ), mỗi lần rất ngắn. Mình dùng nó theo cách này:

# Warm-up + nhiều lần lặp, xuất JSON để phân tích./llama-bench -m models/gemma-3-4b-it-Q4_K_M.gguf \ -ngl 99 -p 512 -n 256 -r 50 -o json > bench.json Enter fullscreen mode Exit fullscreen mode Cách hiệu quả hơn là bắn request liên tục vào llama-server, đồng thời ghi lại metric của GPU qua NVML. Script dưới đây dùng package nvidia-ml-py ( pip install nvidia-ml-py requests ):

import time, json, statistics, requests import pynvml as nv URL = " http://127.0.0.1:8080/completion " DURATION = 15 * 60 # chạy 15 phút PROMPT = " Giải thích cơ chế B-tree index trong PostgreSQL. " * 20 nv. nvmlInit () h = nv. nvmlDeviceGetHandleByIndex ( 0 ) rows, start = [], time. time () while time. time () - start < DURATION: r = requests. post ( URL, json = { " prompt ": PROMPT, " n_predict ": 256, " cache_prompt ": False }). json () t = r [ " timings " ] rows. append ({ " t ": round ( time. time () - start ), " prefill_tps ": t [ " prompt_per_second " ], " decode_tps ": t [ " predicted_per_second " ], " temp ": nv. nvmlDeviceGetTemperature ( h, nv. NVML_TEMPERATURE_GPU ), " sm_mhz ": nv. nvmlDeviceGetClockInfo ( h, nv.

NVML_CLOCK_SM ), " power_w ": nv. nvmlDeviceGetPowerUsage ( h ) / 1000, " throttle ": hex ( nv. nvmlDeviceGetCurrentClocksThrottleReasons ( h )), }) print ( rows [ - 1 ]) json. dump ( rows, open ( " run.json ", " w " )) def summary ( sub, label ): d = [ x [ " decode_tps " ] for x in sub ] p = [ x [ " prefill_tps " ] for x in sub ] print ( f " { label }: decode median= { statistics. median ( d ):. 1 f } " f " p10= { statistics. quantiles ( d, n = 10 )[ 0 ]:. 1 f } | " f " prefill median= { statistics. median ( p ):.

0 f } " ) summary ([ x for x in rows if x [ " t " ] < 60 ], " Cold (0-60s) " ) summary ([ x for x in rows if x [ " t " ] > DURATION - 300 ], " Steady (5 phút cuối) " ) Enter fullscreen mode Exit fullscreen mode Có ba điểm cần lưu ý trong script:

sequenceDiagram participant S as Bench script participant L as llama-server participant G as GPU (NVML) loop Mỗi request trong 15 phút S->>L: POST /completion (cache_prompt=false) L-->>S: timings (prefill/decode tps) S->>G: Đọc temp, SM clock, power, throttle G-->>S: Metrics S->>S: Ghi 1 dòng time series end S->>S: So sánh cold vs steady (median, p10) Bước 3: Giảm thiệt hại khi đã biết card bị throttle Đo xong rồi thì xử lý thế nào? Mình có vài cách đã thử thực tế:

Thêm một chuyện nữa: trên cloud, hai instance cùng loại T4 có thể cho kết quả chênh nhau vài phần trăm, vì phụ thuộc vào vị trí rack và luồng gió của từng server. Đừng benchmark trên một instance rồi áp con số đó cho cả fleet.

Benchmark LLM mà chỉ chạy 30 giây thì kết quả là con số marketing, không phải con số vận hành. Những việc bạn nên làm ngay:

GPU không nói dối, nó chỉ trả lời đúng câu hỏi bạn đặt ra. Nếu muốn biết hiệu năng khi chạy cả ngày, hãy đo trong điều kiện chạy cả ngày.

Quelle: dev.to (dev.to). Original öffnen