跳转至

动态分块流水线并行(CPP)

CPP 使用基于性能剖析的动态分块来均衡每个分块的延迟,并消除 PP 场景中的流水线气泡。

背景

问题陈述

在流水线并行(PP)+ 分块预填充(Chunked Prefill)场景中,长序列被拆分为固定大小的分块,并依次通过流水线。由于 Self-Attention 的 O(n²) 计算复杂度,相同大小的分块随着前缀序列增长,处理时间越来越长:

Chunk 1 (history=0):     ██████         → Time T1
Chunk 2 (history=4k):    ████████       → Time T2 > T1
Chunk 3 (history=8k):    ██████████     → Time T3 > T2
Chunk 4 (history=12k):   ████████████   → Time T4 > T3

这种时间差异会跨流水线阶段传播,导致空闲等待(流水线气泡)增加,并显著降低 GPU 利用率。

解决方案概述

动态分块流水线并行采用先剖析、后预测策略:

Fixed Chunking (equal chunk size, unequal time):

          Stage 0  |■■■■|■■■■■■|■■■■■■■■|■■■■■■■■■■|
          Stage 1  |    |■■■■  |■■■■■■  |■■■■■■■■  |■■■■■■■■■■|
                        ↑ bubble  ↑ bubble   ↑ bubble

Dynamic Chunking (unequal chunk size, equal time):

          Stage 0  |■■■■■■|■■■■■■|■■■■■■|■■■■■■|
          Stage 1  |      |■■■■■■|■■■■■■|■■■■■■|■■■■■■|
                          ↑ no bubble — stages stay in sync

核心思想借鉴自 SGLang 的动态分块机制,并增加了在线校准等增强功能。

设计

二次延迟模型

由于 O(n²) Self-Attention 机制,Transformer 预填充延迟随序列长度呈二次增长:

$$f(l) = a \cdot l^2 + b \cdot l + c$$

其中:

  • $a \cdot l^2$:注意力开销(二次项)
  • $b \cdot l$:线性操作(FFN、投影)
  • $c$:固定开销(内核启动)

启动阶段:性能剖析

在引擎初始化期间,系统会对实际模型性能进行剖析:

  1. 采样:从 base_chunk_size 到接近 0 均匀采样 64 个不同的分块大小
  2. 执行:对每个分块大小执行真实模型前向传播,并精确测量延迟(毫秒)
  3. 拟合:使用最小二乘法拟合二次模型
  4. 目标设置:基于 base_chunk_size 计算每个分块的目标延迟

在 PP 模式下,所有工作节点都会执行前向传播以保持同步,但仅使用第一个 PP rank 的计时结果用于调度决策。

运行时阶段:动态预测

给定当前前缀长度 $L$ 和目标延迟 $T = f(\text{base_chunk_size}) - f(0)$,系统求解下一个分块大小 $x$:

$$f(L + x) - f(L) = T$$

展开为:

$$a \cdot x^2 + (2aL + b) \cdot x - T = 0$$

使用求根公式求解:

$$x = \frac{-(2aL + b) + \sqrt{(2aL + b)^2 + 4aT}}{2a}$$

结果经过后处理:

  1. 平滑:使用 smooth_factor 将预测分块大小与 base_chunk_size 进行混合
  2. 对齐:向下取整到 page_size 的倍数(最小 64)
  3. 约束:不超过 max_model_len - history_len 和 max_num_scheduled_tokens

在线校准

由于性能剖析仅覆盖长度不超过 max_num_batched_tokens 的序列(通常短于真实工作负载),系统会在运行时持续优化模型。

扩展模型(两个变量):

$$f(C, H) = a \cdot C(C+H) + b \cdot (C+H) + c$$

其中 $C$ 是分块大小,$H$ 是前缀历史长度。

每个批次后,记录特征向量 [Σ(C+H)·C, Σ(C+H), N] 和实际执行时间。当积累足够的数据点(5-30)后,使用最小二乘法更新模型参数。

架构

关键组件

组件 位置 职责
ChunkSizePredictor vllm_ascend/core/profiling_chunk_predictor.py 二次模型拟合与预测
ProfilingChunkManager vllm_ascend/core/profiling_chunk_predictor.py 管理剖析工作流和预测器
Scheduler vllm_ascend/core/scheduler_profiling_chunk.py 集成 CPP 调度
EngineCore vllm_ascend/patch/platform/patch_profiling_chunk.py 启动剖析,记录执行时间
NPUWorker vllm_ascend/worker/worker.py 执行真实前向传播剖析
NPUModelRunner vllm_ascend/worker/model_runner_v1.py profile_cpp=True 模式

工作流

┌─────────────────────────────────────────────────────────────┐
│                    Startup Phase                            │
├─────────────────────────────────────────────────────────────┤
│  1. EngineCore.init() triggers profiling                    │
│  2. ProfilingChunkManager samples 64 chunk sizes            │
│  3. NPUWorker executes forward passes                       │
│  4. ChunkSizePredictor fits quadratic model                 │
│  5. Target latency = f(base_chunk_size) - f(0)              │
└─────────────────────────────────────────────────────────────┘
                           ↓
┌─────────────────────────────────────────────────────────────┐
│                    Runtime Phase                            │
├─────────────────────────────────────────────────────────────┤
│  For each prefill chunk:                                    │
│    1. Scheduler queries ChunkSizePredictor                  │
│    2. Given history length L, solve for optimal chunk size  │
│    3. Apply smoothing and alignment                         │
│    4. Execute chunk                                         │
│    5. Record actual timing for online calibration           │
│    6. Update model if enough samples collected              │
└─────────────────────────────────────────────────────────────┘

与 SGLang 的比较

特性 SGLang 动态分块 动态分块流水线并行
特性 SGLang 动态分块 动态分块流水线并行
性能分析方法 预设二次函数 启动时真实前向传播性能分析
模型拟合 $f(l) = a \cdot l^2 + b \cdot l + c$ 相同 + 在线校准 $f(C,H)$
在线更新 无 基于历史的拟合
准确性 在不同硬件上可能存在偏差 适应实际硬件性能
启动成本 无 约 64 次前向传播(数十秒)

约束

  • 需要流水线并行:必须设置 --pipeline-parallel-size > 1
  • 需要分块预填充:必须启用 --enable-chunked-prefill
  • 与平衡调度不兼容:无法启用 additional_config.scheduler_config.enable_balance_scheduling
  • 启动开销:性能分析阶段会使初始化增加数十秒
  • 内存:无额外运行时内存开销;性能分析复用现有 dummy_run 机制

参考资料

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 vl/vllm-ascend