ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

vllm-ascend CPU Binding 深度解析:ARM 服务器上的 Ascend 原生 CPU 亲和性绑定机制

vllm-ascend CPU Binding 深度解析:ARM 服务器上的 Ascend 原生 CPU 亲和性绑定机制 人工智能大模型模型推理服务AscendCANN【免费下载链接】vllm-ascendCommunity maintained hardware plugin for vLLM on Huawei Ascend项目地址https://gitcode.com/gh_mirrors/vl/vllm-ascend点击查看免费下载导读CPU Binding 是 vllm-ascend 面向 ARM 服务器推出的一项Ascend 原生主机侧host-side优化能力从 vllm-ascend v0.18.0rc1 起默认开启enable_cpu_bindingTrue通过将 worker 进程、ACL 线程、release 线程、内存页与 NPU IRQ 精确放置到专属 CPU 区间缓解多 socket ARM 服务器上 Linux 调度器带来的跨 NUMA 访问、线程抢占与延迟抖动问题。本文基于 设计文档 并结合仓库源码 cpu_binding.py完整讲解其动机、配置方式、策略选择、CPU 池构建算法、角色拆分、条件性主机调优、运行日志与排查手段读完即可理解该特性如何工作、何时需要手动关闭以及如何在生产环境验证与排障。一、概述什么是 CPU BindingCPU Binding 是Ascend 原生的主机侧性能优化面向 ARM 服务器上的 vLLM worker。它不改变模型执行逻辑也不改变任何数值结果只负责在宿主环境允许时控制以下内容的 CPU 放置worker 进程本身及其关键运行时线程进程内存页通过内存迁移实现 NUMA 局部性NPU 中断IRQ的处理 CPU。通过把主 worker、ACLAscend 计算库线程和 release 线程固定在专属 CPU 区间该特性有助于降低繁忙主机上因调度器抢占preemption引入的上下文切换开销。从源码看这是一套完全独立于模型执行路径的旁路逻辑绑定动作发生在模型加载、预热与 graph capture 完成之后的 worker 启动流程中见 worker.py。版本与默认行为从vllm-ascend v0.18.0rc1 开始该特性通过enable_cpu_bindingTrue默认启用。在配置层面默认值定义在 ascend_config.py 的enable_cpu_binding: bool True。也就是说通常情况下你不需要手动配置只有当你希望显式关闭或把默认行为写清楚时才需要设置该开关。二、为什么需要 CPU Binding在多 socket ARM 系统上Linux 调度器并不了解 NPU 与 CPU 之间的物理亲缘关系可能把 worker 线程调度到距离该 worker 驱动的 NPU 很远的 CPU上从而引发三个问题跨 NUMA 流量增加worker 访问远端内存节点上的数据读写延迟上升线程抢占加剧调度器频繁迁移线程上下文切换开销变大繁忙主机上尤为明显延迟抖动CPU 争用导致尾延迟不稳定。因此 Ascend 后端需要自有的 CPU 分配策略目标是减少跨 NUMA 流量、减少线程抢占、提升延迟稳定性而不是直接复用上游 GPU 的 NUMA 绑定参数。这也正是上游 NUMA 参数在 Ascend 上被“适配”的原因见 platform.py--numa-bind会被转换为additional_config{enable_cpu_binding: true}--numa-bind-nodes与--numa-bind-cpus会被忽略因为 Ascend 根据 NPU 拓扑或全局逻辑 NPU ID 自行计算 CPU 池用户指定的节点/CPU 反而可能与实际拓扑不符。三、开启方式与依赖工具3.1 在线服务Online Serving默认行为无需任何参数vllm serve Qwen/Qwen2.5-7B-Instruct显式关闭 CPU Bindingvllm serve Qwen/Qwen2.5-7B-Instruct \ --additional-config {enable_cpu_binding: false}3.2 离线推理Offline Inference默认行为from vllm import LLM llm LLM(modelQwen/Qwen2.5-7B-Instruct)显式关闭from vllm import LLM llm LLM( modelQwen/Qwen2.5-7B-Instruct, additional_config{enable_cpu_binding: False}, )该开关在additional_config中的完整说明见 additional_config.md类型为 bool默认True在 ARM 服务器上启用 Ascend 原生 CPU 绑定置为False可关闭。3.3 依赖工具安装官方 vllm-ascend 镜像在 v0.18.0rc1 及更早版本已包含util-linux与procps/procps-ng从 v0.18.0rc1 起官方镜像额外包含numactl。如果你不使用官方镜像需要手动安装# Ubuntu/Debian sudo apt-get install -y util-linux numactl procps # RHEL/CentOS/Alma/Rocky sudo yum install -y util-linux numactl procps-ng # openEuler sudo dnf install -y util-linux numactl procps-ng没有numactl/migratepages时vLLM Ascend 只跳过内存迁移这一步worker 进程与运行时线程仍然会被 pin但已放置在远端 NUMA 节点上的页面不会被搬移可能降低局部性并导致延迟或吞吐退化详见下文条件性主机调优。3.4 与上游 NUMA 参数的协同使用--numa-bind时无需额外操作平台层会自动完成转换并打印日志--numa-bind is not supported on Ascend NPU (GPU-to-NUMA topology detection unavailable). Automatically converted to --additional-config {enable_cpu_binding: true} for Ascend-native CPU-core binding.--numa-bind-nodes、--numa-bind-cpus则会被置空并记录已忽略日志因为 Ascend 内部会自动执行 topo-affinity 核分配。四、工作机制分配器如何制定绑定计划分配器CpuAlloc见 cpu_binding.py的输入全部来自运行时主机状态不使用任何静态假设输入来源用途允许使用的 CPUAllowed CPUs/proc/self/status的Cpus_allowed_list唯一可绑定的 CPU 集合容器 cpuset 会被尊重逻辑 NPU 映射npu-smi info -m将 card/chip ID 映射到全局逻辑 NPU ID并给出total_logic_npus。950PR950DT Products 不报告Chip Logic ID因此用NPU ID作为逻辑 ID运行中的 NPUnpu-smi info进程表按ASCEND_RT_VISIBLE_DEVICES过滤识别本 worker 进程实际使用的逻辑 NPU。A2/A3 进程行使用NPU Chip字段950PR950DT Products 进程行使用NPU ID拓扑亲和性npu-smi info -t topo为topo_affinity模式提供 NPU 到 CPU 的亲和信息CPU NUMA 映射lscpu -eCPU,NODE用于把单 NUMA 亲和池扩展到下一个 NUMA 节点线程拓扑lscpu的Thread(s) per core决定 950PR950DT Products 的 cluster 大小每核 1 线程时为 8 个 CPU每核 2 线程时为 16 个 CPUUVB 轮询线程ps -Te为 950PR950DT Products 的 UVB CPU 绑定寻找宿主uvb_poll_window_thread线程。Docker 容器必须使用--pidhost才能看到这些宿主线程对应源码实现为DeviceInfo类cpu_binding.pyget_npu_map_info()解析npu-smi info -m对 950PR950DT Products 等不输出Chip Logic ID的场景自动退化为以NPU ID作为逻辑 IDL102-L129get_running_npus()解析进程表并按ASCEND_RT_VISIBLE_DEVICES求交集取不到任何运行 NPU 时抛出Can not get running npu info.L146-L178parse_allowed_cpus()从/proc/self/status读取并展开Cpus_allowed_listparse_topo_affinity()解析npu-smi info -t topo中NPUn行的 CPU 列表。4.1 命令执行的健壮性所有npu-smi、lscpu、taskset、migratepages、ps调用都经由execute_command()L44-L56执行它会强制LC_ALLC/LANGC/LC_MESSAGESC以保证本地化系统上的输出仍可解析并设置了 1000 秒超时防止命令卡死。五、策略选择Strategy Selection绑定策略按 Ascend 设备类型选择定义于 hardware_profile.py 的CPUBindingMode枚举topo_affinity/global_slice设备类型策略原因A3global_sliceA3 使用 HCCS 卡间互联每个 NPU 到所有 NUMA 节点的距离几乎相同不存在强 NPU-NUMA 亲和信号。基于全局逻辑 NPU ID 切分可得到确定性的、互不重叠的 CPU 池并实现 worker 间的 CPU/NUMA 隔离950PR950DT Productstopo_affinity使用npu-smi info -t topo的 NPU-CPU 亲和性为每个 worker 从亲和 NUMA 节点分配一个 CPU cluster同时进程行按NPU ID而非NPU Chip上报、跳过 IRQ 绑定、并绑定宿主 UVB 轮询线程A2 与 Atlas 300 推理产品topo_affinity这些设备通过npu-smi info -t topo提供 NPU-CPU 亲和信息因此优先利用拓扑信号回退规则如果选择了topo_affinity但拓扑亲和信息不可用分配器自动回退到global_slice对应源码 L555-L557 的_build_topo_affinity_cpu_pool回退逻辑。此外硬件能力标志IRQ_CPU_RESERVATION决定是否保留 IRQ CPU、CLUSTER_CPU_TOPOLOGY决定是否走 950PR950DT Products 的 cluster 拓扑路径hardware_profile.py。六、CPU 池构建CPU Pool Construction6.1global_slice模式global_slice面向没有可用 NPU-CPU 亲和信号的设备包括 A3。由于 A3 的HCCS 互联使得每个 NPU 到每个 NUMA 节点的距离几乎相同拓扑亲和不是有效的放置信号分配器因此按全局逻辑 NPU ID对排序后的allowed_cpus列表做切分build_global_slice_cpu_pool按以下优先级确定total_npus来自npu-smi info -m的total_logic_npus否则取 topo 亲和条目的数量否则取运行中 NPU 的数量。计算base len(allowed_cpus) // total_npusextra len(allowed_cpus) % total_npus每个逻辑 NPU 获得确定性的切片逻辑 NPU ID extra的获得base 1个 CPU其余 NPU 获得base个 CPU。只有运行中的 NPU会被物化进npu_cpu_pool。关键性质两个拥有相同 cpuset、但可见 NPU ID 不同的独立 worker 进程仍会得到互不重叠的 CPU 池——因为两个进程都在同一个全局 NPU ID 空间上切片。当 cpuset 与 NUMA 对齐时这同时提供了worker 间的 CPU/NUMA 隔离一个 worker 不会与另一个 worker 共享同一 CPU 或 NUMA 切片。global_slice对 CPU 数量有最低要求取决于设备的角色拆分带 IRQ 绑定的设备要求base 52 个 CPU 给 SQ/CQ IRQ 绑定、至少 1 个 CPU 给主 worker、1 个给 ACL 线程、1 个给 release 线程。源码中体现为MIN_CPUS_PER_NPU 5与MIN_CPUS_PER_NPU_WITHOUT_IRQ 3两个常量L20-L22。6.2topo_affinity模式A2 / Atlas 300 推理产品 / 950PR950DT Products 等非 A3 设备A2 和 Atlas 300 推理产品暴露有意义的 NPU-CPU 亲和信息分配器在拓扑亲和可用时以此为起点并对共享亲和组做防重叠处理_build_topo_affinity_cpu_pool从所有逻辑 NPU构建候选集运行中的 NPU 始终纳入非运行 NPU 仅当其亲和区间与本进程的 allowed cpuset 有交集时纳入。对每个候选 NPU将 topo 亲和与allowed_cpus求交集。若某候选的交集为空则本 rank 绑定失败。若亲和 CPU 全部位于同一 NUMA 节点则从下一个 NUMA 节点扩展 CPU 池受allowed_cpus约束。将具有相同扩展池的 NPU 分组并在组内均分共享池。最终npu_cpu_pool只保留运行中的 NPU。纳入非运行 NPU 是有意为之它防止两个独立的单卡 worker可见 NPU 共享同一 topo 亲和选择到同一 CPU 区间——这正是后文示例二要解决的问题。6.3 950PR950DT Products 的专用路径950PR950DT Products 对 topo 亲和的使用方式不同build_ascend_950_cpu_pools把宿主可见的所有uvb_poll_window_thread线程绑定到NUMA0 上除 CPU0 之外的 CPU受allowed_cpus约束。Docker 容器必须使用--pidhost才能看到这些宿主线程用 topo 亲和识别每个 NPU 的单一亲和 NUMA 节点解析lscpu的Thread(s) per core每核 1 线程时 cluster 大小为 8每核 2 线程时为 16把每个亲和 NUMA 节点的排序 allowed CPU 列表切成连续 cluster按排序后的逻辑 NPU ID 分配 cluster包括共享同一亲和 NUMA 的隐藏 NPU最终池只保留运行中的 NPU。若 950PR950DT Products 的 topo 亲和缺失、横跨多个 NUMA 节点、cluster 数量不足、或Thread(s) per core不受支持则跳过 worker CPU 绑定且不向 worker 进程抛出异常仅记录 warning见 L376-L439 中各条action: skip worker CPU binding日志。七、角色拆分Role SplitCPU 池构建完成后分配器按角色拆分。allocate()会根据硬件能力选择走 950PR950DT Products 路径还是默认路径L592-L620。7.1 带 IRQ 绑定的设备角色CPUSQ/CQ IRQpool[0]、pool[1]主 worker 进程及子线程pool[2:-2]ACL 线程pool[-2]Release 线程pool[-1]7.2 950PR950DT Products角色CPU主 worker 进程及子线程整个分配的 clusterACL 线程不单独 pinRelease 线程不单独 pin若最终池的 CPU 数少于角色拆分所需则本 rank 绑定失败并由调用方记录 warning。带 IRQ 绑定的设备每个 NPU 至少需要 5 个 CPU950PR950DT Products 每个 worker 需要一个完整 cluster。实际绑定动作通过taskset完成L246-L255主进程使用taskset -acp同时绑定已存在的子线程ACL/release 线程使用taskset -cp。八、条件性主机调优Conditional Host Tuning在 CPU 亲和性应用之后当环境支持时CPU Binding 还会执行两个主机侧调优步骤。它们是 CPU Binding 的条件性组成部分而非独立的特性开关宿主前提不满足时仅跳过对应步骤CPU 线程绑定仍会继续。8.1 内存迁移Memory Migration使用migratepages把 worker 进程已有内存页迁移到所选 NUMA 节点bind_memory。这让 worker 更接近它读取的内存减少远端 NUMA 读延迟[migrate] NPU:0 - NUMA [1]迁移目标 NUMA 节点取自该 NPU 的 CPU 池锚点 CPU 所在节点。注意run_all中migrate_memory默认开启但当启用 Engram 且开启cpu_offload时worker 会跳过进程级内存迁移——因为 HOST_UVA 表的 pinned backing 可能跨 NUMA 节点共享迁移会破坏其固定性见 worker.py。8.2 IRQ 绑定IRQ Binding当/proc/irq可写且 IRQ 文件可解析时把 NPU IRQ 处理放到对应 NPU 预留的 CPU 上bind_npu_irq若/proc/irq不可写记录提示Docker 需--privilegedtrue若irqbalance.service正在运行且进程可用systemctl先停止它避免与手工 IRQ 亲和冲突通过/proc/interrupts定位sq_send_trigger_irq再通过npu-smi info -t board获取 PCI 地址从/sys/bus/pci/devices/pci/msi_irqs/解析出 SQ/CQ IRQ 号将smp_affinity写为 CPU 掩码cpu_to_mask支持 32 位为一组的多组掩码L217-L225。950PR950DT Products 跳过此步骤即使/proc/irq可写也不写任何smp_affinity文件日志中会出现[irq] IRQ binding skipped on Ascend 950.。性能提示缺少migratepages时页面可能仍留在远端 NUMA 节点与完整 CPU Binding 配置相比延迟或吞吐可能回退。CPU 亲和仍生效但内存局部性变差。九、典型示例9.1 示例一A3 推理服务器640 个 CPU 与 16 个 NPU输入allowed_cpus [0..639]total_logic_npus 16running_npu_list [0..15]计算base 640 // 16 40extra 0驱动逻辑 NPUi的 workeri获得 CPU 切片[i * 40 .. i * 40 39]。全局切片视图CPU range: 0 639 |-- worker0/NPU0 --|-- worker1/NPU1 --| ... |-- worker15/NPU15 --| | 0-39 | 40-79 | ... | 600-639 |每个 worker 切片内部的角色拆分40-CPU worker slice | IRQ CPUs | main worker process and subthreads | ACL thread | release thread | | c0-c1 | c2-c37 | c38 | c39 |具体分配Worker逻辑 NPUCPU 池IRQ CPU主线程 CPUACL CPURelease CPU000-390-12-3738391140-7940-4142-777879.....................1515600-639600-601602-637638639即使不同 worker 进程共享同一 cpuset该布局依然确定因为切片基于全局逻辑 NPU ID。这一性质有对应单元测试覆盖test_build_global_slice_cpu_pool_splits_same_cpuset_across_processestest_cpu_binding.py。9.2 示例二A2 topo_affinity 与共享亲和的隐藏 NPU来自 A2 拓扑的输入NPU0 亲和144-167NPU2 亲和144-167进程 A 只能看到 NPU0进程 B 只能看到 NPU2两个进程的allowed_cpus [144..191]分配器在每个进程中都把隐藏的同亲和 NPU作为候选纳入均分共享的扩展池然后只在最终池中保留可见 NPU进程可见 NPU最终 CPU 池A0144-167B2168-191即使两个 worker 以独立的单卡服务分别启动也能避免 CPU 池重叠。十、运行日志解读分配器会记录所选模式与分配计划[cpu_bind_mode] modetopo_affinity rank0 visible_npus[0] The CPU allocation plan is as follows: NPU0: main[...] acl[...] release[...]950PR950DT Products 使用不同的角色拆分其计划日志不含 ACL/release 字段UVB 轮询线程的绑定在找到匹配线程时单独上报[cpu_bind_mode] modetopo_affinity rank0 visible_npus[0] The CPU allocation plan is as follows: Ascend 950 NPU0: worker[...] [cpu_bind_ascend_950] uvb_poll_window_thread tids[...] cpus[...]日志实现在print_plan()L622-L637中默认路径输出main/acl/release三字段950PR950DT Products 路径输出worker单字段。十一、限制与排查11.1 已知限制仅 ARM 运行x86_64 上直接跳过。源码中is_arm_cpu()L31-L41对 x86 家族返回 False并对未知架构给出警告后禁用绑定CPU 数量下限带 IRQ 绑定的设备每个最终 NPU 池至少 5 个 CPU950PR950DT Products 每个 worker 需要一个完整 CPU clusterglobal_slice是确定性的当 cpuset 与 NUMA 对齐时可提供 CPU/NUMA 隔离但当 CPU 编号或 cpuset 布局跨 NUMA 边界时无法保证池内 NUMA 局部性topo_affinity依赖npu-smi info -t topo的可用输出IRQ 绑定需要可写的/proc/irq与可解析的 PCI/IRQ 信息950PR950DT Products 即使/proc/irq可写也跳过950PR950DT Products 的 UVB 轮询线程绑定需要宿主 PID 命名空间可见性Docker 容器必须--pidhost创建否则uvb_poll_window_thread可能找不到内存迁移需要migratepages否则只跳过内存迁移CPU 亲和仍生效但已有页面未搬移到目标 NUMA 节点、可能通过高延迟远端 NUMA 读取性能因此退化若绑定流程中有异常逃逸NPUWorker会记录 warning 并跳过该 rank 的 CPU 绑定不影响进程启动。11.2 常见消息速查表日志消息含义处理建议CPU binding skipped: non-ARM CPU detected.CPU 绑定只在 ARM 上运行x86_64 上无需处理Can not get running npu info.未发现运行中的 NPU或ASCEND_RT_VISIBLE_DEVICES过滤掉了全部 NPU检查可见 NPU ID 与npu-smi infoInsufficient CPUs for binding...可用 CPU 少于角色拆分所需带 IRQ 绑定设备每逻辑 NPU 至少 5 个 CPU950PR950DT Products 每 worker 需要一个完整 cluster扩大 cpuset 或减少可见 NPUNPU topo affinity not found...拓扑亲和信息不可用950PR950DT Products 上跳过 worker 绑定其他 topo 亲和设备回退到global_slice预期有亲和信息时检查npu-smi info -t topouvb_poll_window_thread not found... --pidhost950PR950DT Products 看不到宿主 UVB 轮询线程以--pidhost重建 Docker 容器并重启 vLLMfailed to bind uvb_poll_window_thread... --pidhost找到 UVB 轮询线程但绑定失败检查权限Docker 环境用--pidhost重建容器The migratepages command is not available...跳过内存迁移CPU 线程绑定继续若 NUMA 局部性或性能受影响安装numactl[irq] IRQ binding skipped on Ascend 950.950PR950DT Products 不使用 IRQ 绑定步骤无需处理worker 主绑定与内存迁移照常进行Bind cpus failed in rank...某绑定步骤失败该 rank 跳过 CPU 绑定检查taskset、lscpu、npu-smi、cpuset 大小与/proc/irq权限11.3 关于 irqbalance 的主机操作需要稳定 IRQ 亲和时在启动 vLLM 前停止 irqbalancesudo systemctl stop irqbalancevLLM 服务退出后如需恢复默认 IRQ 均衡策略sudo systemctl start irqbalance在容器内systemctl不可用的情况下若 IRQ 亲和重要请在宿主上停止irqbalance。十二、实现与验证路径索引核心实现vllm_ascend/cpu_binding.py——DeviceInfo主机信息采集、CpuAlloc策略、池构建、角色拆分、绑定执行与入口bind_cpus()Worker 集成vllm_ascend/worker/worker.py——在模型加载、预热与 capture 之后调用bind_cpus异常时记录 warning 并跳过配置定义vllm_ascend/ascend_config.pyenable_cpu_binding默认 True与 additional_config.md硬件策略vllm_ascend/device/hardware_profile.py——CPUBindingMode枚举及IRQ_CPU_RESERVATION、CLUSTER_CPU_TOPOLOGY等硬件能力标志上游参数适配vllm_ascend/platform.py用户指南feature_guide/cpu_binding.md单元测试tests/ut/device_allocator/test_cpu_binding.py——覆盖npu-smi各输出变体解析、全局切片跨进程不重叠、余数按 NPU ID 分配、topo 亲和解析、NUMA 扩展等关键行为。从测试覆盖可以看出CPU Binding 的解析与分配逻辑被刻意设计为确定性算法只要 cpuset、NPU 可见性等输入不变分配结果就是可复现的。这为多卡、多进程、多 worker 场景下的可预期性能提供了坚实的工程基础——在生产环境中你通常不需要任何手动配置即可获得该能力只有在容器权限、cpuset 规模受限或需要关闭该特性时才需要显式干预。赞分享人工智能大模型模型推理服务AscendCANN【免费下载链接】vllm-ascendCommunity maintained hardware plugin for vLLM on Huawei Ascend项目地址https://gitcode.com/gh_mirrors/vl/vllm-ascend点击查看免费下载相关推荐昇腾 Ascend NPU 上基于 vllm-ascend 部署 Qwen3.6-35B-A3B 推理服务全指南昇腾 Ascend NPU 上基于 vllm ascend 部署 Qwen3.6 35B A3B 推理服务全指南 Qwen3.6 35B A3B 是通义实验室发大模型人工智能教程本地部署微调ComponentKit数据绑定终极指南Binding和Action机制深度解析ComponentKit数据绑定终极指南Binding和Action机制深度解析 ComponentKit是Facebook开源的React inspired移动开发UI组件AIBrix 昇腾 NPU 部署指南使用 StormService 与 vLLM-ascend 在 Ascend 910 上托管 Qwen-2.5 推理服务AIBrix 昇腾 NPU 部署指南使用 StormService 与 vLLM ascend 在 Ascend 910 上托管 Qwen 2.5 推理服务人工智能大模型云原生模型推理服务LLM 网关API网关弹性伸缩上一篇Jupytext 中 MyST Markdown 格式的 Raw Cell 指令语法、双向转换与源码解析下一篇在电脑上优雅操控Android手机Scrcpy GUI的完整实战宝典创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表