• Tutorials >
  • 通过run_cpu脚本优化Intel® Xeon®上的CPU性能
Shortcuts

通过run_cpu脚本优化Intel® Xeon®上的CPU性能

Created On: Jun 25, 2024 | Last Updated: Aug 03, 2024 | Last Verified: Nov 05, 2024

有多种配置选项会影响在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调度或内存放置策略运行进程。如上所述,核心在一个插槽内共享高速缓存,因此避免跨插槽计算是一个好主意。从内存访问的角度来看,限制在本地内存访问比访问远程内存快得多。最新的Linux分发版中应该已经安装``numactl``命令。如果缺失,您可以通过安装命令手动安装,例如在Ubuntu上:

$ apt-get install numactl

在CentOS上,您可以运行以下命令:

$ yum install numactl

Linux中的``taskset``命令是另一个强大的实用程序,它允许您设置或检索正在运行的进程的CPU亲和性。大多数Linux分发版中预安装了``taskset``,如果没有,在Ubuntu上您可以通过以下命令安装:

$ apt-get install util-linux

在CentOS上,您可以运行以下命令:

$ yum install util-linux

使用Intel® OpenMP运行时库

OpenMP是一种多线程实现,通过它一个主线程(一系列连续执行的指令)派生出指定数量的子线程,系统将任务分配给它们并行执行。子线程同时运行,运行时环境将线程分配给不同的处理器。用户可以通过一些环境变量设置控制OpenMP行为来适合其工作负载,这些设置由OMP库读取并执行。默认情况下,PyTorch使用GNU OpenMP库(GNU libgomp)进行并行计算。在Intel®平台上,Intel® OpenMP Runtime Library(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个线程在1个CPU核心(仅使用核心#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]

备注

术语“实例”在此处并不指代云实例。这个脚本作为单个进程执行,它调用多个由多个线程组成的“实例”。在此上下文中,“实例”是一类线程组。

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

上述命令包含以下位置参数:

knob

帮助

program

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

program_args

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

选项解释

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

knob

类型

默认值

帮助

-h--help

显示帮助信息并退出。

-m--module

更改每个进程以将启动脚本解释为Python模块,行为类似于“python -m”。

--no-python

布尔值

False

避免在程序前加上“python”,直接执行它。适用于脚本不是Python脚本的情况。

--log-path

字符串

&apos;&apos;

指定日志文件目录。默认路径为``&apos;&apos;``,表示禁用文件日志记录。

--log-file-prefix

字符串

run

日志文件名的前缀。

用于应用或禁用优化的选项有:

knob

类型

默认值

帮助

--enable-tcmalloc

布尔值

False

启用``TCMalloc``内存分配器。

--enable-jemalloc

布尔值

False

启用``JeMalloc``内存分配器。

--use-default-allocator

布尔值

False

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

--disable-iomp

布尔值

False

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

备注

内存分配器会影响性能。如果用户未指定所需的内存分配器,``run_cpu``脚本将按TCMalloc > JeMalloc > PyTorch默认内存分配器的顺序搜索是否有安装的,选择第一个匹配项。

控制实例数量和计算资源分配的选项有:

knob

类型

默认值

帮助

--ninstances

整数

0

实例数量。

--ncores-per-instance

整数

0

每个实例使用的核心数。

--node-id

整数

-1

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

--core-list

字符串

&apos;&apos;

指定核心列表为``&apos;core_id, core_id, ….&apos;``或核心范围为``&apos;core_id-core_id&apos;``。默认使用所有核心。

--use-logical-core

布尔值

False

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

--skip-cross-node-cores

布尔值

False

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

--rank

整数

-1

为排名指定实例索引,以分配ncores_per_instance;否则ncores_per_instance将顺序分配给实例。

--multi-instance

布尔值

False

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

--latency-mode

布尔值

False

快速设置以延迟模式启动基准测试,所有物理核心被使用,每个实例使用4个核心。

--throughput-mode

布尔值

False

快速设置以吞吐量模式启动基准测试,所有物理核心被使用,每个实例使用1个NUMA节点。

--disable-numactl

布尔值

False

默认情况下使用``numactl``命令来控制NUMA访问。设置此标志将禁用该功能。

--disable-taskset

布尔值

False

禁用``taskset``命令的使用。

备注

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

环境变量

LD_PRELOAD

根据您设置的选项,<lib>/libiomp5.so、<lib>/libjemalloc.so、<lib>/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® 平台上的效率和速度。

另请参见:

文档

访问 PyTorch 的详细开发者文档

查看文档

教程

获取针对初学者和高级开发人员的深入教程

查看教程

资源

查找开发资源并获得问题的解答

查看资源