Unified 與 System Memory (Unified and System Memory)

重點總覽

異質系統有多個實體記憶體(host DRAM、每個 GPU 各自的 DRAM)。資料位於存取它的 processor 記憶體中時效能最佳。CUDA 提供明確管理記憶體放置的 API,但繁瑣;本筆記介紹簡化配置、放置與遷移的特性。

項目 重點
UVA(Unified Virtual Address Space) host 與所有 GPU 記憶體共用單一虛擬位址空間;指標即可判斷記憶體位置
Unified Memory(managed memory) 可同時被 CPU 與 GPU 程式碼存取;可自動在 CPU/GPU 間遷移
配置 managed memory cudaMallocManagedcudaMallocFromPoolAsync(managed pool)、__managed__ 全域變數
Unified Memory paradigms 4 種模式,由 3 個 device attribute 決定(concurrent / pageable / hostPageTables)
Full support(pageable) cudaDevAttrPageableMemoryAccess=1 時所有 system memory 皆為 unified memory
Hardware coherency(ATS) Grace Hopper/Blackwell + NVLink C2C;cache line 粒度;支援 native atomics
HMM(software coherency) Linux kernel 功能;page 粒度;PCIe-connected GPU 也能有 full unified memory
Limited support Windows/WSL/部分 Tegra;只支援 CUDA 明確配置的 managed memory、不可 oversubscribe
Memory advise / prefetch cudaMemAdvise 給放置提示;cudaMemPrefetchAsync 非同步預先搬移資料
Page-locked(pinned)memory 非 pageable;async copy 必要、提升 sync copy 效能、可 map 給 GPU
Mapped memory 直接從 kernel 存取 host memory(zero-copy);走 PCIe/NVLink、高延遲低頻寬
API cudaMallocHost/cudaHostAlloc/cudaFreeHost/cudaHostRegister/cudaHostGetDevicePointer
Tip

Unified memory 有多種型態,取決於 OS、driver 版本、kernel 版本、GPU 硬體與 GPU-CPU interconnect。寫可攜程式時應先用 cudaDeviceGetAttribute 查詢能力,再決定行為。


Unified Virtual Address Space(UVA)

單一 OS process 內,所有 host memory 與所有 GPU 上的 global memory 共用一個虛擬位址空間。無論用 CUDA API(cudaMalloccudaMallocHost)或 system API(newmallocmmap)配置,記憶體都落在這個位址空間中,CPU 與每個 GPU 各佔一段獨特範圍。

            單一虛擬位址空間 (UVA)
 ┌───────────┬───────────┬───────────┐
 │  CPU 範圍 │ GPU0 範圍 │ GPU1 範圍 │ ...
 └───────────┴───────────┴───────────┘
   ↑ 指標值就能判斷它屬於哪個 processor
Tip

因為有 UVA,舊版需要的 mapping 旗標(cudaSetDeviceFlags 搭配 cudaDeviceMapHost)已不再需要。


Unified Memory(managed memory)

Unified memory 是讓一種稱為 managed memory 的配置可同時被 CPU 或 GPU 程式碼存取的 CUDA 特性,且能在 CPU/GPU 間自動遷移。所有 CUDA 支援的系統都有 unified memory。

在某些系統上 managed memory 必須明確配置,方式有三:

Important

在有 HMMATS 的系統上,所有 system memory 都隱含是 managed memory,無論如何配置,都不需要特別配置。


Unified Memory Paradigms(4 種模式與判斷)

unified memory 的特性與行為隨 OS、Linux kernel 版本、GPU 硬體、GPU-CPU interconnect 而不同。可用 cudaDeviceGetAttribute 查詢三個屬性來判斷型態:

Device Attribute 意義
cudaDevAttrConcurrentManagedAccess 1 = full support;0 = limited support
cudaDevAttrPageableMemoryAccess 1 = 所有 system memory 皆 full-support unified;0 = 只有明確配置的 managed memory
cudaDevAttrPageableMemoryAccessUsesHostPageTables coherence 機制:1 = hardware,0 = software

