1049 字
5 分钟
22GB 单卡推理实验记录

目的:在单张魔改 RTX 2080 Ti 22GB (SM75) 上验证 vLLM fork,积累可复现的 benchmark 数据, 为「单卡 TP=1 profile」开源贡献攒素材。所有数字均有日志出处,无推算混入。

这不是不同显卡之间的性能排名,而是一组固定硬件、固定模型和固定请求长度下的实验记录。重点是看 22GB 显存怎样在权重、KV 池和计算工作区之间分配,以及每次调整到底换来了什么。

阅读入口#

  • 概念解释:vLLM 推理部署概念速查
  • 流程动画:vLLM 请求生命周期动画演示(浏览器打开,本数据集的数字都演了一遍)

环境#

项值
系统Windows 11 + WSL2 (Ubuntu 24.04.4)
GPUGigabyte RTX 2080 Ti 22GB(魔改),Turing / SM75,22528 MiB
驱动581.80(Windows 侧),WSL 映射,不装 Linux 驱动
CUDA并存 13.3 / 12.8,构建显式用 12.8
vLLM0.1.17(fork,基于上游 0.21.0),./.venv/bin/python
PyTorch2.11.0+cu128
模型QuantTrio/Qwen3.5-9B-AWQ(AWQ 4bit,LLM-only 加载权重 10.35 GiB)

模型选型结论(单卡 22GB 三关筛选)#

筛选条件:权重 ≤~17GB / 量化格式 fork 已验证 / 架构 fork 认识。

模型权重判定
QuantTrio/Qwen3.5-9B-AWQ10.35 GiB(LLM-only)✅ 唯一全过,消融主实验台
Vishva007/Qwen3.8-27B-W4A16-AutoRound17.2 GiB(LLM-only)✅ 意外跑通(4K 上下文是极限形态)
一切 27B AWQ/INT419-22 GB❌ 物理墙(需双卡 TP=2)
google/gemma-4-31B-it-qat-w4a16-ct23.3 GB❌ 超上限

速度基线(端到端,256 tokens,含 prefill)#

配置耗时tok/s相对基线
eager / seq=1 / 8K(原始基线)6.237s41.0—
+ CUDA Graph5.553s46.1+12.5%
+ MTP_K=23.19s80.3+96%
+ MAX_BATCHED_TOKENS=20483.17s80.8无改善(噪声内)
  • 最优配置:8K / GPU_UTIL 0.80 / CUDA Graph / prefix cache / MTP_K=2 / seq=1 / max_batched 1024 → 80.3 tok/s
  • 理论 decode 上限 = 616 GB/s ÷ 12 GB 权重 ≈ 51 tok/s(eager 效率 ~80%)
  • 27B 参考:23.9 tok/s(safe/4K/eager),理论上限 ≈ 32 tok/s,效率 ~75%

上下文 vs KV 池曲线(mamba 池之谜)#

MAX_MODEL_LEN可用 KV池子 tokens每 token 成本超出地板价开销
8K7.06 GiB188,847~39.2 KB+1.3 GB
32K7.06 GiB217,460~34.0 KB+0.37 GB
128K7.06 GiB227,815~32.5 KB+0.05 GB
262K9.26 GiB300,941~32.3 KB+0.01 GB
  • 地板价 ~32.3 KB/token = 16 层全注意力 × 2(K+V) × 4 heads × 128 dim × 2B(GDN 混合架构只有部分层是 full attention)
  • 额外开销近似 ∝ 1/max_model_len:短上下文时 GDN state 池收一笔 ~1.3GB 的”过路费”,上下文越长摊得越薄
  • 262K 实测:单卡 22GB + Qwen3.5-9B 原生 262K 上下文(GPU_UTIL 0.90),总显存 21998/22528 MiB,速度 38.6 tok/s(长上下文几乎免费,仅 -6%)

Prefix Cache#

  • 长前缀测试(~6.9K token 文档):冷请求 3.30s → 热请求 0.71s(4.6x),cached_tokens=6864
  • 缓存块粒度 = 528 tokens(6864 = 528×13,等于 attention page 与 mamba page 的对齐块大小);短于一块的 prompt 无命中,非 bug
  • 引擎 hit rate 实测 64.9%

MTP 推测解码#

  • QuantTrio/Qwen3.5-9B-AWQ 含 MTP 草稿头(config: mtp_num_hidden_layers: 1)
  • MTP_K=2:Avg Draft acceptance 69.6%(per-position 0.785 / 0.607),Mean acceptance length 2.39/3.0
  • 代价:KV 池 188,847 → 73,728 tokens(-61%,verify 工作区 + cudagraph capture size 3)
  • MTP 与超长上下文天然冲突(262K + MTP 无余量);MTP 下 min_p / logit_bias 失效

环境排障记录(可复现,社区无文档)#

  1. GPU_UTIL 启动检查差 90MB:0.95×22=20.9 > 可用 20.81 → 启动前体检直接拒绝;降到 0.94/0.93 通过
  2. 缺 g++-12:FlashQLA legacy GDN 内核 JIT 编译时 cc1plus: No such file or directory → sudo apt-get install -y g++-12(仓库把编译器 pin 死为 gcc-12,Ubuntu 24.04 默认只有 gcc-13 全家桶)
  3. WSL 检测:pin_memory=False 警告,性能略降
  4. 推理期 Triton JIT 尖峰:首次请求触发 7 个 kernel 的 JIT 编译(_zero_kv_blocks_kernel、_compute_slot_mapping_kernel、_copy_page_indices_kernel、_causal_conv1d_fwd/update_kernel、fused_recurrent_gated_delta_rule_packed_decode_kernel、_fused_post_conv_kernel),jit_monitor 建议扩展 warmup 覆盖

可能的后续贡献#

  1. 单卡 TP=1 启动 profile:README 全部 profile 都是双卡 TP=2,单卡 22GB 验证无人做过 ← 主攻方向
  2. warmup JIT 缺口修复:fork 自带 jit_monitor 已提示方向,门槛最低
  3. GDN 短上下文 KV 池额外开销(~1.3GB @8K):机制待翻 kv_cache_utils.py 确认,可开 issue
  4. 单卡 AWQ 兼容表 / OOM 排查文档(g++-12 坑,WSL2 用户必踩)
  5. 上下文长度 vs KV 池曲线 benchmark

仓库背景:140+ issues、137+ PR,维护者天级响应,外部 PR 确有合并先例(kevinhirsch #133/#125/#111、hotwa #116、superniker #108);提交前须读 issue #74,重大贡献先在 issue/Discord 打招呼。

后续实验#

  • 32K→16K 中间点,验证 1/max_model_len 规律的中间形态
  • MAX_NUM_SEQS=2~4 并发测试(KV 池 73K tokens 余量足够)
  • MAX_BATCHED_TOKENS 在并发下的作用验证
  • 27B @8K 边界实验(KV 111KB/token × 8K ≈ 0.9GB < 2.32GB 池,理论上装得下)
  • 仓库只读扫描:profiles/ 目录、已关 issue,确认贡献点无人做过
  • 数据整理成 hotwa #121 格式的 PR 草案
80.3 tok/s
MTP_K=2
262K
实测上下文
4.6x
Prefix Cache 热请求
系列文章
推理部署实验
相关文章
22GB 单卡推理实验记录
https://www.yyylegend.com/posts/22gb单卡推理实验记录/
作者
YYYLEGEND
发布于
2026-09-17
许可协议
CC BY-NC-SA 4.0