首页
/ vLLM 优化级别详解:-O0 到 -O3 的启动时间与性能权衡机制

vLLM 优化级别详解:-O0 到 -O3 的启动时间与性能权衡机制

2026-09-04 12:24:19作者:咎竹峻Karen

本文基于 vLLM 仓库的设计文档 optimization_levels.md,系统讲解 vLLM 提供的四个优化级别(-O0-O1-O2-O3):它们分别如何设置编译模式、CUDA Graph 模式与算子融合开关,以及这些默认值在源码中的实际应用逻辑。读完后你将掌握如何在 CLI 与 Python API 中切换优化级别、理解各级别背后的配置差异,并能根据启动时间或运行性能目标做出合理选择。

概述:用启动时间换性能

vLLM 提供 4 个优化级别(-O0-O1-O2-O3),核心思想是让用户在启动时间运行性能之间自行权衡:

级别 定位 说明
-O0 不优化 启动最快,性能最低
-O1 快速优化 简单编译与快速融合,PIECEWISE CUDA Graph
-O2 完整优化(默认 更多编译范围与融合,FULL_AND_PIECEWISE CUDA Graph
-O3 激进优化 当前与 -O2 等价,未来可能纳入更耗时或实验性的优化

文档中给出了两条关键规则,源码同样印证了这一点:

  1. 所有优化级别的默认值都可以手工设置底层参数来等价实现——优化级别只是底层 flag 的预设组合,并非黑盒;
  2. 用户显式设置的 flag 优先于优化级别默认值——你手动指定的 --compilation-config 等参数不会被 -O 级别覆盖。

对应实现位于 vllm/config/vllm.pyOptimizationLevel 是一个 IntEnumO0 = 0O1 = 1O2 = 2O3 = 3),VllmConfigoptimization_level 字段默认值即为 OptimizationLevel.O2,这正是"生产环境默认走完整优化"的体现。

使用方式:CLI 与 Python API

文档给出的两种标准用法如下,均可直接复制使用:

# CLI 用法:vllm serve 支持 -O 简写(等价于 --optimization-level)
vllm serve RedHatAI/Llama-3.2-1B-FP8 -O1
# Python API 用法
from vllm.entrypoints.llm import LLM

llm = LLM(
    model="RedHatAI/Llama-3.2-1B-FP8",
    optimization_level=2,  # 等价于 -O2
)

从源码看,-O 简写并非独立的参数,而是由 vllm/utils/argparse_utils.py 在参数预处理阶段重写为标准的 --optimization-level <n> 形式:

elif arg.startswith("-O") and arg != "-O":
    # allow -O flag to be used without space, e.g. -O3 or -Odecode
    # also handle -O=<optimization_level> here
    optimization_level = arg[3:] if arg[2] == "=" else arg[2:]
    processed_args += ["--optimization-level", optimization_level]

-O1-O 1-O=1 三种写法都会被归一化处理。该参数在 vllm/engine/arg_utils.py 中注册(--optimization-level),并在 EngineArgs 中声明,默认值直接取自 VllmConfig.optimization_levelvllm/engine/arg_utils.py#L753),保证了 CLI 与 Python API 的默认行为一致。

各级别详解:默认配置逐项拆解

