跳转到主要内容

Chunked Prefill 深入分析:调度、Chunk Size 与 Attention 形状

· 约 15 分钟阅读

1. 摘要:当前判断

Chunked Prefill 改变的是 prefill 在调度器里占用 GPU 的连续时间。它不会减少完整 prompt 的总 token 数,也不会减少最终要写入的 KV cache。它把长 prompt 的 prefill 拆成多个可调度片段,让 decode 或短 prefill 请求在片段之间获得执行机会。

当前可以相信的判断:

判断含义
它主要优化调度,不是降低总计算量同一个 prompt 的 causal attention、FFN/MoE 计算仍要完成
chunk size 是 TTFT、ITL/TPOT 和吞吐之间的旋钮(同池混部场景)小 chunk 保护 decode tail,大 chunk 保护 TTFT 和 prefill 吞吐;P/D 分离后 decode 不再同池竞争,此 trade-off 弱化,chunk size 转向控制 prefill pool 公平性和 KV 发送节奏
底层性能取决于 shape,不只取决于 token 总数attention 看 Q_len/K_len,GEMM/MoE 看 total_num_scheduled_tokens x hidden_size 和 expert token group
输入分桶和 chunked prefill 解决不同层的问题分桶控制请求进入哪个队列或 batch,chunk 控制单个长请求每轮执行多少 token
P/D 分离后仍可能需要 chunked prefill它转向控制 prefill pool 的排队公平性、KV 发送节奏、activation 峰值和 tail chunk
trace 里的 plan/run 次数不能直接当 chunk sizeQwen3.5 Plus trace 中的 15 plan/run 更像模型结构信号,对应 15 个 full attention layer
Shape 速查:chunk size 如何映射到底层 kernel

同样处理 8K token,chunk=4096 vs chunk=512 vs chunk=64 送入 kernel 的张量形状不同,GPU 利用率也不同:

kernelchunk size 影响的维度chunk 太小的后果
AttentionQ_len = chunk_sizeK_len = 已缓存 KV + chunk_sizeQ 太短,kernel launch 开销占比上升
Dense FFN (GEMM)M = total_scheduled_tokens(本轮所有 chunk token 之和)M 维度小,Tensor Core 吃不饱
MoE Expert每个 expert 的 token 数 ≈ chunk_size × routing_ratiogrouped GEMM 变碎,效率下降

完整分析见 §5 性能模型

调优时先回答四个问题:

  1. 当前 SLO 压力来自 TTFT、ITL/TPOT P99、tokens/s/GPU,还是 SLO QPS?
  2. decode backlog 是否长期存在?
  3. prefix cache hit 后,真实 effective prefill tokens 还有多少?
  4. 当前 chunk 在 attention、GEMM、MoE expert group 上是否太碎?

2. 问题定义:长 Prompt 为什么阻塞 Decode

LLM serving 的每轮调度通常包含两类工作:

工作单请求形态主要瓶颈
Prefill处理 prompt 的一段或全部 token大多 compute-bound,尤其是 FFN/MoE 和大 Q_len attention
Decode每个活跃请求通常生成 1 个 token大多 memory-bound,要读 weights 和已有 KV cache

如果调度器把长 prompt 的 prefill 当成不可切分任务,一个 16K 或 32K prompt 可能连续占住 GPU:

t0: decode batch 稳定出 token
t1: 进入一个 32K prompt
t1-t2: GPU 连续执行完整 prefill
t2: decode batch 才恢复

用户看到的是流式输出停顿。监控上通常体现为:

  • ITL / TPOT P95/P99 拉高;
  • decode step 之间出现长 scheduling gap;
  • trace 中长 prefill kernel 横在 decode kernel 中间;
  • 平均延迟变化不大,但尾延迟明显变差。

Chunked Prefill 把长 prefill 拆成多个调度片段:

prefill chunk 1 -> decode -> prefill chunk 2 -> decode -> prefill chunk 3 -> decode

一个请求只有在自己的 prompt KV 全部写完后才能开始 decode。chunked prefill 不是让同一个请求边 prefill 边 decode,而是在 不同请求之间 交错执行:A 的长 prompt 还没完成时,B/C 的短 prompt 可以先完成并进入 decode。

3. 背景:让 Chunked Prefill 能落地的机制

3.1 Continuous Batching

Continuous batching 允许每个 engine step 动态接收新请求、推进已有请求,并移除完成请求。Chunked Prefill 依赖这个调度模型:如果 batch 必须从头到尾固定,长 prompt 仍会把整批请求绑住。

