执行摘要
- 一句话:EngineCore 跨 NUMA 节点绑定 + PCT 自动绑定
- 推荐动作:建议精读此 PR,特别是 PCT 自动检测的巧妙设计(无 root 权限利用
acpi_cppc/highest_perf 和 CPUID 模式)以及 EngineCore 与 Worker 绑定分离的架构决策。该 PR 展示了为特殊硬件(DGX B300)进行零配置优化的良好实践。
功能与动机
在双路 NUMA 系统中,EngineCore 作为所有 TP/PP Worker 的父进程,之前只绑定到首个 GPU 所在的 NUMA 节点,导致其 Cpus_allowed 受限。当 Worker 分布在另一个 NUMA 节点时,numactl --physcpubind 会验证每个请求的 CPU 属于父进程集合,从而引发 'cpu argument ... is out of range' 错误。此外,DGX B300 的 Xeon 6776P 支持 PCT 技术,部分核心频率可提升至 4.6 GHz(约 2.3 GHz 的两倍),但操作系统默认调度无法自动利用,需要显式绑定才能获得性能优势。
实现拆解
- 新增 PCT 检测模块(
vllm/utils/numa_utils.py):定义 _PctSku 命名元组和 _PCT_CAPABLE_SKUS 字典,映射已知 PCT SKU(6776P/6774P/6962P)到其 highest_perf 和 priority_stride。新增 _pct_sku_config() 缓存函数,读取 /proc/cpuinfo 和 /sys/devices/system/cpu/cpu0/acpi_cppc/highest_perf,若匹配 SKU 表则返回配置,否则返回 None。新增 _maybe_get_pct_cpu_binding(numa_nodes) 函数,对指定的 NUMA 节点,计算其 cpulist 并过滤出 PCT 优先级核心(cpu_id % stride in (0, 1)),返回合并后的 CPU 列表。
- 重构
_get_numactl_args 为 Worker 和 EngineCore 专用函数:原 _get_numactl_args 承担两种绑定逻辑,现拆分为 _get_numactl_worker_args(根据显式 numa_bind_cpus 或自动 PCT 节点绑定)和 _get_enginecore_numa_nodes(计算 DP shard 覆盖的所有 NUMA 节点)。configure_subprocess 根据 process_kind 调用对应函数:若为 "EngineCore",使用 _get_enginecore_numa_nodes 生成 --cpunodebind=... --membind=... 参数覆盖整个 shard 的节点,从而扩大其 cpus_allowed。
- PCT 绑定集成到 Worker 绑定:
_get_numactl_worker_args 内部调用 _maybe_get_pct_cpu_binding,若返回非空列表则使用 PCT 核心列表生成 --physcpubind=... --membind=...;否则回退到显式的 --numa-bind-cpus 或 --cpunodebind。优先级:显式 --numa-bind-cpus > PCT 自动检测 > --cpunodebind 节点绑定。
- 更新配置文档和测试:在
vllm/config/parallel.py 中更新 numa_bind 的文档字符串,说明 PCT 自动绑定行为。tests/utils_/test_numa_utils.py 新增全套 PCT 测试,包括自动启用的 fixture _disable_pct_by_default(避免本地环境干扰)和 _patch_pct_gates helper 以模拟不同 SKU 和 highest_perf 场景。测试覆盖了 SKU 匹配、性能不匹配、节点 cpulist 差异等情况。
关键文件:
vllm/utils/numa_utils.py(模块 NUMA 工具;类别 source;类型 core-logic;符号 _PctSku, _pct_sku_from_cpuinfo, _pct_sku_config, _get_cpu_binding): 核心变更文件,包含 PCT 自动检测、EngineCore 绑定拓宽和 Worker 绑定重构的所有逻辑。
tests/utils_/test_numa_utils.py(模块 单元测试;类别 test;类型 test-coverage;符号 _disable_pct_by_default, _no_pct_open, _patch_pct_gates, fake_open): 新增 PCT 相关测试,包括 mock 文件系统的辅助函数和覆盖所有 SKU 的测试用例,确保检测逻辑正确。
vllm/config/parallel.py(模块 并行配置;类别 source;类型 documentation): 更新 numa_bind 文档字符串,说明 PCT 自动绑定行为,对用户可见。
关键符号:_PctSku, _pct_sku_config, _maybe_get_pct_cpu_binding, _get_numactl_worker_args, _get_enginecore_numa_nodes, _disable_pct_by_default, _patch_pct_gates
关键源码片段
vllm/utils/numa_utils.py
核心变更文件,包含 PCT 自动检测、EngineCore 绑定拓宽和 Worker 绑定重构的所有逻辑。
# _PctSku: 每个 SKU 的配置元组
# highest_perf: CPPC 最大性能比(100MHz 为单位)
# priority_stride: 每个优先级组包含的逻辑 CPU 数
class _PctSku(NamedTuple):
highest_perf: int
priority_stride: int
# 已知 PCT 能力的 Granite Rapids SKU 配置表
# 字典结构 : {model_name: _PctSku}
_PCT_CAPABLE_SKUS: dict[str, _PctSku] = {
"6776P": _PctSku(highest_perf=46, priority_stride=16), # 已实测 DGX B300
"6774P": _PctSku(highest_perf=46, priority_stride=16), # 按 Intel ARK 推测
"6962P": _PctSku(highest_perf=44, priority_stride=18), # 按 Intel ARK 推测
}
# 系统文件路径,用于检测 PCT 能力
_PCT_HIGHEST_PERF_PATH = "/sys/devices/system/cpu/cpu0/acpi_cppc/highest_perf"
_PROC_CPUINFO_PATH = "/proc/cpuinfo"
@cache
def _pct_sku_config() -> _PctSku | None:
"""检测当前系统是否为已知 PCT 平台,并返回对应的 SKU 配置。
读取 /proc/cpuinfo 和 /sys/.../highest_perf,如果匹配 SKU 表
且 highest_perf 一致,则返回配置,否则返回 None(fail closed)。
"""
# ... 打开文件并比较的逻辑,详见源码
tests/utils_/test_numa_utils.py
新增 PCT 相关测试,包括 mock 文件系统的辅助函数和覆盖所有 SKU 的测试用例,确保检测逻辑正确。
@pytest.fixture(autouse=True)
def _disable_pct_by_default(monkeypatch):
"""自动禁用 PCT 检测,避免本地环境干扰。"""
from io import StringIO
real_open = open
def _no_pct_open(path, *args, **kwargs):
# 返回一个不匹配任何 SKU 的 cpuinfo
if path == numa_utils._PROC_CPUINFO_PATH:
return StringIO("processor\t: 0\nmodel name\t: Generic Test CPU\n")
# 使 highest_perf 读取抛出 OSError
if path == numa_utils._PCT_HIGHEST_PERF_PATH:
raise OSError("PCT disabled by autouse fixture")
return real_open(path, *args, **kwargs)
monkeypatch.setattr("builtins.open", _no_pct_open)
numa_utils._pct_sku_config.cache_clear()
yield
numa_utils._pct_sku_config.cache_clear()
def _patch_pct_gates(
monkeypatch,
*,
model_match: bool,
highest_perf: int | None,
cpulist: str | None = "0-31,64-95",
cpulist_by_node: dict[int, str | None] | None = None,
sku: str = "6776P",
):
"""覆盖系统文件访问,模拟指定 SKU 和 highest_perf 的 PCT 环境。"""
import pathlib
from io import StringIO
import regex as re
cpuinfo = (
f"processor\t: 0\nmodel name\t: Intel(R) Xeon(R) Platinum {sku} CPU @ 2.40GHz\n"
if model_match
else "processor\t: 0\nmodel name\t: Intel(R) Xeon(R) Platinum 8480+\n"
)
real_open = open
def fake_open(path, *args, **kwargs):
if path == numa_utils._PROC_CPUINFO_PATH:
return StringIO(cpuinfo)
if path == numa_utils._PCT_HIGHEST_PERF_PATH:
if highest_perf is None:
raise OSError("missing")
return StringIO(f"{highest_perf}\n")
return real_open(path, *args, **kwargs)
# ... 类似地 mock pathlib.Path.read_text 返回 cpulist
monkeypatch.setattr("builtins.open", fake_open)
# ... 继续设置
评论区精华
Harry-Chen: "I have some concerns regarding only detecting the specific model 6776P, since there are more models supporting PCT." 作者随后扩展支持 6774P 和 6962P,并采用 fail closed 策略。
Harry-Chen: "IIUC, the HP cores can be adjusted dynamically. So hardcoding numbers will not work." 作者解释目前内核不支持动态查询,且生产环境无法使用 intel-speed-select,故使用静态 SKU 表。
Harry-Chen: "I think we can make it return list[int], which is more natural for downstream consumers." 作者改为返回 list[int]。
Harry-Chen: "Please be exhaustive and defensive. If kind is neither EngineCore nor Worker, we need to throw some error." 作者添加了警告处理。
gemini-code-assist[bot]: 指出多节点 DP 中 data_parallel_index 可能超出本地 numa_bind_nodes 长度。此问题未在提交中得到明确修复(部分缓解),需后续关注。
- EngineCore 特殊绑定处理 (design): 最终采用 EngineCore 跨 shard NUMA 节点绑定,使用
_get_enginecore_numa_nodes 生成参数。
- PCT SKU 支持范围 (design): 作者添加 6774P 和 6962P,采用失败关闭策略(fail closed)。
- 返回类型建议 (style): 作者改为返回
list[int]。
- 多节点 DP 潜在问题 (correctness): 作者未明确回复,相关逻辑可能部分缓解但不彻底,需后续关注。
风险与影响
- 风险:PCT 检测依赖固定 sysfs 路径和 CPUID 格式,若未来硬件或内核变更可能失效;但设计为 fail closed(不启用 PCT),不影响正确性,仅可能损失性能。EngineCore 绑定放宽到跨 NUMA 节点可能增加内存跨 NUMA 访问延迟,但 EngineCore 不执行计算,影响甚微。多节点 DP 场景中,
data_parallel_index 的 fallback 可能导致 NUMA 索引越界(如 gemini 所述),当前代码是否彻底修复尚不明确,属残留风险。
- 影响:正面影响:所有启用
--numa-bind 的用户在 DGX B300 上自动获得 PCT 绑定,性能提升显著(吞吐量 +64%,TPOT -46%);修复了跨 NUMA 节点 DP 场景下 Worker 启动失败的 bug。负面影响:无,行为向后兼容,仅在用户显式开启 --numa-bind 且未指定自定义 CPU 绑定时生效。团队需维护 SKU 表,但 fail closed 机制降低了维护负担。测试覆盖充分(+338 行测试),回归风险低。
- 风险标记:跨 NUMA 节点 DP 潜在索引越界, PCT 检测依赖硬件特征且需维护 SKU 表, EngineCore 绑定放宽可能影响内存局部性(但影响小)
关联脉络
- PR #33222 Use intel-speed-select for dynamic PCT detection and core selection: 同一个目标(利用 PCT 核心)的不同实现方式,该 PR 依赖 intel-speed-select(需要 root),本 PR 使用无 root 方案。
参与讨论