yafeiaa Blogs

vLLM 推理性能深度分析:阶梯并发实验、Roofline 模型与调度瓶颈验证

环境:AutoDL | 2×RTX 4080 | Qwen/Qwen2.5-7B-Instruct 涵盖 TP=1 与 TP=2 两组阶梯并发实验,以及调度瓶颈深度分析


一、实验环境与基础配置

1.1 服务启动(TP=2)

vllm serve /root/autodl-tmp/models/Qwen/Qwen2.5-7B-Instruct --tensor-parallel-size 2

显存状态(冷启动后)

GPU 0: 30356MiB / 32760MiB  —  VLLM::Worker_TP0
GPU 1: 30356MiB / 32760MiB  —  VLLM::Worker_TP1
功耗:GPU0 37W / GPU1 39W(冷启动空载,P2 状态)

1.2 统一压测参数

所有压测使用相同的参数口径:

./vllm-bench --backend vllm --base-url http://127.0.0.1:8000 \
  --model /root/autodl-tmp/models/Qwen/Qwen2.5-7B-Instruct \
  --dataset-name random \
  --random-input-len 1024 --random-output-len 128 \
  --num-prompts 1000 --max-concurrency 200
参数
数据集 random
Input length 1024
Output length 128
Prompt 数 1000(基线)/ 300~500(阶梯实验)
最大并发 1~200 阶梯递增

1.3 GPU 裸算力基线(并发=1)

将并发度调为 1,消除 prefill 与 decode 的互相抢占,得到 GPU 纯算力基线。

TP=1 基线(单卡)

./vllm-bench --backend vllm --base-url http://127.0.0.1:8000 \
  --model /root/autodl-tmp/models/Qwen/Qwen2.5-7B-Instruct \
  --dataset-name random \
  --random-input-len 1024 --random-output-len 128 \
  --num-prompts 1000 --max-concurrency 1
指标 说明
TPOT (ITL) 25ms GPU 裸算力:单请求独占 GPU 的 decode 耗时
TTFT 250ms GPU 裸算力:prefill 1024 tokens 的耗时

Prefill & Decode Time — conc=1 TTFT & TPOT — conc=1

TP=2 基线(双卡)

指标 说明
TPOT (ITL) 12.07ms 双卡裸算力,约为 TP=1 的 48%
TTFT 62.17ms 双卡裸算力,约为 TP=1 的 25%
E2EL 1595ms 符合公式 62 + 127×12.07 ≈ 1595ms

TPOT 增量对比

场景 Mean TPOT TPOT 增量 占比
TP=1 并发=1(裸算力) 25ms
TP=2 并发=1(裸算力) 12ms
TP=2 并发=200 热 222ms 210ms 95%
TP=2 并发=200 冷 255ms 243ms 95%

TPOT 增量 = 实际 TPOT − conc=1 裸算力 TPOT。注意:高并发下 decode step 同时处理多个 token(GEMM),FLOPs 远高于 conc=1 的 GEMV 操作。因此 TPOT 增量中同时包含了合法计算增长调度/同步开销,不应全部归为"空闲时间"。


二、TP=2 冷启动 vs 热启动

首次发现:冷启动后第一次压测的吞吐明显低于紧接着的第二次,差异约 13%。

2.1 整体概览

指标 第一次(冷启动) 第二次(热) 变化
Benchmark 耗时 184.06s 162.91s -11.5%
Total Token 吞吐 6247 tok/s 7058 tok/s +13.0%
Request 吞吐 5.43 req/s 6.14 req/s +13.1%
Output Token 吞吐 695 tok/s 786 tok/s +13.0%

2.2 延迟指标

指标 第一次 第二次 变化
Mean TTFT 4105ms 4076ms ≈ 无差异
P99 TTFT 28579ms 22938ms -19.7%
Mean TPOT 255ms 222ms -12.9%
Median TPOT 282ms 222ms -21.3%
Mean E2EL 36520ms 32294ms -11.6%
P99 E2EL 62661ms 47541ms -24.1%
Median E2EL 37314ms 33904ms -9.1%

2.3 Steady-State 对比

指标 第一次 第二次 变化
Mean TTFT 1888ms 2169ms +14.9%↑
Mean TPOT 254ms 228ms -10.2%
Request 吞吐 4.48 req/s 5.08 req/s +13.4%
Output Token 吞吐 653 tok/s 739 tok/s +13.2%

2.4 实验结论

现象总结

观察 说明
E2E 延迟第二次降低 ~12% 热请求比冷请求整体更快完成
TPOT 降低 ~13% 每次 decode step 效率更高
Token 吞吐提升 ~13% 单位时间处理更多 token
num_requests_waiting 降低 排队请求减少,调度更高效
TTFT 无明显差异 冷启动不影响首 token 生成速度
GPU 利用率一致 瓶颈不在 GPU 计算,在 CPU 调度侧

核心推论

  • Warmup 很重要:第一次压测触发了 scheduler 和 attention 后端的初始化,第二次直接受益
  • 当前瓶颈在 CPU/调度侧:GPU-Util 两次均为 99%,说明 GPU 持续有 kernel 在执行,TPOT 差异来自 scheduler 排队优化(注:GPU-Util 仅表示非空闲,不直接反映 SM 饱和度)
  • 单请求的 TTFT/TPOT 没变,但整体吞吐提升 → 请求之间重叠度更高,空闲时间更少

E2EL 验算公式

E2EL ≈ TTFT + (output_len - 1) × TPOT

第一次: 4105 + 127 × 255 = 36490 ≈ 36520 ✅
第二次: 4076 + 127 × 222 = 32270 ≈ 32294 ✅

2.5 原始日志

