优化 CPU 与 GPU 性能的简介
在高性能计算和大规模并行任务处理中,GPU 已成为不可或缺的加速器。为了充分利用 GPU 的计算能力,合理分配并将 CPU 核心绑定到 GPU 上,从而优化 CPU 与 GPU 的关系至关重要。本文将深入探讨 socket(插槽)和 NUMA(非统一内存访问)的概念,并讨论如何基于这些硬件架构实现 CPU 与 GPU 核心绑定,以确保最佳的系统性能。
Socket 概念
什么是 Socket?
Socket 通常指主板上物理 CPU 的安装插槽。每个 socket 对应一个物理 CPU,通常包含多个核心以及一个或多个缓存层级(例如 L1、L2、L3 缓存)。在多 socket 系统(如双路或四路服务器)中,每个 socket 都有一个物理 CPU,它们通过高速互联(如 Intel 的 QPI 或 AMD 的 Infinity Fabric)连接。
多 Socket 系统的特性
在多 socket 系统中,每个 socket 的 CPU 可以访问其本地内存,也可以访问其他 socket 的内存。这种内存访问模式引入了 NUMA 的概念,旨在优化内存访问效率。
NUMA(非统一内存访问)架构
什么是 NUMA?
NUMA 代表 Non-Uniform Memory Access,即非统一内存访问。与传统的统一内存访问(UMA)不同,在 NUMA 架构中,系统内存被划分为多个区域,每个区域与特定的 CPU(socket)相关联。访问本地内存(同一 socket 内)比访问远程内存(来自其他 socket)更快,因此延迟更低。
NUMA 节点与内存访问延迟
在 NUMA 系统中,每个 socket 及其直接连接的内存构成一个 NUMA 节点。同一 NUMA 节点内的内存访问更快,而跨节点内存访问由于额外的总线传输会产生更高的延迟。优化内存与 CPU 的亲和性,确保任务在同一 NUMA 节点内运行,是关键的性能优化步骤。
CPU 与 GPU 的物理关系
GPU 硬件架构
GPU 通常通过 PCIe(外围组件互连 Express)总线与 CPU 通信。在多 socket 系统中,GPU 通常只连接到一个 socket(及其对应的 NUMA 节点),而不会跨 socket 连接。这意味着在实际运行时,GPU 与所连接 socket 的 CPU 核心和内存之间具有更高的带宽和更低的延迟。
CPU 与 GPU 的亲和性
CPU 与 GPU 的通信主要依赖于数据传输。数据从 CPU 传输到 GPU,再传回 CPU,涉及的内存访问操作会显著影响性能。如果与 GPU 绑定的 CPU 核心位于同一 NUMA 节点内,数据传输延迟会显著降低。因此,将 CPU 核心绑定到 GPU 是一项关键的性能优化步骤。
基于亲和性的 GPU 与 CPU 核心绑定策略
在 Docker 容器化部署中,实现 GPU 与 CPU 亲和性绑定对于提高容器化任务的性能至关重要。Docker 的 CPU 和 GPU 资源控制功能允许精确控制容器使用的 CPU 核心和 GPU 设备。
容器 CPU 与 GPU 资源分配
Docker 容器允许精确控制分配的 CPU 和 GPU 资源。通过指定容器使用的 CPU 核心和 GPU 设备,可以实现亲和性绑定以优化性能。
Docker CPU 设置
在 Docker 中,可以使用以下参数来控制 CPU 资源分配:
--cpuset-cpus:指定容器可以使用的物理 CPU 核心。例如,--cpuset-cpus="0-3"将容器限制为使用 CPU 核心 0 到 3。--cpu-shares:控制容器的 CPU 使用权重,但不限制具体的核心使用。--cpus:限制容器可以使用的 CPU 核心总数(以虚拟核心计)。
Docker GPU 设置
可以使用以下 Docker 参数来实现 GPU 设备绑定:
--gpus:指定容器可以访问的 GPU 设备。例如,--gpus '"device=0"'将 GPU 0 分配给容器。
在 Docker 中实现 GPU 与 CPU 核心绑定
要在 Docker 容器中实现 GPU 与 CPU 核心绑定,需要结合 CPU 和 GPU 设置。以下是一个在启动 Docker 容器时绑定特定 CPU 核心和 GPU 的示例:
docker run --cpuset-cpus="0-3" --gpus '"device=0"' --memory="8g" my_gpu_container
在这个命令中:
--cpuset-cpus="0-3"将容器绑定到 CPU 核心 0 到 3,这些核心应与 GPU 0 位于同一 NUMA 节点内。--gpus '"device=0"'将 GPU 0 分配给容器。--memory="8g"将容器的内存使用限制为 8 GB,确保内存分配也与 CPU/GPU 亲和性保持一致。
实现最佳绑定
为了确保容器中的最佳绑定,首先需要确定机器的物理拓扑。使用 nvidia-smi topo -m 查看机器的拓扑结构:
nvidia-smi topo -m
从输出中可以确定机器的 NUMA 配置和 GPU 分配。例如,如果机器有两个 NUMA 节点,NUMA 0 有 4 个 GPU,NUMA 1 有 4 个 GPU,则可以识别每个 NUMA 节点的 GPU 与 CPU 亲和性。
亲和性计算的伪代码
以下是一个简化的用于计算亲和性并确定 GPU 和 CPU ID 的伪代码:
type Affinity struct {
}
// 计算亲和性是否满足,并返回对应的 GPU 和 CPU ID
func calAffinity(affinity *Affinity, cpuUse []int, gpuUse []int, gpuReq int, cpuReq int) (bool, []int, []int) {
return true, []int{}, []int{}
}
该方法可用于判断一个节点是否满足最佳绑定要求。当存在多个节点时,可以使用该方法进行评估并选择最合适的节点。
Novita AI 开发了专为下一代 AI 计算量身定制的容器引擎,动态调整算法以实时监控硬件使用情况并进行端到端优化。用户无需担心 NUMA 技术细节即可享受最强的计算性能。
用户还可以在控制面板中进行更高级的 NUMA 设置。如果您有更多相关需求,请随时通过 Discord 联系我们!
访问 Novita AI 了解更多详情!