下面结合源码中 OPTIMIZATION_LEVEL_00OPTIMIZATION_LEVEL_03 四个配置字典(vllm/config/vllm.py#L240-L338)逐级展开。文档列出的设置是核心骨架,源码中还包含若干文档未逐一列举的 pass_config 开关(如 fuse_attn_quantenable_spfuse_gemm_comms),一并说明以保证完整性。

-O0:不优化(No Optimization)

目标是尽可能快地启动:不做 autotuning、不做编译、不使用 CUDA Graph。适合开发初期的调试阶段。

文档列出的设置:

  • -cc.cudagraph_mode=NONE
  • -cc.mode=NONE(同时导致 -cc.custom_ops=["none"]
  • -cc.pass_config.fuse_...=False(所有融合禁用)
  • --kernel-config.enable_flashinfer_autotune=False

源码中 OPTIMIZATION_LEVEL_00 与上述一一对应:cudagraph_mode 设为 CUDAGraphMode.NONEenable_flashinfer_autotuneFalse,且 pass_config 下全部融合开关(fuse_norm_quantfuse_act_quantfuse_allreduce_rmsfuse_attn_quantenable_spfuse_gemm_commsfuse_act_paddingfuse_mla_dual_rms_normfuse_rope_kvcachefuse_qk_norm_rope_kvcacheenable_qk_norm_rope_fusionfuse_rope_kvcache_cat_mla)均为 False

关于"同时导致 custom_ops=["none"]"这一细节,vllm/config/vllm.py#L1436-L1456 中有两条联动逻辑:

  1. 若用户未显式指定 compilation_config.mode,则当 optimization_level > O0 时自动置为 CompilationMode.VLLM_COMPILE,否则置为 CompilationMode.NONE——这就是 O0 下"无编译"的来源;
  2. custom_ops 中没有 "all" 也没有 "none" 时,若 backend 为 inductor 且 mode 非 NONE,则默认追加 "none",否则追加 "all"——因此 O0(mode=NONE)下 custom ops 被整体关闭,而 O1/O2 下才会启用全部自定义 kernel。

-O1:快速优化(Fast Optimization)

优先快速启动,但仍启用基础优化:编译与 PIECEWISE 粒度的 CUDA Graph。文档定位为大多数开发场景的平衡点——既加快启动,又能尽早暴露会破坏 CUDA Graph 或编译路径的代码问题。

文档列出的设置:

  • -cc.cudagraph_mode=PIECEWISE
  • -cc.mode=VLLM_COMPILE
  • --kernel-config.enable_flashinfer_autotune=True

融合开关(源码中并非简单置 True,而是由条件函数在运行时决定,见下文"条件启用的融合"一节):

  • -cc.pass_config.fuse_norm_quant=True*
  • -cc.pass_config.fuse_act_quant=True*
  • -cc.pass_config.fuse_act_padding=True
  • -cc.pass_config.fuse_mla_dual_rms_norm=True

文档脚注:

  • * 这些融合仅在对应算子使用了自定义 kernel 时才启用,否则 Inductor 自身的融合效果更好;
  • † 这些融合是 ROCm 专属且依赖 AITER。

对应源码中 OPTIMIZATION_LEVEL_01 的写法正是把条件函数(enable_norm_fusionenable_act_fusionenable_norm_pad_fusionenable_mla_dual_rms_norm_fusion)而非常量塞进 pass_configcudagraph_modeCUDAGraphMode.PIECEWISEenable_flashinfer_autotuneTrue

-O2:完整优化(Full Optimization,默认级别)

以额外启动时间换性能。文档明确推荐生产工作负载使用此级别,这也是默认值;并提醒此级别下的融合可能因为引入更多编译范围而耗时更久。

-O1 基础上的额外设置:

  • -cc.cudagraph_mode=FULL_AND_PIECEWISE
  • -cc.pass_config.fuse_allreduce_rms=True
  • -cc.pass_config.fuse_rope_kvcache=True

† 该融合为 ROCm 专属且依赖 AITER。

对照 OPTIMIZATION_LEVEL_02vllm/config/vllm.py#L286-L308),它相对 O1 的差异还包括:

  • fuse_allreduce_rmsFalse 变为条件函数 enable_allreduce_rms_fusion:要求 TP > 1,且在 CUDA 上需要 flashinfer 已安装、设备为 Hopper(capability 90)或 Blackwell(capability family 100),ROCm 上则要求 AITER 开启;该路径同时被 VLLM_BATCH_INVARIANT 环境变量抑制(因为融合路径不具备 batch 不变性);
  • fuse_attn_quantenable_spfuse_gemm_comms 分别绑定 IS_QUANTIZEDIS_DENSE 两个占位常量——从源码结构看,这两个属性目前对所有情况都置为 Falsevllm/config/vllm.py#L128-L135 有注释说明相关优化依赖 model_config 的量化/MoE 属性,属于预留接口),因此当前版本这三项实际不生效;
  • 其余 ROCm/MLA 相关融合(fuse_rope_kvcachefuse_qk_norm_rope_kvcachefuse_rope_kvcache_cat_mla)也换成了条件函数。

-O3:激进优化(Aggressive Optimization)

文档说明:当前与 -O2 完全相同,未来可能纳入更耗时或实验性的优化。源码中 OPTIMIZATION_LEVEL_03 的内容与 OPTIMIZATION_LEVEL_02 逐项一致(vllm/config/vllm.py#L309-L331),印证了文档描述。可以推断,O3 存在的意义在于为后续实验性优化预留一个不破坏现有默认行为的"升级通道"。

源码机制:默认值如何被应用,用户参数如何取胜

优化级别并非"强制覆盖",其应用逻辑在 vllm/config/vllm.py#L902-L929_apply_optimization_level_defaults 中实现:

def _set_config_default(self, config_obj, key, value):
    if getattr(config_obj, key) is None:
        # 用户未设置(仍为 None)时才填入默认值
        setattr(config_obj, key, value(self) if callable(value) else value)

流程要点:

  1. _post_init 阶段先按平台/用户配置完成所有用户显式设置的落盘;
  2. 随后取出 OPTIMIZATION_LEVEL_TO_CONFIG[self.optimization_level]vllm/config/vllm.py#L1463-L1464),递归地把默认值写入各嵌套配置对象(compilation_config.pass_configkernel_config 等);
  3. 关键约束:只有当前字段仍为 None(即用户未显式指定)时默认值才会生效——这正是文档"User-set flags take precedence over optimization level defaults"的实现。

条件启用的融合(fuse_norm_quant 等带 * 项)则是把可调用对象存入配置字典,应用默认值时才以当前 VllmConfig 为入参求值。以 enable_norm_fusion 为例(vllm/config/vllm.py#L138-L146):仅当 rms_normquant_fp8 自定义算子被启用、或 rms_norm 的 IR op 优先级不是 native 时才开启,否则交给 Inductor 融合——与文档脚注的解释完全一致。

相关底层概念速查

理解各级别差异还需要两个背景概念:

CUDA Graph 模式CUDAGraphMode 枚举定义于 vllm/config/compilation.py#L53-L63,取值为 NONE(0)、PIECEWISE(1)、FULL(2),另有组合形式 FULL_AND_PIECEWISE = (FULL, PIECEWISE)。PIECEWISE 对编译图做分段捕获、捕获成本低;FULL 额外对整个解码路径做全图捕获、启动更慢但性能更好——这正是 O1 与 O2 的核心差别。

编译模式与 custom ops 的联动:如前文 -O0 一节所述,mode=NONE 时 custom ops 默认为 "none"。此外 vllm/config/vllm.py#L1404-L1415 有一条保护逻辑:若用户通过其他设置禁用了 Inductor 编译,引擎会告警"仅在 inductor 编译期间生效的优化设置将被忽略",避免配置静默失效。

故障排查(Troubleshooting)

文档"Common Issues"一节给出的三条建议,对应到具体操作如下:

  1. 启动时间过长(Startup Time Too Long):改用 -O0-O1 换取更快启动;
  2. 编译错误(Compilation Errors):设置 debug_dump_path 以获取额外的调试信息;
  3. 性能问题(Performance Issues):确保生产环境使用默认的 -O2,不要为了启动速度牺牲稳态吞吐。

小结

  • 优化级别是底层 flag 的预设组合:-O0 关编译、关 CUDA Graph、关全部融合与 autotune;-O1 加 VLLM_COMPILE + PIECEWISE + 基础融合;-O2(默认)再加 FULL_AND_PIECEWISE 与 allreduce/RMSNorm 等高级融合;-O3 当前等同 -O2
  • 默认值只在用户未显式配置对应字段时生效,_apply_optimization_level_defaults 保证了用户参数优先级;
  • 所有细节可以在 vllm/config/vllm.py 中逐字段核对:级别枚举与配置字典(L111-L338)、默认值应用逻辑(L887-L929)、编译模式联动(L1436-L1485);CLI 参数入口见 vllm/engine/arg_utils.pyvllm/utils/argparse_utils.py
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
982
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384