================= Serving Benchmark Result =================
Successful requests:                     1000      
Failed requests:                         0         
Maximum request concurrency:             200       
Benchmark duration (s):                  184.06    
Total input tokens:                      1021847   
Total generated tokens:                  128000    
Request throughput (req/s):              5.43      
Output token throughput (tok/s):         695.43    
Peak output token throughput (tok/s):    3683.00   
Peak concurrent requests:                210.00    
Total token throughput (tok/s):          6247.13   
--------------------Time to First Token---------------------
Mean TTFT (ms):                          4105.63   
Median TTFT (ms):                        1316.94   
P99 TTFT (ms):                           28579.09  
P90 TTFT (ms):                           13852.11  
----------Time per Output Token (excl. 1st token)-----------
Mean TPOT (ms):                          255.23    
Median TPOT (ms):                        281.67    
P99 TPOT (ms):                           288.21    
P90 TPOT (ms):                           285.97    
--------------------Inter-token Latency---------------------
Mean ITL (ms):                           255.23    
Median ITL (ms):                         325.15    
P99 ITL (ms):                            335.78    
P90 ITL (ms):                            329.41    
---------------------End-to-end Latency---------------------
Mean E2EL (ms):                          36520.30  
Median E2EL (ms):                        37314.13  
P99 E2EL (ms):                           62661.13  
P90 E2EL (ms):                           47221.33  
============================================================
============ Steady-State Metrics =============
Concurrency threshold:              >= 0.95 * 200 = 190
Window:                             0.1s -> 180.7s  (180.6s)
Observed peak concurrency:          200
Requests started in window:         811 / 1000 (81.1%)
Requests completed in window:       810
-----------------------------------------------
Request throughput (req/s):         4.48
Output token throughput (tok/s):    653.02
Input token throughput (tok/s):     4588.30
Total token throughput (tok/s):     5241.31
-----------------------------------------------
Mean TTFT (ms):                     1888.12
Median TTFT (ms):                   1315.00
P99 TTFT (ms):                      28543.14
P90 TTFT (ms):                      2914.28
-----------------------------------------------
Mean TPOT (ms):                     254.27
Median TPOT (ms):                   282.80
P90 TPOT (ms):                      286.04
P99 TPOT (ms):                      288.31
================= Serving Benchmark Result =================
Successful requests:                     1000      
Failed requests:                         0         
Maximum request concurrency:             200       
Benchmark duration (s):                  162.91    
Total input tokens:                      1021847   
Total generated tokens:                  128000    
Request throughput (req/s):              6.14      
Output token throughput (tok/s):         785.70    
Peak output token throughput (tok/s):    3800.00   
Peak concurrent requests:                217.00    
Total token throughput (tok/s):          7058.06   
--------------------Time to First Token---------------------
Mean TTFT (ms):                          4076.72   
Median TTFT (ms):                        1941.42   
P99 TTFT (ms):                           22938.96  
P90 TTFT (ms):                           13225.27  
----------Time per Output Token (excl. 1st token)-----------
Mean TPOT (ms):                          222.19    
Median TPOT (ms):                        222.21    
P99 TPOT (ms):                           282.03    
P90 TPOT (ms):                           277.71    
--------------------Inter-token Latency---------------------
Mean ITL (ms):                           222.19    
Median ITL (ms):                         318.70    
P99 ITL (ms):                            333.32    
P90 ITL (ms):                            328.38    
---------------------End-to-end Latency---------------------
Mean E2EL (ms):                          32294.56  
Median E2EL (ms):                        33904.32  
P99 E2EL (ms):                           47541.62  
P90 E2EL (ms):                           39384.57  
============================================================
============ Steady-State Metrics =============
Concurrency threshold:              >= 0.95 * 200 = 190
Window:                             0.1s -> 159.6s  (159.5s)
Observed peak concurrency:          200
Requests started in window:         811 / 1000 (81.1%)
Requests completed in window:       810
-----------------------------------------------
Request throughput (req/s):         5.08
Output token throughput (tok/s):    739.41
Input token throughput (tok/s):     5195.51
Total token throughput (tok/s):     5934.91
-----------------------------------------------
Mean TTFT (ms):                     2168.68
Median TTFT (ms):                   1639.29
P99 TTFT (ms):                      22938.77
P90 TTFT (ms):                      3541.12
-----------------------------------------------
Mean TPOT (ms):                     228.32
Median TPOT (ms):                   254.46
P90 TPOT (ms):                      278.01
P99 TPOT (ms):                      282.53

三、Warmup 验证

目标:找到最小成本的预热方式,消除冷启动后首次压测的性能劣化(~13% 吞吐差距)

3.1 方案一:短请求 curl(❌ 无效)

for i in {1..10}; do
  curl -s http://localhost:8000/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{"model":"/root/autodl-tmp/models/Qwen/Qwen2.5-7B-Instruct","messages":[{"role":"user","content":"hello"}],"max_tokens":10,"temperature":0}' \
    > /dev/null && echo "✅ $i/10"
done

结果:预热后第一次压测的吞吐仍明显低于第二次。

Warmup 方案一结果

原因分析:短请求(max_tokens=10)不会触发和正式压测相同规模的 KV cache 分配和 scheduler 调度路径,预热不充分。

3.2 方案二:长文本 curl(❌ 仍不足)

for i in $(seq 1 10); do
  echo "=== Warmup $i/10 ==="
  curl -s http://localhost:8000/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
      "model": "/root/autodl-tmp/models/Qwen/Qwen2.5-7B-Instruct",
      "messages": [{"role": "user", "content": "请详细解释机器学习中的注意力机制是如何工作的,包括自注意力和多头注意力的原理。"}],
      "max_tokens": 128,
      "temperature": 0
    }' > /dev/null
  echo "   ✅ done"
done

结果:预热后两次压测仍有明显差距,第二次吞吐显著高于第一次。

Warmup 方案二结果

原因分析:虽然输出长度匹配了(128 tokens),但 curl 是串行请求,无法模拟压测时的高并发调度压力

3.3 方案三:低并发 vllm-bench(✅ 有效)

./vllm-bench --backend vllm --base-url http://127.0.0.1:8000 \
  --model /root/autodl-tmp/models/Qwen/Qwen2.5-7B-Instruct \
  --dataset-name random \
  --random-input-len 1024 --random-output-len 128 \
  --num-prompts 50 --max-concurrency 10

结果:预热效果明显,第一次正式压测的吞吐接近第二次。

Warmup 方案三结果

3.4 方案四:高并发 vllm-bench(✅✅ 更优)

./vllm-bench --backend vllm --base-url http://127.0.0.1:8000 \
  --model /root/autodl-tmp/models/Qwen/Qwen2.5-7B-Instruct \
  --dataset-name random \
  --random-input-len 1024 --random-output-len 128 \
  --num-prompts 50 --max-concurrency 50

结果:预热后第一次正式压测的吞吐几乎等同于第二次,冷热差距基本消除。

Warmup 方案四结果

3.5 Warmup 小结

方案 请求方式 并发 输出长度 效果
curl 串行 1 10 ❌ 无效
curl 串行 1 128 ❌ 仍不足
vllm-bench 10 128 ✅ 有效
vllm-bench 50 128 ✅✅ 最优

关键结论

  • 并发是 warmup 的关键变量,串行请求即使输出长度匹配也无法预热 scheduler
  • 输出长度要匹配线上口径,太短不会触发足够的 decode 路径
  • 推荐 warmup 策略:用与线上相同的 input/output 长度 + 中等并发(正式并发的 25%50%),跑 50100 个 prompt 即可