3.2 Paged KV Cache

PagedAttention / paged KV cache 把每个请求的 KV 存到 block/page 中。调度器可以在不同 step 中继续给同一个请求追加 KV,而不要求 KV 在物理内存上连续。

这让 partial prefill 成为可执行状态:

request A:
  已写入 KV: 0-4095
  本轮追加: 4096-8191
  后续继续: 8192-...

3.3 输入分桶

输入分桶按 prompt 长度、effective prefill token 或业务类型把请求送入不同队列。它减少同批请求长度差异,降低 padding、shape 抖动和调度不确定性。

Chunked Prefill 和输入分桶的作用层不同:

机制控制对象主要收益
输入分桶请求进入哪个队列 / worker / batch让同批 shape 更接近
Chunked Prefill单个长请求每轮执行多少 token降低长 prefill 的不可抢占时间

3.4 Prefix Cache

原始 ISL 不等于真实要算的 prefill token。system prompt 复用、RAG 前缀共享和多轮 agent 都可能命中 prefix cache。

raw ISL = 32K
prefix hit = 28K
effective prefill = 4K

这种请求不应简单按 32K 长 prompt 处理。更合理的调度特征是 effective prefill tokens,再加上 KV load latency。

4. 方法:Chunked Prefill 在调度器里做什么

不同框架的参数名不同,但核心抽象相同:每轮 scheduler 有一个 token budget。

4.1 vLLM 抽象

vLLM V1 scheduler 维护每个请求已经计算到哪里:

request.num_computed_tokens
request.num_tokens / request.num_tokens_with_spec

每轮调度时,chunk 大小来自剩余 token 和本轮 token budget:

remaining = request.num_tokens - request.num_computed_tokens
num_scheduled_tokens = min(remaining, token_budget)

如果 enable_chunked_prefill=false,而一个 waiting request 的 remaining 大于本轮 token budget,scheduler 会停在这个请求上,不继续往后调度短请求。打开 chunked prefill 后,scheduler 可以只安排这个长请求的一段 token,把剩余 budget 留给后面的请求。

所以源码里的 chunk size 更接近:

本轮 token_budget 中分给某个 request 的 num_scheduled_tokens

它不是模型配置里的 seq_len,也不是 hidden_size

vLLM 中相关调参项包括:

参数作用
max_num_batched_tokens单轮 token budget,直接影响 partial prefill 粒度
max_num_seqs单轮最多 sequence 数,影响 decode batch 宽度
max_num_partial_prefills允许多少个请求同时处于 partial prefill 状态
max_long_partial_prefills限制长 prompt 的 partial prefill 并发数
long_prefill_token_threshold区分长 prompt 和短 prompt 的阈值

4.2 TensorRT-LLM 抽象

TensorRT-LLM 常把这个能力叫 chunked contextchunked prefill。它和 max_num_tokens、paged KV cache、in-flight batching 绑定:

max_num_tokens = 单轮 scheduler token budget
tokens_per_block = KV cache block 粒度
chunked context = 长 prompt 可以只调度第一个 chunk

这带来两个结果:

  • max_num_tokens 不必大到覆盖最长 prompt;
  • activation / workspace 的单轮峰值受控,省下的 memory budget 可以给 KV cache,提高并发或长上下文容量。

4.3 Decode Piggyback

Sarathi-Serve 的关键点是把 decode token piggyback 到 prefill chunk 上。decode-only batch 往往 GPU 利用率低,而 prefill chunk 是 compute-bound。混合执行可以让 decode 共享更饱满的 kernel shape:

只做 decode:
  batch_tokens = active_decode_requests
  M 维度小,访存主导

prefill chunk + decode:
  batch_tokens = prefill_chunk_tokens + active_decode_requests
  M 维度变大,GPU 利用率更高

这也是 chunk size 不能只按延迟调的原因。它同时影响 kernel shape 和 GPU 利用率。

5. 性能模型:Chunk Size 如何影响底层计算

设一个请求的总输入长度为 N,第 i 个 chunk 新处理 C_i 个 token,之前已经写入 KV cache 的 token 数为 P_i

5.1 Attention Shape

Prefill chunk 的 causal attention 不只看 chunk 内部 token。新 token 还要 attend 到过去已经写入 KV cache 的 token:

