Prhub

#40161 [bugfix] Use only onlines CPUs in lscpu

原始 PR 作者 Galigator 合并时间 2026-04-20 21:19 文件变更 1 提交数 8 评论 3 代码增减 +1 / -1

执行摘要

修复 CPU 资源探测中因离线核心导致 JSON 解析失败的问题。

PR body 详细描述了在 Ubuntu 24.04 上使用 CPU 后端运行 vLLM 服务时遇到的引擎启动失败问题。错误栈显示 vllm/utils/cpu_resource_utils.py 中的 _get_cpu_list 函数在解析 lscpu -J -e=CPU,CORE,NODE 输出时,因离线 CPU 核心的 node 字段值为未加引号的连字符“-”而触发 json.decoder.JSONDecodeError。现有正则表达式替换逻辑(将 "node": - 替换为 "node": 0)未能完全处理此情况,导致系统无法启动。作者指出,正确的解决方法是使用 lscpu --online 标志直接过滤掉离线 CPU,避免生成无效 JSON。

该 PR 是一个典型的边界条件 bugfix,变更简洁明了,适合快速浏览以理解问题根因和修复方案。值得关注的设计决策是选择在命令层面过滤离线 CPU(使用 --online),而非在代码层面增强 JSON 清洗逻辑,这体现了“在源头解决问题”的简洁性原则。对于涉及 CPU 资源管理或跨平台兼容性的开发者,建议阅读 _get_cpu_list 函数的完整实现,以了解其在整个资源初始化链条中的作用。

讨论亮点

review 中仅有一次实质性讨论:

  • gemini-code-assist[bot] 指出,虽然添加 --online 标志解决了离线 CPU 导致的 JSON 无效问题,但第 162 行的正则表达式 r'"node":\s*-\s*(,|\n)' 仍然脆弱,因为它只针对 node 字段,且假设了特定的 JSON 格式(如尾部逗号或换行)。如果 lscpu 输出被压缩或其他字段(如 core)也包含未加引号的连字符,json.loads 仍可能失败。建议使用更健壮的正则表达式来处理所有字段和多种 JSON 格式。
  • Galigator 回复认为,当前 PR 仅关注在线 CPU 问题,正则表达式的有效性已由先前作者验证过,且当前的正则表达式 r'"node":\s*-\s*(,|\n)' 比建议的更精确。
  • 结论:讨论未达成进一步修改共识,PR 按原方案合并。
  • 未解决疑虑:gemini-code-assist[bot] 提出的正则表达式脆弱性问题未被采纳,潜在风险仍存在,但通过 --online 标志已规避了主要故障场景。

实现拆解

  1. 修改 CPU 列表获取命令:在 vllm/utils/cpu_resource_utils.py_get_cpu_list 函数中,将调用 lscpu 的命令行参数从 "lscpu -J -e=CPU,CORE,NODE" 更新为 "lscpu --json --extended=CPU,CORE,NODE --online"
    - 涉及文件vllm/utils/cpu_resource_utils.py
    - 关键符号_get_cpu_list 函数
    - 具体变更:添加 --online 标志以仅获取在线 CPU 信息;同时将短参数 -J-e= 分别改为长参数 --json--extended=,提升代码可读性。
    - 原因--online 标志确保 lscpu 输出中不包含离线 CPU 核心,从而避免 JSON 中出现未加引号的连字符“-”,从根本上解决解析错误。参数形式更新是次要的代码风格改进。
    - 影响:此变更直接影响引擎启动时的 CPU 资源探测逻辑,确保在具有离线核心的系统上能够正常初始化。
  2. 无配套改动:本次 PR 仅修改了核心逻辑文件,未涉及测试、配置、文档或部署脚本的更新。
文件 模块 状态 重要度
vllm/utils/cpu_resource_utils.py 工具函数 modified 4.72

关键符号

_get_cpu_list

关键源码片段

vllm/utils/cpu_resource_utils.py core-logic

这是唯一被修改的文件,包含修复 JSON 解析错误的 CPU 列表获取逻辑。

@cache
def _get_cpu_list() -> list[LogicalCPUInfo]:
    if platform.system() == "Darwin":
        # For MacOS, no user-level CPU affinity and SMT, return all CPUs
        cpu_count = os.cpu_count()
        assert cpu_count
        return [LogicalCPUInfo(i, i, 0) for i in range(cpu_count)]
​
    # 关键变更:添加 --online 标志仅获取在线 CPU,避免 JSON 中出现未加引号的连字符“-”
    # 同时将短参数 -J -e= 更新为长参数 --json --extended=,提升代码可读性
    lscpu_output = subprocess.check_output(
        "lscpu --json --extended=CPU,CORE,NODE --online", shell=True, text=True
    )
​
    # 对于没有 NUMA 的平台,将 '-' 替换为 '0'
    # 注意:此正则表达式仅处理 node 字段,在添加 --online 后,离线 CPU 已被过滤,但格式问题仍可能存在
    lscpu_output = re.sub(r'"node":\s*-\s*(,|\n)', r'"node": 0\1', lscpu_output)
​
    logical_cpu_list: list[LogicalCPUInfo] = json.loads(
        lscpu_output, object_hook=LogicalCPUInfo.json_decoder
    )["cpus"]
​
    # 过滤掉属性为 -1 的 CPU(无效 CPU)
    logical_cpu_list = [
        x for x in logical_cpu_list if -1 not in (x.id, x.physical_core, x.numa_node)
    ]
​
    return logical_cpu_list

评论区精华

正则表达式脆弱性讨论 正确性

gemini-code-assist[bot] 指出,尽管添加 --online 标志解决了离线 CPU 问题,但第 162 行的正则表达式 r'"node":\s*-\s*(,|\n)' 仍然脆弱,因为它只针对 node 字段且假设特定 JSON 格式,如果 lscpu 输出被压缩或其他字段包含未加引号的连字符,json.loads 仍可能失败。

结论:Galigator 回复认为当前 PR 仅关注在线 CPU 问题,正则表达式已由先前作者验证,且当前版本更精确,未进行修改。 · 已解决

风险与影响

  1. 回归风险:极低。变更仅影响 lscpu 命令的参数,不改变核心逻辑。--online 标志是标准参数,广泛支持于主流 Linux 发行版(如 Ubuntu、CentOS)。
  2. 性能风险:无。命令输出数据量因过滤离线 CPU 而可能略微减少,但影响可忽略。
  3. 安全风险:无。未引入新的外部依赖或敏感操作。
  4. 兼容性风险:低。需确保目标系统上的 lscpu 版本支持 --online 标志。根据 PR body,问题出现在 util-linux==2.39.3,该版本应支持此标志。对于极旧系统(如 util-linux < 2.3),可能不支持长参数形式,但短参数 -b 也可实现类似效果(PR 中未采用)。
  5. 代码健壮性风险:中。如 review 讨论所指,第 162 行的正则表达式替换逻辑仍可能在某些边缘情况下(如压缩 JSON 或其他字段含“-”)失败,但 --online 标志已避免了主要故障路径。
  1. 用户影响:直接修复了在具有离线 CPU 核心的系统(如某些 Ubuntu 24.04 配置)上运行 CPU 后端时引擎启动失败的问题,提升用户体验和系统可靠性。影响范围限于使用 CPU 后端的用户。
  2. 系统影响:确保 CPU 资源探测模块能稳定获取在线 CPU 列表,支持引擎正常初始化和线程绑定,避免因 JSON 解析错误导致的级联故障。
  3. 团队影响:变更微小且集中,易于理解和维护,不会增加后续开发负担。
正则表达式脆弱性 平台兼容性

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论