四種 paradigm:

Paradigm 判斷條件
Limited unified memory ConcurrentManagedAccess = 0(Windows / WSL / Tegra)
Full(僅 explicit managed) ConcurrentManagedAccess = 1 且 PageableMemoryAccess = 0
Full(all allocations, software coherence) 上者皆 1,且 ...UsesHostPageTables = 0(HMM)
Full(all allocations, hardware coherence) 上者皆 1,且 ...UsesHostPageTables = 1(ATS)
   有 unified memory?  (所有現代 GPU 皆有 UVA + unified memory)
            │
   ConcurrentManagedAccess == 1 ?
       ├── 0 ──► Limited support(Windows/WSL/Tegra)
       └── 1 ──► Full support
                   │
            PageableMemoryAccess == 1 ?
              ├── 0 ──► 只有 CUDA 配置的 managed memory 是 unified
              └── 1 ──► 所有 system memory 都是 unified
                         │
                  UsesHostPageTables == 1 ?
                    ├── 1 ──► Hardware coherence (ATS)
                    └── 0 ──► Software coherence (HMM)

查詢與判斷邏輯的精簡程式碼:

cudaDeviceGetAttribute(&concurrentManagedAccess,
                       cudaDevAttrConcurrentManagedAccess, deviceId);
cudaDeviceGetAttribute(&pageableMemoryAccess,
                       cudaDevAttrPageableMemoryAccess, deviceId);
cudaDeviceGetAttribute(&pageableMemoryAccessUsesHostPageTables,
                       cudaDevAttrPageableMemoryAccessUsesHostPageTables, deviceId);

if (concurrentManagedAccess) {
  if (pageableMemoryAccess)
    // full support;UsesHostPageTables=1 為 hardware,0 為 software coherency
    ;
  else
    // full support,僅限 CUDA 配置的 managed allocations
    ;
} else {
  // limited support: Windows, WSL, or Tegra
}

此即把上面的決策樹翻成程式碼,逐 GPU(cudaGetDeviceCount/cudaSetDevice)查詢能力。


Full Unified Memory Feature Support

大多數 Linux 系統有 full unified memory 支援。

full support 下 managed 配置的一般行為:

Warning

上述配置與遷移行為可能偏離,程式設計者可用 hints 與 prefetch 影響它。

Hardware Coherency(ATS)

在如 Grace Hopper、Grace Blackwell 這類使用 NVIDIA CPU 且 CPU-GPU 以 NVLink Chip-to-Chip(C2C) 相連的硬體上,可使用 Address Translation Services(ATS)。此時 cudaDevAttrPageableMemoryAccessUsesHostPageTables = 1。

除了對所有 host 配置都有 full unified memory 支援外,ATS 還提供:

Warning

Hardware coherency 讓 host 存取 GPU-only 配置(如 cudaMalloc 配置的記憶體)。ATS 提供 HMM 的所有能力;當 ATS 可用時,HMM 會自動停用

HMM(Software Coherency)

Heterogeneous Memory Management(HMM) 是 Linux(需適當 kernel 版本)的功能,提供 software-coherent 的 full unified memory,把 ATS 的部分便利帶給 PCIe-connected GPU

$ nvidia-smi -q | grep Addressing
Addressing Mode : HMM
比較 Hardware Coherency(ATS) Software Coherency(HMM)
啟用條件 NVIDIA CPU + NVLink C2C Linux kernel ≥ 6.1.24/6.2.11/6.3
GPU 連接 NVLink C2C PCIe
屬性旗標 ...UsesHostPageTables = 1 ...UsesHostPageTables = 0
粒度 cache line memory page
native atomics 支援
優先級 有 ATS 時自動停用 HMM 被 ATS 取代

Limited Unified Memory Support

Windows(含 WSL) 與部分 Tegra 系統上,只有 unified memory 的有限子集。managed memory 仍可用,但 CPU/GPU 間遷移行為不同:

Warning