四、单卡计算受限实验(TP=1 阶梯并发)

背景:冷热对比发现 TP=2 场景下瓶颈在 CPU 调度侧,但缺少数据证明 tensor core 是否真正饱和(GeForce 卡不支持 DCGM PROF 指标,无法区分 compute-bound 与 memory-bound)。

目标:改用单卡(TP=1),通过逐步提高并发度,找到 GPU 从 memory-bound → compute-bound 的拐点。

4.1 实验设计

思路:decode 阶段在低并发下是 GEMV(矩阵×向量),天然 memory-bound。提高并发后 continuous batching 将多个 decode 请求合并成 GEMM,batch size 越大,tensor core 越饱和。

方法:单卡启动服务,用 vllm-bench 阶梯式提高并发,记录每轮的关键指标。

# 服务端(TP=1)
vllm serve /root/autodl-tmp/models/Qwen/Qwen2.5-7B-Instruct --tensor-parallel-size 1
# 阶梯压测脚本
for conc in 8 16 32 64 128 200; do
  if [ $conc -le 32 ]; then N=300; else N=500; fi

  echo "======================================"
  echo "  并发度 = $conc  (num-prompts=$N)"
  echo "======================================"
  nvidia-smi --query-gpu=power.draw,temperature.gpu,\
    utilization.gpu,utilization.memory --format=csv -l 1 \
    > /tmp/gpu_monitor_conc${conc}.csv &
  MONITOR_PID=$!

  ./vllm-bench --backend vllm --base-url http://127.0.0.1:8000 \
    --model /root/autodl-tmp/models/Qwen/Qwen2.5-7B-Instruct \
    --dataset-name random \
    --random-input-len 1024 --random-output-len 128 \
    --num-prompts $N --max-concurrency $conc

  kill $MONITOR_PID 2>/dev/null
done

4.2 采集指标

类别 指标 数据来源 说明
性能 TPOT (mean/median) vllm-bench 输出 每个 token 的生成时间
性能 Token 吞吐 (tok/s) vllm-bench 输出 系统总吞吐
性能 Request 吞吐 (req/s) vllm-bench 输出 每秒完成请求数
功耗 GPU 功耗 (W) nvidia-smi power.draw 接近 TDP=320W 说明算力受限
温度 GPU 温度 (°C) nvidia-smi temperature.gpu 避免 throttling(≥85°C 需关注)
SM GPU-Util (%) nvidia-smi utilization.gpu 接近 100% 是必要条件,但非充分
Mem Mem-Util (%) nvidia-smi utilization.memory 高 → memory-bound;下降 → compute-bound

4.3 实验结果

TP=1, Qwen2.5-7B-Instruct, input=1024, output=128(2026-07-02 实测)

整体指标

指标 conc=8 conc=16 conc=32 conc=64 conc=128 conc=200
Benchmark 耗时 142.82s 100.13s 74.77s 104.20s 96.97s 106.44s
Request 吞吐 2.10 req/s 3.00 req/s 4.01 req/s 4.80 req/s 5.16 req/s 4.70 req/s
Output Token 吞吐 268.87 tok/s 383.50 tok/s 513.60 tok/s 614.19 tok/s 660.02 tok/s 601.26 tok/s
Total Token 吞吐 2415.54 tok/s 3445.47 tok/s 4614.23 tok/s 5518.27 tok/s 5930.01 tok/s 5402.06 tok/s
Mean TTFT 417.42ms 696.92ms 1113.52ms 1742.84ms 3849.61ms 8274.87ms
P99 TTFT 1006.08ms 1895.69ms 2959.38ms 7838.34ms 16154.24ms 30199.08ms
Mean TPOT 26.38ms 36.19ms 52.33ms 90.22ms 162.54ms 262.62ms
Median TPOT 26.48ms 37.05ms 53.64ms 94.46ms 180.43ms 285.73ms
Mean E2EL 3767.33ms 5293.65ms 7759.02ms 13200.18ms 24491.84ms 41627.83ms

Steady-State 指标

指标 conc=8 conc=16 conc=32 conc=64 conc=128 conc=200
Request 吞吐 2.09 req/s 2.93 req/s 3.79 req/s 4.40 req/s 4.11 req/s 3.06 req/s
Output Token 吞吐 271.18 tok/s 380.92 tok/s 518.98 tok/s 580.73 tok/s 571.74 tok/s 513.08 tok/s
Mean TTFT 423.89ms 668.58ms 1025.30ms 1414.30ms 2597.92ms 4966.95ms
Mean TPOT 26.46ms 36.41ms 53.54ms 90.99ms 165.13ms 251.96ms

GPU 监控(nvidia-smi 实测)

指标 conc=8 conc=16 conc=32 conc=64 conc=128 conc=200
GPU 功耗 avg 261W 284W 293W 298W 306W 304W
GPU 功耗 max 308W 316W 317W 315W 316W 315W
GPU-Util avg 100% 99% 99% 98% 99% 98%
Mem-Util avg 85% 69% 57% 46% 51% 55%
温度 avg 66°C 72°C 75°C 77°C 78°C 78°C

TPOT & GPU Power 趋势 吞吐 & Mem-Util 趋势 TTFT 趋势

4.4 结果分析

TPOT 随并发增长趋势

并发度 Mean TPOT 相比 conc=1 的倍数 TPOT 增量 GPU 功耗
1(裸算力) 25ms 1.0× 250W
8 26ms 1.1× 1ms 261W
16 36ms 1.4× 11ms 284W
32 52ms 2.1× 27ms 293W
64 90ms 3.6× 65ms 298W
128 163ms 6.5× 138ms 306W
200 263ms 10.5× 238ms 304W

关键观察

  • conc=8 时 TPOT 几乎无变化(25→26ms),TPOT 增量几乎为零
  • conc=16 开始 TPOT 明显抬头(26→36ms,+38%),batch 开始积累
  • conc=32 时 TPOT 翻倍(26→52ms),continuous batching 形成有效 GEMM
  • conc=64 时 TPOT 加速增长(52→90ms,+73%),TPOT 增量 65ms(含合法计算增长 + 调度开销)
  • conc=128 时 TPOT 继续恶化(90→163ms,+81%),TPOT 增量 138ms
  • conc=200 时已过饱和(163→263ms,+61%),吞吐反而下降

吞吐拐点分析

