仿真模型参考
本文说明 vllm-sr-sim 背后的数学模型、各模型假设、假设失效之处,以及如何按工作负载调参。
面向进阶用户与维护者。操作路径请先读 快速开始 与 容量规划场景。
1. GPU 迭代延迟模型
公式
每个 GPU profile 暴露迭代延迟函数:
iter_t(n_active, mean_seq_len) = W + H_eff × n_active
| 符号 | 含义 | 单位 |
|---|---|---|
W | 基础迭代成本:权重内存读、AllReduce、核启动 | 秒 |
H | 在 calibration_ctx 上测得的每序列开销 | s/seq |
H_eff | 按实际平均序列长度缩放后的有效每序列开销 | s/seq |
n_active | 当前 batch 中活跃序列数 | — |
mean_seq_len | 活跃序列的平均总 token(prompt + 输出) | tokens |
calibration_ctx | 测量 H 时的上下文长度(默认 8192) | tokens |
序列长度缩放:
H_eff = H × (mean_seq_len / calibration_ctx)
注意力计算成本随序列长度近似线性:O(n_active × seq_len × d_head)。池服务 800 token 的 LMSYS 请求时,H_eff 比服务 8192 token 上限时小约 10×。
异构池为何重要
iter_t 与 n_slots 均随上下文长度反向缩放;合起来使短池相对同构池有显著吞吐优势(A100-80 GB 例:W=8 ms,H=0.65 ms,calibration_ctx=8192):
| Pool | max_ctx | n_slots | mean_seq | H_eff | iter_t @full | GPU 吞吐 |
|---|---|---|---|---|---|---|
| Short pool | 2 048 | 512 | 800 | 6.5 × 10⁻⁵ | 40 ms | ~78 req/s |
| Homo pool | 8 192 | 128 | 1 600 | 1.3 × 10⁻⁴ | 25 ms | ~49 req/s |
| Long pool | 8 192 | 128 | 5 000 | 4.0 × 10⁻⁴ | 59 ms | ~2 req/s |
| Homo (agent) | 65 536 | 16 | 15 000 | 1.2 × 10⁻³ | 27 ms | ~1 req/s |
若省略 mean_seq_len(兼容旧调用),H_eff = H,等价于假设每条活跃序列都是 calibration_ctx 长 —— 仅当池内平均请求长度与标定上下文一致时才正确。明显更短的请求应传入 mean_seq_len。
预置 H100 profile 常数
W = 0.004 s (4 ms 基础迭代,权重内存读主导)
H = 0.00032 s/seq @ calibration_ctx = 8192(Llama-3-70B,TP8,BF16)
由微基准拟合;任意 GPU+模型可用 ProfileBuilder 从第一性原理计算。
假设与局限
| 假设 | 失效情形 |
|---|---|
| 注意力成本 ∝ seq_len(线性) | 无 FlashAttention 的二次核或极长序列上的次线性核 |
解析模型中活跃 batch 的 mean_seq_len = 单请求长度 | 同构池混合 batch:iter_t 由混合决定,非单条请求长度 |
| 跨 batch 常数 W | 极小 batch(n_active < 4)时核启动开销占比变大 |
| H 对 n_active 线性 | n_active 超过算力或带宽饱和点后 H 非线性上升 |
2. KV-cache 槽模型
公式
池中每 GPU 须同时满足两类并发上限:
kv_limit = total_kv_blks ÷ ⌈max_ctx / blk_size⌉
compute_cap = max_slots × calibration_ctx ÷ max_ctx
n_slots = min(kv_limit, compute_cap)
| 符号 | 含义 | A100_80GB 示例 |
|---|---|---|
total_kv_blks | GPU 上 PagedAttention 块总数 | 65 536 |
blk_size | 每 KV 块 token 数 | 16 |
max_ctx | 池的最大上下文 | 按池配置 |
max_slots | 在 calibration_ctx 测得的注意力带宽饱和上限 | 128 |
calibration_ctx | 测量 max_slots 时的上下文 | 8 192 |
更短 max_ctx 下,相同带宽预算可支持更多并发序列,故 compute_cap 与 max_ctx 成反比。在 max_ctx = calibration_ctx 时两限制按构造相等。
A100-80 GB 示例:
| max_ctx | kv_limit | compute_cap | n_slots |
|---|---|---|---|
| 2 048 | 512 | 512 | 512 |
| 4 096 | 256 | 256 | 256 |
| 8 192 | 128 | 128 | 128 |
| 16 384 | 64 | 64 | 64 |
| 65 536 | 16 | 16 | 16 |
这是双池效率的主要来源:max_ctx = 4096 时可跑 256 条并发 —— 比 8192 时多 2× —— 而每迭代注意力成本按同因子下降。
KV 块准入门限
新请求准入前 DES 检查块预算:
blocks_needed = ⌈(l_in + l_out) / blk_size⌉
if used_blocks + blocks_needed > total_kv_blks:
→ 抢占当前最长活跃请求(回到队列头重排)
刻画 PagedAttention 块级分配,避免未检查 KV 容量即准入导致 OOM。
假设
| 假设 | 失效情形 |
|---|---|
最坏块分配:准入时 l_in + l_out 块 | 推测解码或早停使实际输出 < l_out |
固定 total_kv_blks | 解耦 serving 时 prefill/decode GPU 块预算不同 |
| 块粒度 16 token | vLLM 0.4+ 默认 block_size=16;用 ManualProfile(blk_size=...) 调整 |