在 limited support 系統上,違反「GPU 活動時 CPU 不可存取 managed memory」會造成問題;這與 full support(CPU/GPU 可並行存取)形成關鍵差異。


Memory Advise 與 Prefetch

程式設計者可給 NVIDIA Driver 提示,協助最大化效能。

API 用途
cudaMemAdvise 指定配置的屬性,影響其放置位置以及被其他 device 存取時是否遷移
cudaMemPrefetchAsync 建議非同步地把特定配置搬移到別處
Tip

cudaMemPrefetchAsync 常見用法:在 kernel 啟動就開始搬移它將用到的資料,讓資料搬運與其他 GPU kernel 執行重疊,藏住延遲。


Page-Locked Host Memory(pinned memory)

cudaMallocHost 配置的是 host 上的 page-locked memory(又稱 pinned memory)。用 mallocnewmmap 等傳統機制配置的 host 記憶體不是 page-locked,可能被 OS 換出(swap)到磁碟或實體搬移。

API 功能
cudaMallocHost 配置 page-locked host memory
cudaHostAlloc 預設同 cudaMallocHost,但多收 flags 指定其他記憶體參數
cudaFreeHost 釋放 cudaMallocHost / cudaHostAlloc 配置的記憶體
cudaHostRegister 已存在(如 malloc/mmap)的記憶體區間 page-lock
Important

cudaHostRegister 讓開發者無法控制的 3rd party library 或外部程式配置的 host 記憶體也能被 page-lock,以用於 async copy 或 mapping。Page-locked host memory 可被系統中所有 GPU 用於 async copy 與 mapped memory。

Warning

在 non I/O coherent 的 Tegra device 上,page-locked host memory 不被快取,且不支援 cudaHostRegister()


Mapped Memory(zero-copy)

在有 HMM 或 ATS 的系統上,所有 host memory 都能用 host 指標直接從 GPU 存取。當 ATS/HMM 不可用時,可把 host 配置 map 進 GPU 記憶體空間讓 GPU 存取。Mapped memory 一律是 page-locked

範例 kernel(直接操作 mapped host memory):

__global__ void copyKernel(float* a, float* b)
{
    int idx = threadIdx.x + blockDim.x * blockIdx.x;
    a[idx] = b[idx];
}
Warning

Mapped memory 留在 CPU 記憶體,kernel 中存取需經 CPU-GPU interconnect(PCIe 或 NVLink C2C)交易,延遲較高、頻寬較低。不應把它當成 unified memory 或明確記憶體管理的高效替代品,用於 kernel 大部分的記憶體需求。

  cudaMallocHost / cudaHostAlloc:用同一個 host 指標
    GPU kernel ──(PCIe / NVLink C2C)──► [ Host (pinned) memory ]
                                          ↑ 資料始終留在 CPU 端

  cudaHostRegister:需轉換成 device 指標
    malloc 配置 ──► cudaHostRegister ──► cudaHostGetDevicePointer
    kernel 用 devPtr ─(interconnect)─► host memory

cudaMallocHost / cudaHostAlloc

cudaMallocHostcudaHostAlloc 配置的 host 記憶體會自動被 mapped。回傳的指標可直接用在 kernel 中存取 host 上的記憶體(經 CPU-GPU interconnect)。

// cudaMallocHost:指標可直接傳給 kernel
CUDA_CHECK(cudaMallocHost(&a, vLen*sizeof(float)));
CUDA_CHECK(cudaMallocHost(&b, vLen*sizeof(float)));
int blocks = vLen / threads;
copyKernel<<<blocks, threads>>>(a, b);   // 直接用 host 指標

// cudaHostAlloc:用 flag 指定 mapped
CUDA_CHECK(cudaHostAlloc(&a, vLen*sizeof(float), cudaHostAllocMapped));
copyKernel<<<blocks, threads>>>(a, b);

重點:cudaHostAlloc 需傳 cudaHostAllocMapped 之類的 flag;兩者回傳的 host 指標都能直接在 kernel 使用。