并发度 Output Token 吞吐 Total Token 吞吐 边际收益
8 269 tok/s 2416 tok/s
16 384 tok/s 3445 tok/s +43%
32 514 tok/s 4614 tok/s +34%
64 614 tok/s 5518 tok/s +19%
128 660 tok/s 5930 tok/s +7%
200 601 tok/s 5402 tok/s -9% ⚠️

吞吐在 conc=128 达到峰值,conc=200 反而下降 9%,说明系统已过饱和。排队延迟 > 新增并发带来的收益。

状态判定

并发区间 状态 说明
≤8 🔵 memory-bound GEMV 模式,TPOT 几乎等于裸算力,Mem-Util 100%
16~32 🟡 过渡区 batch 逐渐形成 GEMM,TPOT 开始增长,吞吐快速提升
64 🟢 最佳性价比点 Mem-Util 降至 46%(最低),功耗 298W(93% TDP);OI=55 仍低于 Ridge=135,纯 Roofline 属带宽区,但硬件已接近饱和
128 🟢 吞吐峰值 功耗峰值 306W,吞吐极限 660 tok/s;OI=109 仍低于 Ridge
200 过饱和 吞吐倒退 9%,TTFT 飙到 8.3s

4.5 结论:最佳性价比拐点 = conc=64

GPU 功耗与 Mem-Util 证据链

并发度 功耗 TDP 占比 Mem-Util 状态判定
1 250W 78% 100% 🔵 memory-bound — GEMV,显存带宽瓶颈
8 261W 82% 85% 🔵 memory-bound
16 284W 89% 69% 🟡 过渡区
32 293W 92% 57% 🟡 过渡区
64 298W 93% 46% 🟢 硬件近饱和(OI=55 < Ridge=135,Roofline 仍属带宽区)
128 306W 96% 51% 🟢 硬件近饱和(OI=109 < Ridge=135)
200 304W 95% 55% ⚫ 过饱和

关键判据

  1. Mem-Util 从 100% 降至 46% — 显存带宽不再是瓶颈
  2. GPU 功耗 ≥ 300W(94% TDP) — conc≥64 时功耗持续 298W+
  3. GPU-Util 始终 ~99% — GPU 持续有 kernel 在执行
  4. TPOT 在 conc≥32 后近似线性增长 — 并发翻倍,TPOT 也翻倍

结论:单卡 RTX 4080 在 conc=64 时达到最佳性价比拐点。此时 GPU 功耗 298W(93% TDP)、Mem-Util 降至 46%,硬件接近饱和。但算术强度 OI=55 仍低于 Ridge Point(135),纯 Roofline 意义上仍处于带宽区——硬件虽接近饱和,但 scheduler 开销已占主导,继续提高并发的边际收益急剧递减。

4.6 Roofline Model 分析

理论天花板

参数 RTX 4080
FP16 Tensor Core 峰值 97 TFLOPS
显存带宽 716.8 GB/s
Ridge Point (OI) 97 / 0.717 ≈ 135 FLOPs/Byte
模型权重 (FP16) 7B × 2 bytes = 14 GB
单 token decode FLOPs 2 × 7B = 14G FLOPs

OI 定量计算(以 Qwen2.5-7B 为例):

  • 权重读取:~14 GB(每步固定,跨 batch 共享)
  • KV cache 读取:2 × B × seq_len × d_model × (n_kv_heads / n_heads) × 2 bytes,随并发 B 增长
  • FLOPs:2BN(Attention)+ 6B·d_model·ffn_dim(SwiGLU FFN),随 B 线性增长
  • OI = FLOPs / (weight_bytes + kv_bytes),由于 KV cache 读取随 B 增加,OI 略低于并发度(低约 15~19%)

各并发度在 Roofline 上的位置

并发 OI Ridge=135 实测 TFLOPS 天花板达成率 瓶颈判定
1 1 <135 (带宽区) 0.56 78% ⬅️带宽 🔵 接近带宽天花板(GEMV, memory-bound)
8 7 <135 (带宽区) 4.25 74% ⬅️带宽 🔵 靠近带宽天花板
16 14 <135 (带宽区) 6.19 54% ⬅️带宽 🟡 开始偏离带宽天花板
32 28 <135 (带宽区) 8.56 37% ⬅️带宽 🟡 偏离加剧
64 55 <135 (带宽区) 9.93 22% ⬅️带宽 🟡 带宽区但 scheduler-bound
128 109 <135 (带宽区) 11.02 12% ⬅️带宽 🟡 带宽区但 scheduler-bound
200 168 >135 (计算区) 10.66 11% ⬅️算力 ⚫ 过饱和

注:「天花板达成率」的计算方式取决于 OI 所处的区域:

  • OI < Ridge(带宽区)实测 TFLOPS / (OI × 显存带宽),表示离带宽天花板的距离。例如 conc=64 达成率 22%(带宽天花板 39.4 TFLOPS)。
  • OI > Ridge(计算区)实测 TFLOPS / 算力峰值,表示离算力天花板的距离。例如 conc=200 达成率 11%(算力天花板 97 TFLOPS)。

它与 nvidia-smi 的 Mem-Util 是两回事(后者是显存控制器繁忙程度),例如 conc=64 达成率 22%,但 Mem-Util 为 46%。

Roofline Model

关键发现

  1. conc=1 贴着带宽天花板跑(78%) → 符合预期,GEMV 天然 memory-bound,OI=1 远低于 Ridge Point(135)
  2. conc≥16 后逐渐偏离带宽天花板 → continuous batching 开始形成 GEMM,OI 增长但达成率下降
  3. conc≥64 后 OI 仍低于 Ridge Point(55 < 135) → 理论上仍处于 Roofline 的带宽区,但并非 memory-bound,因为天花板达成率仅 22%,远未触及带宽天花板。scheduler 开销是主要原因
    • OI=55 时带宽天花板:0.717 × 55 = 39.4 TFLOPS
    • 实测:9.93 TFLOPS,仅达到带宽天花板的 25%
  4. conc=200 首次越过 Ridge Point(OI=168 > 135) → 进入计算区,天花板达成率切换为算力天花板(97 TFLOPS),实测仅达到 11%,说明 scheduler 问题同样锁死了算力利用率,且吞吐下滑
带宽天花板 (conc=1):    ████████████████████████░░░ 78%  (OI=1, 纯 GEMV)
非 GPU 时间 (conc=64):   ██████░░░░░░░░░░░░░░░░ 25%  (OI=55, scheduler-bound)
非 GPU 时间 (conc=200):  ███░░░░░░░░░░░░░░░░░░░ 11%  (OI=168, 过饱和)

TP=1 最优并发度推荐

