• Tutorials >
  • Optimizing CPU Performance on Intel® Xeon® with run_cpu Script
Shortcuts

使用run_cpu脚本优化Intel® Xeon®的CPU性能

创建日期:2024年6月25日 | 最后更新:2024年8月3日 | 最后验证:2024年11月5日

在英特尔® 至强® 可扩展处理器上执行时,有几个配置选项可能会影响 PyTorch 推理的性能。 为了获得最佳性能,提供了 torch.backends.xeon.run_cpu 脚本,该脚本优化了线程和内存管理的配置。 对于线程管理,脚本配置了线程亲和性和英特尔® OMP 库的预加载。 对于内存管理,它配置了 NUMA 绑定并预加载了优化的内存分配库,如 TCMalloc 和 JeMalloc。 此外,脚本还提供了在单实例和多实例场景下可调节的计算资源分配参数, 帮助用户尝试为特定工作负载找到资源利用的最佳协调方案。

你将学到什么

  • 如何利用诸如numactltaskset、Intel® OpenMP运行时库以及优化的内存分配器如TCMallocJeMalloc等工具来提升性能。

  • 如何配置CPU资源和内存管理以在Intel® Xeon®处理器上最大化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

使用英特尔® 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

选择优化的内存分配器

从性能角度来看,内存分配器也扮演着重要角色。更高效的内存使用减少了不必要的内存分配或销毁的开销,从而加快了执行速度。根据实践经验,对于深度学习工作负载,TCMallocJeMalloc 通过尽可能重用内存,可以获得比默认的 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核心上使用1个线程运行单实例推理(仅使用核心#0):

$ python -m torch.backends.xeon.run_cpu --ninstances 1 --ncores-per-instance 1 <program.py> [program_args]
  1. 在单个CPU节点(NUMA插槽)上运行单实例推理:

$ python -m torch.backends.xeon.run_cpu --node-id 0 <program.py> [program_args]
  1. 要运行多实例推理,在112核CPU上每个实例14核的8个实例:

$ python -m torch.backends.xeon.run_cpu --ninstances 8 --ncores-per-instance 14 <program.py> [program_args]
  1. 要在吞吐量模式下运行推理,其中每个CPU节点中的所有核心都设置一个实例:

$ python -m torch.backends.xeon.run_cpu --throughput-mode <program.py> [program_args]

注意

这里的术语“instance”并不是指云实例。这个脚本作为一个单一进程执行,该进程调用由多个线程形成的多个“instances”。在这个上下文中,“instance”是一种线程组。

使用 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]

上面的命令有以下位置参数:

旋钮

帮助

program

要启动的程序/脚本的完整路径。

program_args

要启动的程序/脚本的输入参数。

选项的解释

通用选项设置(旋钮)包括以下内容:

旋钮

类型

默认值

帮助

-h, --help

显示帮助信息并退出。

-m, --module

将每个进程更改为将启动脚本解释为python模块,执行与“python -m”相同的行为。

--no-python

布尔

为了避免在程序前加上“python” - 直接执行它。当脚本不是Python脚本时很有用。

--log-path

字符串

''

指定日志文件目录。默认路径是'',这意味着禁用日志记录到文件。

--log-file-prefix

字符串

“运行”

日志文件名的前缀。

用于应用或禁用优化的旋钮有:

旋钮

类型

默认值

帮助

--启用tcmalloc

布尔

启用TCMalloc内存分配器。

--enable-jemalloc

布尔

启用JeMalloc内存分配器。

--使用默认分配器

布尔

使用默认的内存分配器。既不会使用TCMalloc也不会使用JeMalloc

--disable-iomp

布尔

默认情况下,如果安装了Intel® OpenMP库,将会使用它。设置此标志将禁用Intel® OpenMP的使用。

注意

内存分配器影响性能。如果用户没有指定所需的内存分配器,run_cpu脚本将按照TCMalloc > JeMalloc > PyTorch默认内存分配器的顺序搜索是否安装了其中任何一个,并采用第一个匹配的分配器。

用于控制实例数量和计算资源分配的旋钮有:

旋钮

类型

默认值

帮助

--ninstances

整数

0

实例数量。

--每个实例的核心数

整数

0

每个实例使用的核心数。

--节点ID

整数

-1

用于多实例的节点ID,默认情况下将使用所有节点。

--核心列表

字符串

''

要指定核心列表为'core_id, core_id, ....'或核心范围为'core_id-core_id'。默认情况下,将使用所有核心。

--使用逻辑核心

布尔

默认情况下仅使用物理核心。指定此标志可启用逻辑核心的使用。

--skip-cross-node-cores

布尔

为了防止工作负载在跨NUMA节点的核心上执行。

--rank

整数

-1

指定实例索引以分配ncores_per_instance给rank;否则ncores_per_instance将按顺序分配给实例。

--多实例

布尔

快速设置以在多插槽CPU服务器上调用多个工作负载实例。

--latency-mode

布尔

快速设置以调用延迟模式下的基准测试,其中使用所有物理核心,每个实例使用4个核心。

--吞吐量模式

布尔

快速设置以调用吞吐量模式的基准测试,其中使用所有物理核心,并且每个实例使用1个NUMA节点。

--disable-numactl

布尔

默认情况下,numactl 命令用于控制 NUMA 访问。设置此标志将禁用它。

--disable-taskset

布尔

禁用taskset命令的使用。

注意

此脚本将设置的环境变量包括以下内容:

环境变量

LD_PRELOAD

根据您设置的旋钮,/libiomp5.so、/libjemalloc.so、/libtcmalloc.so 可能会附加到 LD_PRELOAD。

KMP_AFFINITY

如果预加载了libiomp5.so,可以将KMP_AFFINITY设置为"granularity=fine,compact,1,0"

KMP_BLOCKTIME

如果预加载了libiomp5.so,KMP_BLOCKTIME将被设置为“1”。

OMP_NUM_THREADS

ncores_per_instance 的值

MALLOC_CONF

如果预加载了libjemalloc.so,MALLOC_CONF将被设置为"oversize_threshold:1,background_thread:true,metadata_thp:auto"

请注意,脚本会尊重预先设置的环境变量。例如,如果您在运行脚本之前已经设置了上述环境变量,脚本不会覆盖这些变量的值。

结论

在本教程中,我们探索了各种高级配置和工具,旨在优化PyTorch在Intel® Xeon®可扩展处理器上的推理性能。通过利用torch.backends.xeon.run_cpu脚本,我们展示了如何微调线程和内存管理以实现最佳性能。我们涵盖了关键概念,如NUMA访问控制、优化的内存分配器如TCMallocJeMalloc,以及使用Intel® OpenMP进行高效的多线程处理。

此外,我们提供了实用的命令行示例,指导您设置单实例和多实例场景,确保根据特定工作负载优化资源利用率。 通过理解和应用这些技术,用户可以显著提高其PyTorch应用程序在Intel® Xeon®平台上的效率和速度。

另请参阅:

优云智算