cudaHostRegister

當 ATS/HMM 不可用時,system allocator 配置的記憶體仍可用 cudaHostRegister map 供 kernel 直接存取。但與 CUDA API 配置不同,不能用 host 指標在 kernel 存取,必須用 cudaHostGetDevicePointer() 取得 device 區域的指標,並在 kernel 中使用該指標。

a = (float*)malloc(vLen*sizeof(float));
CUDA_CHECK(cudaHostRegister(a, vLen*sizeof(float), 0));
CUDA_CHECK(cudaHostGetDevicePointer((void**)&devA, (void*)a, 0));
// kernel 必須使用 devA(device 指標),不可用 a
copyKernel<<<blocks, threads>>>(devA, devB);

重點:cudaHostRegister + cudaHostGetDevicePointer 是用 host 指標 a 與 device 指標 devA 兩個不同指標

Unified Memory vs Mapped Memory

比較 Mapped Memory Unified Memory
資料所在 一直留在 CPU 記憶體 通常遷移到存取它的 processor 記憶體
存取路徑 每次都走 PCIe/NVLink 首次遷移後可用完整 GPU 記憶體頻寬
atomics 支援 不保證所有系統支援所有存取型態 保證所有存取型態都支援
效能 高延遲、低頻寬,難充分利用 GPU 反覆存取同一 page/cache line 效能高
別名 舊文件稱 zero-copy memory
Warning

對 mapped host memory 的 atomic 函式,從 host 或其他 GPU 的角度看不是 atomic。CUDA runtime 要求 1/2/4/8/16-byte 自然對齊的 load/store 須保持為單一存取;不支援會把 8-byte 自然對齊操作拆開的 PCIe bridge topology。


考試/測驗重點

情境/關鍵字 答案
由指標判斷記憶體在 CPU 或哪個 GPU cudaPointerGetAttributes()(靠 UVA)
不想指定 copy 方向 cudaMemcpyDefault(自動判斷)
配置 managed memory 的三種方式 cudaMallocManagedcudaMallocFromPoolAsync(managed pool)、__managed__ 全域變數
判斷 full vs limited unified memory cudaDevAttrConcurrentManagedAccess(1=full,0=limited)
判斷所有 system memory 是否皆 unified cudaDevAttrPageableMemoryAccess(1=是)
判斷 hardware 還是 software coherence cudaDevAttrPageableMemoryAccessUsesHostPageTables(1=hardware,0=software)
ATS 出現於哪種硬體 Grace Hopper / Grace Blackwell + NVLink C2C;HMM 自動停用
HMM 是什麼 Linux kernel 的 software-coherency full unified memory;PCIe GPU 適用
HMM 需要的 kernel 版本 ≥ 6.1.24 / 6.2.11 / 6.3
查 addressing mode 是否 HMM nvidia-smi -q | grep Addressing
coherence 粒度 software=memory page;hardware=cache line
oversubscription full support 允許;limited support 不允許
limited support 平台 Windows、WSL、部分 Tegra
limited support 陷阱 GPU 活動時 CPU 不可存取 managed memory;GPU 同步時才遷回
hardware coherency 能否從 host 存取 cudaMalloc 記憶體 不能(GPU-only 配置)
async copy 必要條件 host 端須是 page-locked(pinned)memory
page-lock 既有 host 配置 cudaHostRegister(搭配 cudaHostGetDevicePointer
cudaMallocHost vs cudaHostAlloc 後者多收 flags(如 cudaHostAllocMapped
釋放 pinned memory cudaFreeHost(非 free
mapped memory 舊名 zero-copy memory
cudaHostRegister 的指標陷阱 kernel 必須用 device 指標(cudaHostGetDevicePointer),不能用 host 指標
mapped memory atomics 對 host/其他 GPU 而言不是 atomic
不支援 cudaHostRegister 的平台 non I/O coherent Tegra device
cudaDeviceMapHost / cudaSetDeviceFlags 因 UVA 已不再需要