目标 推荐并发 吞吐 TPOT 说明
最低延迟 ≤8 269 tok/s 26ms TPOT 增量≈0
最佳性价比 64 614 tok/s 90ms 吞吐/延迟均衡点
最高吞吐 128 660 tok/s 163ms 吞吐极限
❌ 避免 200 601 tok/s 263ms 过饱和

4.7 Nsight 实时监控命令

# 方案 B:先启动服务,然后 attach profile
vllm serve /root/autodl-tmp/models/Qwen/Qwen2.5-7B-Instruct --tensor-parallel-size 1 &

# 找到 PID,attach profiling 30s
nsys profile -t cuda,nvtx,osrt -o decode_profile --duration 30 -p $(pgrep -f "vllm serve")

五、双卡计算受限实验(TP=2 阶梯并发)

用 TP=2 复现 TP=1 的阶梯并发实验,对比 TP Scaling Efficiency 与调度开销差异。

5.1 实验设计

# 服务启动
vllm serve /root/autodl-tmp/models/Qwen/Qwen2.5-7B-Instruct --tensor-parallel-size 2

# 阶梯压测
for conc in 1 64 128 200; do
  if [ $conc -le 32 ]; then N=300; else N=500; fi

  nvidia-smi --query-gpu=power.draw,temperature.gpu,\
    utilization.gpu,utilization.memory --format=csv -l 1 \
    > /tmp/gpu_monitor_tp2_conc${conc}.csv &
  MONITOR_PID=$!

  ./vllm-bench --backend vllm --base-url http://127.0.0.1:8000 \
    --model /root/autodl-tmp/models/Qwen/Qwen2.5-7B-Instruct \
    --dataset-name random \
    --random-input-len 1024 --random-output-len 128 \
    --num-prompts $N --max-concurrency $conc

  kill $MONITOR_PID 2>/dev/null
done

5.2 整体性能

注:conc=64/128/200 为同一轮连续压测(conc 递增,服务持续运行),conc=1 为单独一轮。conc=200 本次实测数据与第二章 conc=200 存在差异(本次 500 样本、20.66s,第二章 1000 样本、162.91s),推测因第二章数据为独立测试而本次为阶梯序列末轮,scheduler 已充分预热。

指标 conc=1 conc=64 conc=128 conc=200
Total Token 吞吐 (tok/s) 720.74 11315.95 26628.96 27826.71
Output Token 吞吐 (tok/s) 80.22 1259.48 2963.84 3097.15
Benchmark 耗时 (s) 478.66 50.81 21.59 20.66
Mean TPOT (ms) 12.07 44.28 35.66 52.70
Mean TTFT (ms) 62.17 782.36 524.91 776.69
Mean E2EL (ms) 1595.33 6406.35 5053.58 7469.61

Steady-State 指标

指标 conc=64 conc=128 conc=200
Request 吞吐 (req/s) 9.22 23.80 18.75
Output Token 吞吐 (tok/s) 1219.27 3131.35 3102.84
Mean TTFT (ms) 830.52 454.58 605.99
Mean TPOT (ms) 47.08 35.53 50.22

性能分析

TPOT 异常下降(conc=128 反而比 conc=64 低):

并发度 Mean TPOT 相对 conc=1 倍数 TPOT 增量 说明
1(裸算力) 12.07ms 1.0× 双卡裸算力基线
64 44.28ms 3.7× 32ms batch 形成但调度效率不高
128 35.66ms 3.0× 24ms 🔽 反而下降 — batch 效率更优
200 52.70ms 4.4× 41ms 开始过饱和

conc=128 的 TPOT 比 conc=64 更低,说明 TP=2 场景下 scheduler 需要更高的并发才能进入高效 batch 模式。这与 TP=1 的行为完全不同(TP=1 中 TPOT 随并发单调递增)。

吞吐增长趋势:

并发度 Output Token 吞吐 边际收益 累计收益
1 80 tok/s
64 1259 tok/s 15.7×
128 2964 tok/s +135% 37.0×
200 3097 tok/s +4.5% 38.6×

吞吐在 conc=128 达到接近峰值(2964 tok/s),conc=200 仅增长 4.5%,已近饱和。

5.3 GPU 监控数据(nvidia-smi)

nvidia-smi 采样间隔 1s,过滤空闲期(GPU-Util=0%),双卡单独统计。

指标 conc=1 conc=64 conc=128 conc=200
GPU0 功耗 avg (max) 232W (238) 215W (237) 211W (227) 217W (231)
GPU1 功耗 avg (max) 219W (223) 200W (222) 199W (215) 205W (219)
双卡合计功耗 avg 451W 415W 410W 421W
GPU-Util avg 98% 100% 100% 99%
Mem-Util avg 97% 46% 71% 67%
温度 avg 55°C 57°C 54°C 55°C

与 TP=1 的 Mem-Util 对比

并发度 TP=1 Mem-Util TP=2 Mem-Util 差异
conc=1 100% 97% ≈ 一致,都 memory-bound
conc=64 46% 46% 拐点一致
conc=128 51% 71% TP=2 Mem-Util 反而回升 → 不同行为
conc=200 55% 67% TP=2 始终高于 TP=1

关键观察:TP=2 的 Mem-Util 在 conc=64 降至 46%(与 TP=1 一致),但 conc=128 反而回升至 71%,与 TP=1 持续下降的趋势相反。这解释了 conc=128 TPOT 比 conc=64 更低的异常现象。

功耗分析

并发度 TP=1 单卡功耗 TP=2 双卡合计 单卡平均
conc=1 250W 451W 226W
conc=64 298W 415W 208W
conc=128 306W 410W 205W
conc=200 304W 421W 211W

TP=2 单卡功耗远低于 TP=1(205226W vs 250306W),每卡只处理 3.5B 参数,算力远未饱和。两张卡合计功耗 410~451W,而 TDP 合计 640W,利用率仅 64%~70%。

5.4 TP=1 vs TP=2 对比

对比维度 TP=1 TP=2 差异分析
裸算力 TPOT (conc=1) 25ms 12.07ms 🔽 -52%
裸算力 TTFT (conc=1) 250ms 62.17ms 🔽 -75%
峰值吞吐 660 tok/s (conc=128) 3097 tok/s (conc=200) 🚀 +369%
峰值 TPOT 163ms (conc=128) 35.66ms (conc=128) 🔽 -78%
TPOT 行为模式 随并发单调递增 conc=128 反降 不同调度特征
最优性价比并发 conc=64 (614 tok/s) conc=128 (2964 tok/s) TP=2 最佳点在更高并发
过饱和标志 conc=200 吞吐下降 9% conc=200 吞吐仅 +4.5% TP=2 过饱和更温和
TPOT 增量占比 (conc=200) 90.5% 77% 🔽 TP=2 TPOT 增量占比更低(含合法计算增长 + 调度开销)

