使用 run_cpu 脚本优化 Intel® Xeon® 上的 CPU 性能¶
创建于:2024 年 6 月 25 日 | 最后更新:2024 年 8 月 3 日 | 最后验证:2024 年 11 月 5 日
在 Intel® Xeon® 可扩展处理器上执行 PyTorch 推理时,有几种配置选项会影响性能。为了获得最佳性能,PyTorch 提供了 torch.backends.xeon.run_cpu
脚本,该脚本可优化线程和内存管理的配置。对于线程管理,该脚本配置线程亲和性和 Intel® OMP 库的预加载。对于内存管理,它配置 NUMA 绑定并预加载优化内存分配库,例如 TCMalloc 和 JeMalloc。此外,该脚本还为单实例和多实例场景中的计算资源分配提供了可调参数,帮助用户尝试针对特定工作负载优化资源利用协调。
你将学到什么¶
如何利用
numactl
、taskset
、Intel® OpenMP Runtime Library 和优化内存分配器(例如TCMalloc
和JeMalloc
)等工具来增强性能。如何在 Intel® Xeon® 处理器上配置 CPU 资源和内存管理,以最大化 PyTorch 推理性能。
优化介绍¶
应用 NUMA 访问控制¶
在单个插槽中为用户提供越来越多的 CPU 内核是一件有利的事情,因为它提供了更多的计算资源。然而,这也导致了内存访问的竞争,这可能导致程序由于内存繁忙而停滞。为了解决这个问题,引入了非统一内存访问 (NUMA)。与统一内存访问 (UMA) 不同,在 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 Runtime Library¶
OpenMP 是一种多线程实现,一种并行化方法,其中主线程(一系列连续执行的指令)分叉指定数量的子线程,系统将任务分配给它们。然后线程同时运行,运行时环境将线程分配给不同的处理器。用户可以使用一些环境变量设置来控制 OpenMP 的行为以适应其工作负载,设置由 OMP 库读取和执行。默认情况下,PyTorch 使用 GNU OpenMP Library (GNU libgomp) 进行并行计算。在 Intel® 平台,Intel® OpenMP Runtime Library (libiomp) 提供 OpenMP API 规范支持。与 libgomp 相比,它通常能带来更高的性能优势。
可以使用以下任一命令安装 Intel® OpenMP Runtime Library
$ 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 socket) 上运行单实例推理
$ 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 |
“run” |
日志文件名前缀。 |
用于应用或禁用优化的旋钮是
旋钮 |
类型 |
默认值 |
帮助 |
---|---|---|---|
|
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;否则 ncores_per_instance 将按顺序分配给实例。 |
|
bool |
False |
在多插槽 CPU 服务器上调用多个工作负载实例的快速设置。 |
|
bool |
False |
以延迟模式调用基准测试的快速设置,其中使用所有物理内核,每个实例 4 个内核。 |
|
bool |
False |
以吞吐量模式调用基准测试的快速设置,其中使用所有物理内核,每个实例 1 个 numa 节点。 |
|
bool |
False |
默认情况下使用 |
|
bool |
False |
禁用 |
注意
此脚本将设置的环境变量包括以下内容
环境变量 |
值 |
---|---|
LD_PRELOAD |
根据您设置的旋钮,可能会将 <lib>/libiomp5.so, <lib>/libjemalloc.so, <lib>/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® 平台上的效率和速度。
另请参阅