使用 run_cpu 脚本优化 Intel® Xeon® CPU 性能 §
创建于:2025 年 4 月 1 日 | 最后更新:2025 年 4 月 1 日 | 最后验证:2024 年 11 月 5 日
在 Intel® Xeon®可扩展处理器上执行 PyTorch 推理时,存在多个配置选项可能会影响性能。为了获得最佳性能,提供了 torch.backends.xeon.run_cpu
脚本,该脚本优化了线程和内存管理的配置。对于线程管理,脚本配置了线程亲和性和 Intel® OMP 库的预加载。对于内存管理,它配置了 NUMA 绑定并预加载了优化的内存分配库,如 TCMalloc 和 JeMalloc。此外,脚本还提供了可调整的计算资源分配参数,适用于单实例和多实例场景,帮助用户尝试针对特定工作负载的最佳资源利用率协调。
你将学到什么 §
如何利用
numactl
、taskset
、Intel® OpenMP 运行时库以及优化的内存分配器如TCMalloc
和JeMalloc
来提高性能。如何配置 CPU 资源和内存管理以最大化 Intel® Xeon®处理器上的 PyTorch 推理性能。
优化介绍 §
应用 NUMA 访问控制
在单个插槽内为用户提供越来越多的 CPU 核心是有益的,因为这提供了更多的计算资源。然而,这也导致了内存访问的竞争,这可能导致程序因忙碌的内存而停滞。为了解决这个问题,引入了非一致性内存访问(NUMA)。与所有内存对所有核心都同等可访问的统一内存访问(UMA)不同,NUMA 将内存组织成多个组。一定数量的内存直接连接到一个插槽的集成内存控制器,成为该插槽的本地内存。本地内存访问比远程内存访问快得多。
用户可以在 Linux 上使用 lscpu
命令获取 CPU 信息,以了解机器上有多少核心和插槽。此外,此命令还提供 NUMA 信息,例如 CPU 核心的分布。以下是在配备 Intel® Xeon® CPU Max 9480 的机器上执行 lscpu
的示例:
$ lscpu
...
CPU(s): 224
On-line CPU(s) list: 0-223
Vendor ID: GenuineIntel
Model name: Intel (R) Xeon (R) CPU Max 9480
CPU family: 6
Model: 143
Thread(s) per core: 2
Core(s) per socket: 56
Socket(s): 2
...
NUMA:
NUMA node(s): 2
NUMA node0 CPU(s): 0-55,112-167
NUMA node1 CPU(s): 56-111,168-223
...
检测到两个插槽,每个插槽包含 56 个物理核心。启用超线程后,每个核心可以处理 2 个线程,因此每个插槽有 56 个逻辑核心。因此,该机器有 224 个 CPU 核心处于服务状态。
通常,物理核心的索引先于逻辑核心。在这种情况下,0-55 号核心是第一个 NUMA 节点上的物理核心,56-111 号核心是第二个 NUMA 节点上的物理核心。
逻辑核心的索引随后:112-167 号核心对应第一个 NUMA 节点上的逻辑核心,168-223 号核心对应第二个 NUMA 节点上的逻辑核心。
通常,运行具有计算密集型工作负载的 PyTorch 程序应避免使用逻辑核心以获得良好的性能。
Linux 提供了一个名为 numactl
的工具,允许用户控制进程或共享内存的 NUMA 策略。它使用特定的 NUMA 调度或内存放置策略运行进程。如上所述,核心在一个插槽中共享高速缓存,因此避免跨插槽计算是一个好主意。从内存访问的角度来看,局部限制内存访问比访问远程内存要快得多。 numactl
命令应已安装在最近的 Linux 发行版中。如果未安装,您可以使用以下命令手动安装,例如在 Ubuntu 上:
$ apt-get install numactl
在 CentOS 上,您可以运行以下命令:
$ yum install numactl
Linux 中的 taskset
命令是另一个强大的实用工具,允许您设置或检索正在运行的进程的 CPU 亲和力。 taskset
在大多数 Linux 发行版中都是预安装的,如果没有安装,您可以在 Ubuntu 上使用以下命令进行安装:
$ apt-get install util-linux
在 CentOS 上,您可以运行以下命令:
$ yum install util-linux
使用 Intel® OpenMP 运行时库
OpenMP 是多线程的一种实现,是一种并行化方法,其中主线程(一系列依次执行的指令)分支出指定数量的子线程,系统将任务分配给它们。然后这些线程并发运行,运行时环境将线程分配到不同的处理器。用户可以通过一些环境变量设置来控制 OpenMP 的行为,以适应他们的工作负载,这些设置由 OMP 库读取和执行。默认情况下,PyTorch 使用 GNU OpenMP 库(GNU libgomp)进行并行计算。在 Intel® 平台上,Intel® OpenMP 运行时库(libiomp)提供 OpenMP API 规范支持。它通常比 libgomp 带来更多的性能优势。
您可以使用以下命令之一安装 Intel® OpenMP 运行时库:
$ pip install intel-openmp
或者
$ conda install mkl
选择优化的内存分配器
从性能角度来看,内存分配器起着重要的作用。更有效的内存使用可以减少不必要的内存分配或销毁的开销,从而实现更快的执行。根据实践经验,对于深度学习工作负载,通过尽可能重用内存, TCMalloc
或 JeMalloc
可以比默认的 malloc 操作获得更好的性能。
您可以在 Ubuntu 上运行以下命令来安装 TCMalloc
:
$ apt-get install google-perftools
在 CentOS 上,您可以通过运行以下命令来安装它:
$ yum install gperftools
在 conda 环境中,也可以通过运行以下命令进行安装:
$ conda install conda-forge::gperftools
在 Ubuntu JeMalloc
上可以通过以下命令进行安装:
$ apt-get install libjemalloc2
在 CentOS 上可以通过运行以下命令进行安装:
$ yum install jemalloc
在 conda 环境中,也可以通过运行以下命令进行安装:
$ conda install conda-forge::jemalloc
快速入门示例命令
以 1 线程在 1 个 CPU 核心上运行单实例推理(仅使用核心#0):
$ python -m torch.backends.xeon.run_cpu --ninstances 1 --ncores-per-instance 1 <program.py> [program_args]
在单个 CPU 节点上运行单实例推理(NUMA 插座):
$ python -m torch.backends.xeon.run_cpu --node-id 0 <program.py> [program_args]
以多实例推理运行,112 核心 CPU 上 8 个实例,每个实例 14 个核心:
$ python -m torch.backends.xeon.run_cpu --ninstances 8 --ncores-per-instance 14 <program.py> [program_args]
以吞吐量模式运行推理时,每个 CPU 节点上的所有核心都会启动一个实例:
$ python -m torch.backends.xeon.run_cpu --throughput-mode <program.py> [program_args]
备注
这里的“实例”并不指代云实例。此脚本作为一个单独的进程执行,调用多个“实例”,这些实例由多个线程组成。“实例”在这种情境下相当于一组线程。
使用 torch.backends.xeon.run_cpu
¶
可以使用以下命令显示参数列表和使用说明:
$ python -m torch.backends.xeon.run_cpu –h
usage: run_cpu.py [-h] [--multi-instance] [-m] [--no-python] [--enable-tcmalloc] [--enable-jemalloc] [--use-default-allocator] [--disable-iomp] [--ncores-per-instance] [--ninstances] [--skip-cross-node-cores] [--rank] [--latency-mode] [--throughput-mode] [--node-id] [--use-logical-core] [--disable-numactl] [--disable-taskset] [--core-list] [--log-path] [--log-file-prefix] <program> [program_args]
上述命令具有以下位置参数:
旋钮 |
帮助 |
---|---|
|
要启动的程序/脚本的完整路径。 |
|
要启动的程序/脚本的输入参数。 |
选项说明
通用选项设置(旋钮)包括以下内容:
旋钮 |
类型 |
默认值 |
帮助 |
---|---|---|---|
|
显示帮助信息并退出。 |
||
|
将每个进程更改为将启动脚本解释为 Python 模块,以与“python -m”相同的行为执行。 |
||
|
bool |
False |
为了避免在程序前添加“python”,直接执行即可。当脚本不是 Python 脚本时很有用。 |
|
str |
|
指定日志文件目录。默认路径为 |
|
str |
跑 |
日志文件名的前缀为。 |
应用或禁用优化的旋钮有:
旋钮 |
类型 |
默认值 |
帮助 |
---|---|---|---|
|
bool |
False |
启用 |
|
bool |
False |
启用 |
|
bool |
False |
使用默认内存分配器。既不使用 |
|
bool |
False |
默认情况下,如果已安装,将使用 Intel® OpenMP 库。设置此标志将禁用 Intel® OpenMP 的使用。 |
备注
内存分配器影响性能。如果用户没有指定所需的内存分配器, run_cpu
脚本将按顺序搜索是否安装了以下内存分配器:TCMalloc > JeMalloc > PyTorch 默认内存分配器,并选择第一个匹配项。
控制实例数量和计算资源分配的旋钮有:
旋钮 |
类型 |
默认值 |
帮助 |
---|---|---|---|
|
int |
0 |
实例数量。 |
|
int |
0 |
每个实例使用的核心数。 |
|
int |
-1 |
用于多实例的节点 ID,默认情况下将使用所有节点。 |
|
str |
|
默认情况下将使用所有核心。可以通过指定 |
|
bool |
False |
默认情况下仅使用物理核心。指定此标志将启用逻辑核心的使用。 |
|
bool |
False |
防止工作负载在 NUMA 节点间的核心上执行。 |
|
int |
-1 |
指定实例索引以分配 ncores_per_instance 给 rank;否则 ncores_per_instance 将按顺序分配给实例。 |
|
bool |
False |
快速设置,在多插槽 CPU 服务器上调用多个工作负载实例。 |
|
bool |
False |
快速设置,以延迟模式进行基准测试,其中使用所有物理核心,每个实例 4 个核心。 |
|
bool |
False |
快速设置以启用吞吐量模式进行基准测试,在此模式下使用所有物理核心,并为每个实例分配 1 个 NUMA 节点。 |
|
bool |
False |
默认情况下使用 |
|
bool |
False |
禁用 |
备注
此脚本将设置的环境变量包括以下内容:
环境变量 |
值 |
---|---|
LD_PRELOAD |
根据您设置的旋钮,可能将 /libiomp5.so、/libjemalloc.so、/libtcmalloc.so 添加到 LD_PRELOAD 中。 |
KMP_AFFINITY |
如果预加载 libiomp5.so,则可以将 KMP_AFFINITY 设置为 |
KMP_BLOCKTIME |
如果预加载 libiomp5.so,则将 KMP_BLOCKTIME 设置为“1”。 |
OMP_NUM_THREADS |
|
MALLOC_CONF |
如果 libjemalloc.so 已预加载,则 MALLOC_CONF 将被设置为 |
请注意,该脚本会尊重预先设置的环境变量。例如,如果您在运行脚本之前设置了上述环境变量,则变量的值不会被脚本覆盖。
结论 ¶
在本教程中,我们探讨了各种针对 Intel® Xeon®可扩展处理器的 PyTorch 推理性能优化的高级配置和工具。通过利用 torch.backends.xeon.run_cpu
脚本,我们展示了如何微调线程和内存管理以实现最佳性能。我们涵盖了诸如 NUMA 访问控制、优化的内存分配器如 TCMalloc
和 JeMalloc
以及使用 Intel® OpenMP 进行高效多线程等基本概念。
此外,我们还提供了实用的命令行示例,指导您设置单实例和多实例场景,确保针对特定工作负载进行最佳资源利用。通过理解和应用这些技术,用户可以显著提高其 PyTorch 应用程序在 Intel® Xeon®平台上的效率和速度。
参见:
理解 PyTorch 英特尔 CPU 性能:第一部分 第二部分