5.5 图表分析

TPOT & GPU Power 趋势 吞吐 & Mem-Util 趋势 TTFT 趋势 TP=1 vs TP=2 吞吐对比 TP=1 vs TP=2 TPOT 对比 TP=1 vs TP=2 Mem-Util 对比 综合总结图

5.6 关键发现

  1. TP=2 吞吐远超 TP=1:峰值 3097 tok/s vs 660 tok/s(+369%),但这是两张卡合计
  2. TPOT 异常下降(conc=128 < conc=64):与 TP=1 单调递增完全不同,TP=2 需要更高并发才能进入高效 batch 模式
  3. conc=128 是 TP=2 的最佳性价比点:吞吐 2964 tok/s(峰值的 96%),TPOT 仅 35.66ms(最低点)
  4. TPOT 增量占比反而降低:conc=200 的 TPOT 增量占比约 77%,低于 TP=1 的 90.5%(注意:该增量包含 batch 增大带来的合法计算增长,不全是调度开销)

5.7 原始日志

================= Serving Benchmark Result =================
Successful requests:                     300      
Failed requests:                         0         
Maximum request concurrency:             1         
Benchmark duration (s):                  478.66    
Total input tokens:                      306592    
Total generated tokens:                  38400     
Request throughput (req/s):              0.63      
Output token throughput (tok/s):         80.22     
Peak output token throughput (tok/s):    83.00     
Peak concurrent requests:                2.00      
Total token throughput (tok/s):          720.74    
--------------------Time to First Token---------------------
Mean TTFT (ms):                          62.17     
Median TTFT (ms):                        44.10     
P99 TTFT (ms):                           160.71    
P90 TTFT (ms):                           155.20    
----------Time per Output Token (excl. 1st token)-----------
Mean TPOT (ms):                          12.07     
Median TPOT (ms):                        12.07     
P99 TPOT (ms):                           12.11     
P90 TPOT (ms):                           12.09     
--------------------Inter-token Latency---------------------
Mean ITL (ms):                           12.07     
Median ITL (ms):                         12.08     
P99 ITL (ms):                            12.70     
P90 ITL (ms):                            12.36     
---------------------End-to-end Latency---------------------
Mean E2EL (ms):                          1595.33   
Median E2EL (ms):                        1576.75   
P99 E2EL (ms):                           1696.40   
P90 E2EL (ms):                           1689.94   
============================================================
============ Steady-State Metrics =============
Concurrency threshold:              >= 0.95 * 1 = 1
Window:                             0.0s -> 478.7s  (478.7s)
Observed peak concurrency:          1
Requests started in window:         300 / 300 (100.0%)
Requests completed in window:       299
-----------------------------------------------
Request throughput (req/s):         0.62
Output token throughput (tok/s):    80.22
Input token throughput (tok/s):     640.52
Total token throughput (tok/s):     720.74
-----------------------------------------------
Mean TTFT (ms):                     62.17
Median TTFT (ms):                   44.10
P99 TTFT (ms):                      160.71
P90 TTFT (ms):                      155.20
-----------------------------------------------
Mean TPOT (ms):                     12.07
Median TPOT (ms):                   12.07
P90 TPOT (ms):                      12.09
P99 TPOT (ms):                      12.11
================= Serving Benchmark Result =================
Successful requests:                     500      
Failed requests:                         0         
Maximum request concurrency:             64        
Benchmark duration (s):                  50.81     
Total input tokens:                      511016    
Total generated tokens:                  64000     
Request throughput (req/s):              9.84      
Output token throughput (tok/s):         1259.48   
Peak output token throughput (tok/s):    2752.00   
Peak concurrent requests:                127.00    
Total token throughput (tok/s):          11315.95  
--------------------Time to First Token---------------------
Mean TTFT (ms):                          782.36    
Median TTFT (ms):                        392.59    
P99 TTFT (ms):                           3219.09   
P90 TTFT (ms):                           1879.11   
----------Time per Output Token (excl. 1st token)-----------
Mean TPOT (ms):                          44.28     
Median TPOT (ms):                        24.39     
P99 TPOT (ms):                           83.53     
P90 TPOT (ms):                           77.89     
--------------------Inter-token Latency---------------------
Mean ITL (ms):                           44.28     
Median ITL (ms):                         23.69     
P99 ITL (ms):                            270.11    
P90 ITL (ms):                            55.51     
---------------------End-to-end Latency---------------------
Mean E2EL (ms):                          6406.35   
Median E2EL (ms):                        3588.75   
P99 E2EL (ms):                           12414.67  
P90 E2EL (ms):                           11486.00  
============================================================
============ Steady-State Metrics =============
Concurrency threshold:              >= 0.95 * 64 = 61
Window:                             0.0s -> 47.6s  (47.6s)
Observed peak concurrency:          64
Requests started in window:         440 / 500 (88.0%)
Requests completed in window:       439
-----------------------------------------------
Request throughput (req/s):         9.22
Output token throughput (tok/s):    1219.27
Input token throughput (tok/s):     9449.77
Total token throughput (tok/s):     10669.04
-----------------------------------------------
Mean TTFT (ms):                     830.52
Median TTFT (ms):                   392.43
P99 TTFT (ms):                      3219.63
P90 TTFT (ms):                      2102.67
-----------------------------------------------
Mean TPOT (ms):                     47.08
Median TPOT (ms):                   43.22
P90 TPOT (ms):                      77.93
P99 TPOT (ms):                      83.60
================= Serving Benchmark Result =================
Successful requests:                     500      
Failed requests:                         0         
Maximum request concurrency:             128       
Benchmark duration (s):                  21.59     
Total input tokens:                      511016    
Total generated tokens:                  64000     
Request throughput (req/s):              23.15     
Output token throughput (tok/s):         2963.84   
Peak output token throughput (tok/s):    3712.00   
Peak concurrent requests:                247.00    
Total token throughput (tok/s):          26628.96  
--------------------Time to First Token---------------------
Mean TTFT (ms):                          524.91    
Median TTFT (ms):                        468.75    
P99 TTFT (ms):                           1131.63   
P90 TTFT (ms):                           903.48    
----------Time per Output Token (excl. 1st token)-----------
Mean TPOT (ms):                          35.66     
Median TPOT (ms):                        36.20     
P99 TPOT (ms):                           37.21     
P90 TPOT (ms):                           36.93     
--------------------Inter-token Latency---------------------
Mean ITL (ms):                           35.66     
Median ITL (ms):                         34.41     
P99 ITL (ms):                            98.15     
P90 ITL (ms):                            39.61     
---------------------End-to-end Latency---------------------
Mean E2EL (ms):                          5053.58   
Median E2EL (ms):                        5058.74   
P99 E2EL (ms):                           5706.48   
P90 E2EL (ms):                           5519.99   
============================================================
============ Steady-State Metrics =============
Concurrency threshold:              >= 0.95 * 128 = 122
Window:                             0.0s -> 15.9s  (15.9s)
Observed peak concurrency:          128
Requests started in window:         379 / 500 (75.8%)
Requests completed in window:       378
-----------------------------------------------
Request throughput (req/s):         23.80
Output token throughput (tok/s):    3131.35
Input token throughput (tok/s):     24395.32
Total token throughput (tok/s):     27526.67
-----------------------------------------------
Mean TTFT (ms):                     454.58
Median TTFT (ms):                   449.21
P99 TTFT (ms):                      1129.99
P90 TTFT (ms):                      547.26
-----------------------------------------------
Mean TPOT (ms):                     35.53
Median TPOT (ms):                   36.47
P90 TPOT (ms):                      36.98
P99 TPOT (ms):                      37.31
================= Serving Benchmark Result =================
Successful requests:                     500      
Failed requests:                         0         
Maximum request concurrency:             200       
Benchmark duration (s):                  20.66     
Total input tokens:                      511016    
Total generated tokens:                  64000     
Request throughput (req/s):              24.20     
Output token throughput (tok/s):         3097.15   
Peak output token throughput (tok/s):    3800.00   
Peak concurrent requests:                299.00    
Total token throughput (tok/s):          27826.71  
--------------------Time to First Token---------------------
Mean TTFT (ms):                          776.69    
Median TTFT (ms):                        625.87    
P99 TTFT (ms):                           1731.52   
P90 TTFT (ms):                           1495.49   
----------Time per Output Token (excl. 1st token)-----------
Mean TPOT (ms):                          52.70     
Median TPOT (ms):                        57.56     
P99 TPOT (ms):                           59.60     
P90 TPOT (ms):                           58.86     
--------------------Inter-token Latency---------------------
Mean ITL (ms):                           52.70     
Median ITL (ms):                         52.13     
P99 ITL (ms):                            154.89    
P90 ITL (ms):                            62.60     
---------------------End-to-end Latency---------------------
Mean E2EL (ms):                          7469.61   
Median E2EL (ms):                        8025.32   
P99 E2EL (ms):                           8968.65   
P90 E2EL (ms):                           8877.64   
============================================================
============ Steady-State Metrics =============
Concurrency threshold:              >= 0.95 * 200 = 190
Window:                             0.0s -> 16.6s  (16.5s)
Observed peak concurrency:          200
Requests started in window:         311 / 500 (62.2%)
Requests completed in window:       310
-----------------------------------------------
Request throughput (req/s):         18.75
Output token throughput (tok/s):    3102.84
Input token throughput (tok/s):     19228.31
Total token throughput (tok/s):     22331.15
-----------------------------------------------
Mean TTFT (ms):                     605.99
Median TTFT (ms):                   571.66
P99 TTFT (ms):                      1731.22
P90 TTFT (ms):                      769.80
-----------------------------------------------
Mean TPOT (ms):                     50.22
Median TPOT (ms):                   57.64
P90 TPOT (ms):                      58.86
P99 TPOT (ms):                      59.60

