使用 run_cpu 指令碼最佳化 Intel® Xeon® 上的 CPU 效能#
創建於:2024 年 6 月 25 日 | 最後更新:2025 年 7 月 1 日 | 最後驗證:2024 年 11 月 5 日
在 Intel® Xeon® 可擴充套件處理器上執行 PyTorch 推理時,有幾種配置選項會影響效能。為了獲得最佳效能,我們提供了 torch.backends.xeon.run_cpu 指令碼,該指令碼可最佳化執行緒和記憶體管理配置。對於執行緒管理,該指令碼配置執行緒親和性和 Intel® OMP 庫的預載入。對於記憶體管理,它配置 NUMA 繫結並預載入最佳化的記憶體分配庫,例如 TCMalloc 和 JeMalloc。此外,該指令碼為單例項和多例項場景中的計算資源分配提供了可調引數,幫助使用者嘗試針對特定工作負載最佳化資源利用率的協調。
您將學到什麼#
如何利用
numactl、taskset、Intel® OpenMP 執行時庫以及TCMalloc和JeMalloc等最佳化記憶體分配器來提升效能。如何配置 CPU 資源和記憶體管理,以最大化 PyTorch 在 Intel® Xeon® 處理器上的推理效能。
最佳化介紹#
應用 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 個 CPU 核心上的 1 個執行緒執行單例項推理(僅使用核心 #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 上,每個例項使用 14 核,共 8 個例項
$ 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]
上述命令具有以下位置引數
knob |
help |
|---|---|
|
要啟動的程式/指令碼的完整路徑。 |
|
要啟動的程式/指令碼的輸入引數。 |
選項說明#
通用選項設定(knobs)包括以下內容
knob |
type |
預設值 |
help |
|---|---|---|---|
|
顯示幫助訊息並退出。 |
||
|
將每個程序解釋為 Python 模組,以與“python -m”相同的行為執行。 |
||
|
布林值 |
假 |
避免在程式前新增“python” - 直接執行。當指令碼不是 Python 指令碼時很有用。 |
|
str |
|
指定日誌檔案目錄。預設路徑為 |
|
str |
“run” |
日誌檔名中的字首。 |
用於應用或停用最佳化的 knobs 是
knob |
type |
預設值 |
help |
|---|---|---|---|
|
布林值 |
假 |
啟用 |
|
布林值 |
假 |
啟用 |
|
布林值 |
假 |
使用預設記憶體分配器。不會使用 |
|
布林值 |
假 |
預設情況下,如果安裝了 Intel® OpenMP 庫,將使用它。設定此標誌將停用 Intel® OpenMP 的使用。 |
注意
記憶體分配器會影響效能。如果使用者未指定所需的記憶體分配器,run_cpu 指令碼將按 TCMalloc > JeMalloc > PyTorch 預設記憶體分配器的順序搜尋是否安裝了其中任何一個,並採用第一個匹配的。
用於控制例項數量和計算資源分配的 knobs 是
knob |
type |
預設值 |
help |
|---|---|---|---|
|
int |
0 |
例項數量。 |
|
int |
0 |
每個例項使用的核心數。 |
|
int |
-1 |
多例項使用的節點 ID,預設使用所有節點。 |
|
str |
|
指定核心列表,格式為 |
|
布林值 |
假 |
預設只使用物理核心。指定此標誌可啟用邏輯核心的使用。 |
|
布林值 |
假 |
防止工作負載在跨 NUMA 節點的上執行。 |
|
int |
-1 |
指定例項索引以分配 ncores_per_instance;否則 ncores_per_instance 將按順序分配給例項。 |
|
布林值 |
假 |
在多插槽 CPU 伺服器上呼叫工作負載多個例項的快速設定。 |
|
布林值 |
假 |
呼叫延遲模式基準測試的快速設定,其中使用所有物理核心,每個例項使用 4 個核心。 |
|
布林值 |
假 |
呼叫吞吐量模式基準測試的快速設定,其中使用所有物理核心,每個例項使用 1 個 numa 節點。 |
|
布林值 |
假 |
預設情況下, |
|
布林值 |
假 |
停用 |
注意
此指令碼將設定的環境變數包括以下內容
環境變數 |
值 |
|---|---|
LD_PRELOAD |
根據您設定的 knobs,可能會將 <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® 平臺上的效率和速度。
另請參閱