Q_len = C_i
K_len = P_i + C_i
attention work ≈ C_i * P_i + C_i * C_i / 2

含义:

  • chunk 越靠后,P_i 越大;
  • 即使 C_i 固定,后面的 chunk attention 也更重;
  • 总 attention work 理论上和完整 prefill 接近,切块主要改变执行粒度和 kernel shape。

如果有 prefix cache hit,命中的 prefix 不需要重新算 FFN 和 attention 输出,但 suffix token 仍然要 attend 到 cached prefix:

Q_len = suffix_chunk
K_len = cached_prefix + previous_suffix + suffix_chunk

所以 KV hit 后 attention 不一定按 1-h 线性下降,详见 Causal Attention 与 KV hit 面积模型

5.2 GEMM / MLP / MoE Shape

Transformer block 里除了 attention,还有大量 MLP / MoE 计算。对 dense FFN 来说,chunk size 主要决定 GEMM 的 M 维度:

X: [batch_tokens, hidden]
W: [hidden, intermediate]
Y: [batch_tokens, intermediate]

其中 batch_tokens 近似等于本轮所有 prefill token 加上 decode token。

影响:

  • C 太小:GEMM 的 M 维度小,Tensor Core 利用率可能下降;
  • C 变大:GEMM 更饱满,但单轮占用时间变长;
  • 多个短 prompt 合批:可能比单个小 chunk 更能撑大 M 维度;
  • MoE 模型还要看 expert routing 后每个 expert 的 token 数,chunk 太小会让 grouped GEMM 变碎。

5.3 Seq Len、Batch 和 Hidden 的关系

每轮执行可以看成一组 tensor shape:

prefill attention:
  Q = [num_q_tokens, num_heads, head_dim]
  K/V = [num_kv_tokens, num_kv_heads, head_dim]

FFN / dense GEMM:
  M = num_tokens_this_iteration
  N/K = hidden/intermediate dimensions

decode attention:
  Q_len 通常是 1
  K_len 是当前上下文长度

对应关系:

维度含义是否随请求变化
hidden_size模型固定宽度不变
num_scheduled_tokens某 request 本轮新算 token 数,也就是该 request 的 Q_len
total_num_scheduled_tokens本轮所有 request/chunk 的 token 总数
seq_lens每个 request 算完本轮后的上下文长度,也就是 attention 的 K_len 边界
block_table每个 request 的 paged KV 地址表

性能不是由“总 token 数”单独决定,而是由这些 shape 决定。

5.4 Chunk Size 的权衡

目标倾向的 chunk size原因
降低 decode ITL / TPOT P99小 chunk单次 prefill 占用 GPU 的连续时间短,decode 更快被调度
降低 TTFT大 chunk一个请求更快完成全部 prefill,少走几轮调度
提高峰值吞吐中到大 chunkprefill GEMM / attention 形状更大,GPU 利用率更高,launch 占比更低
支持长上下文和高并发小到中 chunkactivation 峰值和单轮 token budget 受控,KV cache 能留更多空间

6. 调度策略:Bucket、Backlog 和 Prefix Hit

6.1 Bucket-aware Chunk Size

不同输入桶可以用不同 chunk size:

输入桶倾向策略
短 prompt不切或大 chunk,优先 TTFT
中等 prompt中等 chunk,兼顾 TTFT 和 ITL
长 prompt小到中 chunk,保护 decode tail latency
超长 prompt小 chunk + admission control,避免占满 KV cache

6.2 Decode-backlog-aware Chunk Size

同一个输入桶里,也可以根据 decode backlog 动态调 chunk:

decode backlog 高:
  chunk size 变小
  更频繁让 decode step 执行

decode backlog 低:
  chunk size 变大
  尽快完成 prefill,提高 TTFT 和吞吐

这个策略比固定 chunk size 更接近线上目标,因为 chunked prefill 的根因是 prefill/decode 干扰,而干扰强度取决于当时有多少 decode 请求在等。

6.3 Prefix-hit-aware Scheduling

effective_prefill_tokens 作为调度特征:

effective_prefill_tokens =
  raw_input_tokens - reusable_prefix_tokens + kv_load_penalty_as_tokens

命中高的长 prompt 不应该被简单当作长 prefill 请求。

6.4 Bucket-aware Admission

输入分桶不只决定请求去哪排队,还可以决定是否允许新长 prompt 进入当前 decode-heavy worker:

decode backlog 高 + 长 prompt:
  延迟 admission 或路由到 prefill 更空的 worker

