優化 CPU 與 GPU 效能的介紹
在高效能運算與大規模並行任務處理中,GPU 已成為不可或缺的加速器。為了充分發揮 GPU 的運算能力,必須透過合理分配並綁定 CPU 核心至 GPU 來優化 CPU 與 GPU 的關係。本文將深入探討 Socket 與 NUMA(非均勻記憶體存取)的概念,並討論如何基於這些硬體架構實作 CPU 與 GPU 核心綁定,以確保系統達到最佳效能。
Socket 概念
什麼是 Socket?
Socket 通常指主機板上安裝實體 CPU 的插槽。每個 Socket 對應一顆實體 CPU,通常包含多個核心以及一層或多層快取(例如 L1、L2、L3 快取)。在多 Socket 系統(例如雙路或四路伺服器)中,每個 Socket 各有一顆實體 CPU,並透過高速互連(例如 Intel 的 QPI 或 AMD 的 Infinity Fabric)相連。
多 Socket 系統的特性
在多 Socket 系統中,每個 Socket 的 CPU 不僅可以存取自己的本地記憶體,也能存取其他 Socket 的記憶體。這種記憶體存取模式引入了 NUMA 的概念,目的在於最佳化記憶體存取效率。
NUMA(非均勻記憶體存取)架構
什麼是 NUMA?
NUMA 全稱為 Non-Uniform Memory Access,即非均勻記憶體存取。與傳統的均勻記憶體存取(UMA)不同,在 NUMA 架構中,系統記憶體被劃分為多個區域,每個區域與特定的 CPU(Socket)相關聯。存取本地記憶體(同一個 Socket 內)比存取遠端記憶體(來自其他 Socket)更快,因此延遲較高。
NUMA 節點與記憶體存取延遲
在 NUMA 系統中,每個 Socket 與其直接連接的記憶體形成一個 NUMA 節點。同一 NUMA 節點內的記憶體存取速度較快,而跨節點存取則因額外的匯流排傳輸而產生較高的延遲。最佳化記憶體與 CPU 的親和性,確保任務在同一 NUMA 節點內執行,是關鍵的效能優化步驟。
CPU 與 GPU 的實體關係
GPU 硬體架構
GPU 通常透過 PCIe(Peripheral Component Interconnect Express)匯流排與 CPU 通訊。在多 Socket 系統中,GPU 通常只連接到一個 Socket(及其對應的 NUMA 節點),而不會跨 Socket 連接。這表示在實際運作中,GPU 與其所連接的 Socket 的 CPU 核心及記憶體之間具有更高的頻寬與更低的延遲。
CPU 與 GPU 的親和性
CPU 與 GPU 之間的通訊主要依賴資料傳輸。資料從 CPU 傳輸到 GPU,再傳回 CPU,這個過程涉及記憶體存取操作,對效能影響很大。如果 GPU 所綁定的 CPU 核心與 GPU 位於同一個 NUMA 節點內,資料傳輸延遲將會顯著降低。因此,將 CPU 核心綁定至 GPU 是關鍵的效能優化步驟。
基於親和性的 GPU 與 CPU 核心綁定策略
在 Docker 容器化部署中,實作 GPU 與 CPU 的親和性綁定對於提升容器化任務的效能至關重要。Docker 的 CPU 與 GPU 資源控制功能允許精確控制容器使用的 CPU 核心與 GPU 裝置。
容器的 CPU 與 GPU 資源分配
Docker 容器允許精確控制分配到的 CPU 與 GPU 資源。透過指定容器使用的 CPU 核心與 GPU 裝置,可以實作親和性綁定以最佳化效能。
Docker CPU 設定
在 Docker 中,可以使用以下參數控制 CPU 資源分配:
--cpuset-cpus:指定容器可以使用的實體 CPU 核心。例如--cpuset-cpus="0-3"將容器限制為使用 CPU 核心 0 到 3。--cpu-shares:控制容器的 CPU 使用權重,但不限制特定核心的使用。--cpus:限制容器可以使用的 CPU 核心總數(以虛擬核心為單位)。
Docker GPU 設定
可以使用以下 Docker 參數綁定 GPU 裝置:
--gpus:指定容器可以存取的 GPU 裝置。例如--gpus '"device=0"'將 GPU 0 分配給容器。
在 Docker 中實作 GPU 與 CPU 核心綁定
要在 Docker 容器中實作 GPU 與 CPU 核心綁定,需要結合 CPU 與 GPU 設定。以下是在啟動 Docker 容器時綁定特定 CPU 核心與 GPU 的範例:
docker run --cpuset-cpus="0-3" --gpus '"device=0"' --memory="8g" my_gpu_container
在此命令中:
--cpuset-cpus="0-3"將容器綁定到 CPU 核心 0 到 3,這些核心應與 GPU 0 位於同一個 NUMA 節點內。--gpus '"device=0"'將 GPU 0 分配給容器。--memory="8g"將容器的記憶體使用量限制為 8 GB,確保記憶體分配也與 CPU/GPU 親和性一致。
達到最佳綁定
為了在容器中達到最佳綁定,首先需要確定機器的實體拓撲。使用 nvidia-smi topo -m 查看機器的拓撲:
nvidia-smi topo -m
從輸出結果可以判斷機器的 NUMA 配置與 GPU 分配。例如,如果機器有兩個 NUMA 節點,NUMA 0 有 4 個 GPU,NUMA 1 有 4 個 GPU,你就可以找出每個 NUMA 節點的 GPU 與 CPU 親和性。
親和性計算的虛擬碼
以下是簡化的親和性計算虛擬碼,用於決定 GPU 與 CPU ID:
type Affinity struct {
}
// 計算親和性是否滿足,並回傳對應的 GPU 與 CPU ID
func calAffinity(affinity *Affinity, cpuUse [ ]int, gpuUse [ ]int, gpuReq int, cpuReq int) (bool, [ ]int, [ ]int) {
return true, [ ]int{}, [ ]int{}
}
這個方法可以用來判斷節點是否滿足最佳綁定需求。當存在多個節點時,可以使用這個方法進行評估並選擇最合適的節點。Novita AI 開發了一個專為下一代 AI 運算設計的容器引擎,能夠動態調整演算法,即時監控硬體使用情況並進行端到端最佳化。使用者可以享受最強的運算效能,無需擔心 NUMA 的技術細節。
使用者也可以在控制面板中進行更高階的 NUMA 設定。如果您有更多相關需求,歡迎在 Discord 上與我們聯絡!
造訪 Novita AI 了解更多詳情!