六、调度瓶颈深度分析

6.1 Nsight Systems Profiling

使用 Nsight Systems 对 TP=1、conc=64 场景进行 GPU timeline 采集,精确定位 decode step 中的时间分布。

采集方法

# 方案 B(attach 模式)
vllm serve /root/autodl-tmp/models/Qwen/Qwen2.5-7B-Instruct --tensor-parallel-size 1 &
nsys profile -t cuda,nvtx,osrt -o decode_profile --duration 30 -p $(pgrep -f "vllm serve")

# 另一终端发起压测
./vllm-bench --backend vllm --base-url http://127.0.0.1:8000 \
  --model /root/autodl-tmp/models/Qwen/Qwen2.5-7B-Instruct \
  --dataset-name random \
  --random-input-len 1024 --random-output-len 128 \
  --num-prompts 200 --max-concurrency 64

Timeline 整体视图(200ms 窗口)

Nsight Timeline 全景

截图对应约 200ms 时间窗口,完整覆盖约两个 decode step 周期。

观察项 说明
🟩 cudaEventSynchronize(绿色条) CPU 线程调用 cuEventSynchronize 等待 GPU 完成
🟫 epoll_wait(米色方块) EngineCore 线程进行 I/O 事件等待
🟫 sem_wait(棕色条) 线程间信号量同步等待
GPU HW 行(蓝色区域) GPU 执行 kernel 的时间段

CUDA Stream 与 Kernel 分布

Nsight Kernel 细节

Stream 分工

Stream 总占比 组成 角色
Default stream 7 93.6% 24.6% Graphs + 68.9% Kernels + 6.4% Memory 主力执行流
Stream 22 6.0% 99.8% Kernels + 0.2% Memory 辅助流

GPU 时间分布(所有 Stream 合计)

类别 占比 含义
Kernels 70.9% 单个 CUDA kernel 执行时间
Graphs 23.0% CUDA Graph 执行(封装多个 kernel 减少 CPU launch 开销)
Memory 6.1% 数据搬运(Host-Device / Device-Device)

识别的主要 Kernel

Kernel 名称 类型 用途
cutlass::Kernel2<...s16816gemm_relu_bf16_256x128_32x3_tn_align8> CUTLASS GEMM + ReLU MLP gate/up projection
ampere_bf16_s16816gemm_bf16_256x128_lda8_f2f_stages_32x3_tn CUTLASS GEMM MLP down projection
flash::flash_fwd_splitkv_kernel<128,64,128,4,...> Flash Attention Self-attention
triton_red... Triton Reduction Attention 后处理
triton_p... Triton Pointwise RoPE / LayerNorm

注:CUTLASS kernel 的模板参数 bf16_256x128_32x3 表示 tile size 256×128,stages=3,这是针对 RTX 4080 (sm_86) 优化过的配置。

生成时间分布图

Nsight 完整 decode 周期

截图显示约 200ms 窗口内 GPU 活动与 CPU 同步事件的对应关系。

分析结论

解码后的执行模式