decode backlog 低 + 长 prompt:
  允许大 chunk 快速完成 prefill

7. 源码路径:以 vLLM 为例

7.1 Scheduler 输出每个请求本轮推进多少 token

scheduler 输出的是每个 request 本轮要推进多少 token:

A: 3072 tokens
B: 512 tokens
C: 512 tokens

这三个请求可以同时进入一次 model forward。这里的“同时”不是让请求共享上下文,而是共享一次批处理执行。

7.2 Model Runner Flatten 输入

model runner 会把本轮 token flatten 成连续输入:

total_num_scheduled_tokens = 4096
input_ids: [4096]
positions: [4096]
hidden states after embedding: [4096, hidden_size]

同时保留 request 边界:

query_start_loc = [0, 3072, 3584, 4096]
seq_lens[A] = A.num_computed_tokens + 3072
seq_lens[B] = B.num_computed_tokens + 512
seq_lens[C] = C.num_computed_tokens + 512
block_table / slot_mapping = 每个 request 自己的 KV blocks

GEMM/MLP/MoE 可以把多个请求的 token 合在一起算,所以更关心 total_num_scheduled_tokens x hidden_size。Attention 不能跨用户混看,它依赖 query_start_locseq_lensblock_table 保证 A 只 attend A 的 KV,B 只 attend B 的 KV。

7.3 Attention Backend 的 plan/run

BatchPrefillWithPagedKVCacheWrapper.plan/run 属于 FlashInfer paged prefill attention,不是 vLLM scheduler 的计划。

可以分两层看:

vLLM scheduler:
  选哪些 request/chunk 进本轮 forward
  决定每个 request 的 num_scheduled_tokens

FlashInfer prefill wrapper:
  plan: 根据本轮 ragged/paged shape 准备 attention 元数据
  run: 运行 paged KV causal prefill attention kernel

plan 需要处理动态形状:

query_start_loc / qo_indptr
kv_page_indptr
kv_page_indices
kv_last_page_len
causal mask
每个 request 的 Q_len / K_len
kernel tiling / workspace

run 执行 attention:

attention(Q_chunk, paged_KV_cache)

chunk 太小会增加的不只是 scheduler 次数,还会增加 attention backend 的 plan/run 次数、KV block 元数据准备次数和 host/runtime 开销。

8. Trace 证据:Qwen3.5 Plus GB300 Prefill

8.1 观测结果

在一个 GB300 prefill trace 中,可以观察到:

GPUModelRunner._model_forward: 65 次
前 64 个已采集 step: BatchPrefillWithPagedKVCacheWrapper.plan/run = 15/15
前 64 个已采集 step: HybridConnector.save_kv_layer = 60
最后一个已采集 step: plan/run = 2/2, save_kv_layer = 11

结合 Qwen3.5 Plus 的模型配置:

layers = 60
hidden_size = 4096
attention_heads = 32
kv_heads = 2

15 plan/run 更像模型结构信号,不是 chunk token 数。

8.2 模型结构解释

trace 里能看到一个重复结构:

FlashAttentionImpl.forward * 1
inner_fn * 1
(Qwen3NextGatedDeltaNet._forward_core + inner_fn) * 3

这对应一个 4 层 group:

1 层 full attention
3 层 GatedDeltaNet / GDN

60 层模型就有:

60 / 4 = 15 个 full attention layer
45 个 GDN layer

trace 的 GDN kernel 计数也能对上:

GDN chunked kernel 总数 = 2895
45 * 64 + 15 = 2895

因此一个完整 prefill step 更准确地描述为:

跑完整 60 层模型
  15 层 full attention -> FlashInfer BatchPrefill plan/run
  45 层 GDN / linear-attention-like path -> GDN chunked kernel
  60 层都触发 KV/state save hook

8.3 inner_fn 是什么

trace 里的 inner_fn 不是模型里的语义模块名。它是 torch.compile / Inductor / PiecewiseBackend 包出来的 compiled graph 入口。

在 Qwen3.5 Plus 的 trace 里,一个典型 inner_fn 下面包含:

moe_forward_shared
SharedFusedMoE.forward_impl
ModelOptNvFp4FusedMoE.apply
flashinfer_trtllm_fp4_moe
Qwen2MoeMLP.forward
ReplicatedLinear.forward
MergedColumnParallelLinear.forward
SiluAndMul.forward
RowParallelLinear.forward
Linear.forward

