基於親和性的 GPU 容器核心綁定策略

基於親和性的 GPU 容器核心綁定策略

優化 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 了解更多詳情!

single numa