约 90~100ms(一个完整 decode step 周期)
┌──────────────────────────────────────────┐
│ GPU kernel 序列(连续执行)                │
│ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐          │
│ │ K │ │ K │ │ K │ │ K │ │ K │  ...      │
│ └───┘ └───┘ └───┘ └───┘ └───┘          │
│                                          │
│ ▼ cudaEventSynchronize(CPU 等 GPU)     │ ← 🟩 绿色条
│                                          │
│ 调度间隔(~10-20ms)                      │
│   ├─ epoll_wait(I/O 等待)               │
│   └─ sem_wait(线程同步)                 │
│                                          │
│ 下一轮 decode kernel 序列开始              │
└──────────────────────────────────────────┘

核心发现

发现一:CPU-GPU 同步开销

cudaEventSynchronize 的存在表明 vLLM 的异步调度中存在残留的 CPU-GPU 同步点。vLLM V1 默认启用了异步调度(async_scheduling=True),允许 CPU 准备第 N+1 步时 GPU 执行第 N 步。但实际 Nsight 数据中仍可见 cudaEventSynchronize 阻塞,说明异步重叠不彻底:

  • GPU 执行当前 batch 的 kernel
  • CPU 在 cudaEventSynchronize 处等待 GPU 完成部分操作(如准备下一批输入数据)
  • 此后 CPU 执行调度逻辑(epoll_wait + sem_wait
  • GPU 开始下一批 kernel

vLLM 官方也承认 V1 的异步支持是 “retrofitted behavior and hacks”,MRV2(新一代 Model Runner)才真正以异步流水线为原生设计。

发现二:混合执行方式(CUDA Graph + 传统 Launch)

GPU 执行时间中:

  • 23.0% 来自 CUDA Graph(预编译的 kernel 序列)
  • 70.9% 来自传统单个 kernel launch

vLLM 已在使用 CUDA Graph 优化 attention 等固定路径,但大部分 GEMM 和 element-wise 操作仍以传统方式 launch。

发现三:算子组成

算子 来源 对应模型组件
cutlass::Kernel2<...gemm_relu...> CUTLASS MLP gate/up projection
ampere_bf16_s16816gemm... CUTLASS MLP down projection
flash::flash_fwd_splitkv_kernel FlashAttention v2 Self-attention
triton_red... / triton_p... Triton Softmax / RoPE / LayerNorm

可能的开销来源

现象 可能原因
cudaEventSynchronize 异步调度中的残留同步点,CPU 等待 GPU 完成部分操作
epoll_wait EngineCore 线程等待 I/O 事件(网络 / IPC)
sem_wait vLLM 内部线程间同步(scheduler worker 通信)

与实验结果交叉验证

指标 阶梯实验(conc=64) Nsight 观察
Mean TPOT 90.22ms 90100ms 周期 ✅
同步/调度事件 cudaEventSynchronize + epoll_wait + sem_wait 占据 GPU 空闲间隙 ✅
GPU-Util 98% GPU kernel 条连续无间隙 ✅

6.2 Grafana 监控截图

TP=2 conc=200 压测过程中的实时监控数据:

Requests Prefill and Decode Time Token Throughput E2E Request Latency vllm:num_requests_waiting


七、总结与下一步

7.1 TP=1 vs TP=2 瓶颈性质对比

场景 瓶颈性质 核心证据
TP=1 conc≥64 后 硬件近饱和 功耗 298306W(9396% TDP),Mem-Util 降至 46%;但 OI=55~109 仍低于 Ridge=135,scheduler 开销显著
TP=2 始终 scheduler-bound 单卡功耗仅 205226W(6471% TDP),GPU 远未饱和

TP=1 经过足够并发可以压满单卡算力。TP=2 则永远无法压满 GPU——每卡只处理 3.5B 参数,scheduler 开销增长始终快于 batch 合并带来的算力收益。

7.2 根本原因

从 Nsight Systems profiling 确认,vLLM V1 的异步调度中存在残留的 CPU-GPU 同步点cudaEventSynchronize)。虽然 vLLM 默认启用异步调度让 CPU 和 GPU 部分重叠,但实际执行中仍有明显的同步等待:

提交 kernel → cudaEventSynchronize(CPU 等 GPU 完成部分操作)→ CPU 调度 → 提交下一批
                                                              ↑
                                                      GPU 空闲,等 CPU

这导致 CPU 和 GPU 无法完全流水线化,是当前系统性能瓶颈的根本原因。官方也在新一代 Model Runner(MRV2)中将异步流水线作为原生设计来彻底解决此问题。

7.3 优化方向评估

方案 可行性 说明
--num-scheduler-steps ❌ vLLM V1 不兼容 官方说明
--max-num-seqs 512 ⏳ 可试 放宽默认 256 上限,可能小幅改善
vLLM MRV2(下一代 Model Runner) ⏳ 开发中 原生异步流水线设计,无 CPU 同步点
换用 SGLang ⭐ 最高收益 异步调度架构,从根本上减少 cudaEventSynchronize 等待
换用 TensorRT-LLM ⭐ 高收益但高投入 异步流水线执行,CPU 与 GPU 可重叠

7.4 最终结论

当前系统的性能天花板来自 GPU 利用率不足,根因是 vLLM V1 异步调度中的残留同步开销,而非 GPU 硬件瓶颈。

TP=2 虽然能将吞吐推到 TP=1 的 4.7×,但这只是双卡硬件翻倍的物理红利。每张 GPU 的实际利用率仅 64%~71%,算力远未饱和。在不改变推理框架的前提下,通过调参最多只能获得 5%~10% 的边际提升。要突破这个天花板,需要更彻底的异步流水线架构(SGLang / TensorRT-LLM 或 vLLM 新一代 MRV2)从执行模型层面解决 CPU-GPU 串行化问题。

7.5 待办事项清单

  • Warmup 验证:并发是关键,推荐 vllm-bench --num-prompts 50 --max-concurrency 50(见第三章)
  • DCGM 监控完善:GeForce 卡不支持 PROF 指标
  • 低并发对比:并发=1 下 TPOT=25ms(见第一章)
  • Nsight Systems profiling:发现 cudaEventSynchronize 残留同步开销,CPU 与 GPU 无法完全流水线化(见第六章)
  • 单卡计算受限实验:TP=1 阶梯并发,找到最佳性价比拐点 conc=64,Roofline 验证 GPU 硬件不是瓶颈(见第四章)
  • 双卡计算受限实验:TP=2 阶梯并发,发现 TPOT 异常下降和 Mem-Util V 型走势(见第五章)