所以它不是 attention,也不是 scheduler。它主要覆盖 MoE/MLP 子图:

shared MLP/expert:
  up/gate projection -> SiLU * gate -> down projection

routed MoE:
  token routing -> FP4/FP8 fused MoE kernel -> combine

这说明 chunked prefill 的单步成本不只由 full attention 决定。对 hybrid MoE 模型,还要看 GDN、shared MLP、routed MoE、量化和 KV/state 保存。

8.4 证据边界

这份 trace 的 JSON 和 gzip 文件是完整的,但采集窗口几乎贴着最后一次 execute_model 结束:

最后一次 GPUModelRunner.execute_model 距 trace 末尾: 0.035 ms
最后一次 WorkerWrapperBase.execute_model 距 trace 末尾: 0 ms

因此最后一个已采集 step 的 2/2 plan/run + 11 save_kv_layer 只能说明:

采集窗口内最后一个 step 明显小于前 64 个完整 step

不能单独断言:

它一定是整个请求的最终 tail chunk

要确认最终 tail chunk,需要补充:

request_id
chunk_id
token_range
num_scheduled_tokens
num_computed_tokens
seq_len
prefill_done / kv_send_done

没有这些字段时,trace 能证明“有重复 chunked prefill step”,但不能精确还原绝对 chunk size。

9. 实验设计:如何找到合适 Chunk Size

第一轮实验不要直接在线上全量调。先做小矩阵,把机制跑清楚:

变量建议取值观察目标
chunk size / token budget512 / 1024 / 2048 / 4096 / 8192TTFT 与 ITL 的拐点
输入长度桶0-1K / 1-4K / 4-16K / 16K+分桶后每桶最佳 chunk 是否不同
并发低 / 中 / 高decode backlog 对最佳 chunk 的影响
OSL短输出 / 中输出 / 长输出decode 占比越高,越需要保护 ITL
prefix hit0% / 50% / 90%effective prefill 缩短后是否要调大 chunk
max_num_seqs小 / 默认 / 大decode batch 宽度和 KV memory 的权衡
GPU 类型H20 / A100 / H100 / B200算力、HBM、kernel launch 占比不同
模型类型dense / MoE / hybrid attentionexpert batch、KV layout、attention kernel 差异

至少看这些指标:

层级指标解释
用户体验TTFT P50/P95/P99chunk 太小可能拉高 TTFT
流式输出ITL / TPOT P50/P95/P99chunked prefill 的主要保护对象
调度器scheduling gapdecode step 之间是否被 prefill 拉开
吞吐tokens/s/GPU、SLO QPSchunk 太小可能降低总吞吐
GPUSM active、Tensor Core utilization、HBM bandwidth判断 compute-bound / memory-bound
KernelGEMM M 维、attention Q/K shape、kernel duration判断 chunk 是否太碎
KVKV blocks allocated、fragmentation、swap/offload判断 long context 并发是否受 KV 限制
Prefix cachehit tokens、miss tokens、KV load latency判断 effective prefill 是否变短

推荐先画四张图:

chunk size -> TTFT P99
chunk size -> TPOT/ITL P99
chunk size -> tokens/s/GPU
chunk size -> prefill kernel duration + decode scheduling gap

判断规则:

  • chunk size 变小后 ITL P99 没改善:问题可能不在 prefill 插队,或者 decode backlog 不高;
  • TTFT 大幅变差但 ITL 只小幅变好:chunk 过小;
  • tokens/s/GPU 明显下降:kernel shape 太碎,或 plan/run、KV block 管理、launch 开销占比过高;
  • MoE grouped GEMM 时间上升:expert token group 可能太小。

Trace 里最好补这些字段:

request_id
sequence_id
phase = prefill | decode
chunk_id
chunk_start_token
chunk_end_token
past_kv_tokens
prefix_hit_tokens
scheduled_token_count
batch_num_seqs
batch_num_tokens
kernel_name
kernel_duration

10. 讨论:P/D 分离下 Chunked Prefill 的意义

Chunked Prefill 和 P/D 分离都源于同一个事实:prefill 和 decode 的资源需求不同。

方案适用情况代价
Chunked Prefill单实例或同池混部,想降低 prefill 对 decode 的阻塞调参复杂,TTFT/ITL 权衡明显
P/D 分离长 prompt、长输出、tail latency 敏感,资源池足够大KV transfer、路由、扩缩容和故障恢复复杂
二者组合prefill pool 内仍有长短请求干扰,或 KV 发送需要分段控制需要更完整的 scheduler 和 KV 生命周期观测

在非 P/D 场景,chunked prefill 的主要价值是保护 decode:

长 prefill chunk 之间插入 decode step

在 P/D 分离场景,decode 不再和 prefill 同池争 GPU,chunked prefill 的价值发生变化:

场景Chunked Prefill 的作用
Prefill pool 内混有长短 prompt防止一个超长 prompt 阻塞短 prompt 的 TTFT
KV transfer 需要分段让 prefill 计算、KV 写入和 KV 发送形成更细粒度流水
activation/workspace 峰值受限限制单轮 context token 数,给 KV cache 或并发留空间
prefix cache hit 差异大按 effective prefill tokens 调度,而不是按 raw ISL
tail chunk 很小避免最后小 chunk 造成低效 kernel 或不必要的同步

所以 P/D 分离后,chunked prefill 不再主要解决“decode 被 prefill 卡住”,而是解决 prefill pool 的公平性、资源峰值和 KV 生命周期粒度。

11. 局限与常见误区

11.1 把 Chunked Prefill 当成 Prefill 加速

它主要是调度优化。完整处理同一个 prompt 时,总计算量不会凭空减少。

真正减少 prefill 计算的机制是:

  • prefix cache / RadixAttention;
  • prompt 压缩;
  • KV cache reuse;
  • 更快的 attention / GEMM kernel;
  • 量化或低精度计算。

11.2 只按原始 ISL 分桶

原始 ISL 不等于 effective prefill。prefix hit、system prompt 复用、RAG 前缀共享都会改变真实需要计算的 token 数。

11.3 固定 Chunk Size 套所有 Workload

短 prompt、长 prompt、长输出 reasoning、短输出分类、多轮 agent 的最佳 chunk 不一样。固定值只能当起点。

11.4 只看吞吐,不看 Tail

大 chunk 可能让 tokens/s/GPU 好看,但把 ITL P99 拉坏。对流式输出服务,ITL P99 往往比平均吞吐更接近用户体验。

11.5 忽略 MoE Expert Batch

Dense 模型上有效的 chunk size,放到 MoE 模型上可能让每个 expert 的 token group 太小,导致 grouped GEMM 和 all-to-all 效率下降。

11.6 把 plan/run 次数误读成 Chunk Size

BatchPrefillWithPagedKVCacheWrapper.plan/run 的次数常常和模型结构有关。Qwen3.5 Plus trace 里的 15 plan/run 对应 60 层模型中的 15 个 full attention layer,而不是每个 chunk 有 15 个 token 或 15 个请求。

如果要看 chunk size,需要 scheduler 侧的 num_scheduled_tokenstoken_range 或运行参数中的 token budget。

12. 后续优化方向

12.1 动态 Chunk Size

根据实时状态调 chunk:

chunk_size = f(
  decode_backlog,
  prefill_queue_length,
  prompt_bucket,
  prefix_hit_tokens,
  current_kv_free_blocks,
  recent_itl_p99
)

第一版可以只用 decode backlog 和输入桶,避免规则过复杂。

12.2 MoE-aware Chunk Policy

MoE 模型可以观察每个 expert 的 token group:

expert_tokens_p50
expert_tokens_p95
num_active_experts
dispatch_combine_time
grouped_gemm_time

如果 chunk 变小后 expert group 过碎,可以给 MoE 模型设置更大的 chunk 下限,或者按 expert load 动态调整。

12.3 Trace-driven Simulator Calibration

把 chunk size 纳入模拟器,不要只建模总 prefill time:

prefill_time(request) =
  sum(chunk_compute_time(C_i, P_i, batch_shape_i))
  + scheduler_overhead_per_chunk
  + kv_block_overhead_per_chunk

decode_delay =
  sum(prefill_chunk_duration inserted before decode step)

这样才能解释为什么两个配置总 prefill FLOPs 接近,但 ITL P99 差很多。

12.4 KV Lifecycle Observability

在 P/D 分离或 prefix cache 场景,trace 需要覆盖 KV 生命周期:

prefill chunk done
kv block allocated
kv block filled
kv block sent
decode side kv received
decode first token ready

否则只能看到模型 forward,无法判断瓶颈在 prefill compute、KV transfer、decode admission 还是 cache lookup。

13. 参考资料

相关页面

修改历史3 次提交