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 | cudaMallocManaged、cudaMallocFromPoolAsync(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 |
Unified memory 有多種型態,取決於 OS、driver 版本、kernel 版本、GPU 硬體與 GPU-CPU interconnect。寫可攜程式時應先用 cudaDeviceGetAttribute 查詢能力,再決定行為。
Unified Virtual Address Space(UVA)
單一 OS process 內,所有 host memory 與所有 GPU 上的 global memory 共用一個虛擬位址空間。無論用 CUDA API(cudaMalloc、cudaMallocHost)或 system API(new、malloc、mmap)配置,記憶體都落在這個位址空間中,CPU 與每個 GPU 各佔一段獨特範圍。
- 任何記憶體的位置(在 CPU 或哪個 GPU)都可由指標值用
cudaPointerGetAttributes()判斷。 cudaMemcpy*()的cudaMemcpyKind可設為cudaMemcpyDefault,由指標自動判斷複製方向。
單一虛擬位址空間 (UVA)
┌───────────┬───────────┬───────────┐
│ CPU 範圍 │ GPU0 範圍 │ GPU1 範圍 │ ...
└───────────┴───────────┴───────────┘
↑ 指標值就能判斷它屬於哪個 processor
因為有 UVA,舊版需要的 mapping 旗標(cudaSetDeviceFlags 搭配 cudaDeviceMapHost)已不再需要。
Unified Memory(managed memory)
Unified memory 是讓一種稱為 managed memory 的配置可同時被 CPU 或 GPU 程式碼存取的 CUDA 特性,且能在 CPU/GPU 間自動遷移。所有 CUDA 支援的系統都有 unified memory。
在某些系統上 managed memory 必須明確配置,方式有三:
- CUDA API
cudaMallocManaged cudaMallocFromPoolAsync,pool 以allocType = cudaMemAllocationTypeManaged建立- 帶
__managed__specifier 的全域變數
在有 HMM 或 ATS 的系統上,所有 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 支援。
- 若
cudaDevAttrPageableMemoryAccess= 1:所有 system memory(無論 CUDA API 或 system API 配置)都以 full feature 的 unified memory 運作,包含mmap建立的 file-backed 配置。 - 若 = 0:只有 CUDA 配置為 managed 的記憶體才是 unified;system API 配置的記憶體未被管理,不保證能從 GPU kernel 存取。
full support 下 managed 配置的一般行為:
- 通常配置在**第一次被觸碰(first touch)**的 processor 記憶體空間。
- 當被目前所在以外的 processor 使用時,通常會遷移。
- 遷移/存取粒度:memory page(software coherence) 或 cache line(hardware coherence)。
- 允許 oversubscription:可配置超過 GPU 實體可用量的 managed memory。
上述配置與遷移行為可能偏離,程式設計者可用 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 還提供:
- 駐留在 GPU 的 managed 配置(如
cudaMallocManaged)可從 CPU 不經遷移直接存取(cudaDevAttrDirectManagedMemAccessFromHost= 1)。 - CPU-GPU 連結支援 native atomics(
cudaDevAttrHostNativeAtomicSupported= 1)。 - 硬體 coherence 相較 software coherence 可提升效能。
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。
- 需 Linux Kernel 6.1.24、6.2.11、或 6.3 以上。
- 查詢 addressing mode:
$ nvidia-smi -q | grep Addressing
Addressing Mode : HMM
- HMM 可用時,full unified memory 受支援且所有 system 配置都隱含是 unified memory。
- 若系統同時有 ATS,HMM 停用、改用 ATS。
| 比較 | 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 間遷移行為不同:
- managed memory 先配置在 CPU 實體記憶體。
- 以大於虛擬記憶體 page 的粒度遷移。
- 在 GPU 開始執行時遷移到 GPU。
- GPU 活動期間 CPU 不可存取 managed memory。
- 在 GPU 同步時遷回 CPU。
- 不允許 oversubscription。
- 只有 CUDA 明確配置為 managed 的記憶體才是 unified。
在 limited support 系統上,違反「GPU 活動時 CPU 不可存取 managed memory」會造成問題;這與 full support(CPU/GPU 可並行存取)形成關鍵差異。
Memory Advise 與 Prefetch
程式設計者可給 NVIDIA Driver 提示,協助最大化效能。
| API | 用途 |
|---|---|
cudaMemAdvise |
指定配置的屬性,影響其放置位置以及被其他 device 存取時是否遷移 |
cudaMemPrefetchAsync |
建議非同步地把特定配置搬移到別處 |
cudaMemPrefetchAsync 常見用法:在 kernel 啟動前就開始搬移它將用到的資料,讓資料搬運與其他 GPU kernel 執行重疊,藏住延遲。
Page-Locked Host Memory(pinned memory)
cudaMallocHost 配置的是 host 上的 page-locked memory(又稱 pinned memory)。用 malloc、new、mmap 等傳統機制配置的 host 記憶體不是 page-locked,可能被 OS 換出(swap)到磁碟或實體搬移。
- async copy(CPU↔GPU)必須使用 page-locked memory。
- 也能提升 synchronous copy 的效能。
- 可 map 給 GPU 供 kernel 直接存取。
| API | 功能 |
|---|---|
cudaMallocHost |
配置 page-locked host memory |
cudaHostAlloc |
預設同 cudaMallocHost,但多收 flags 指定其他記憶體參數 |
cudaFreeHost |
釋放 cudaMallocHost / cudaHostAlloc 配置的記憶體 |
cudaHostRegister |
將已存在(如 malloc/mmap)的記憶體區間 page-lock |
cudaHostRegister 讓開發者無法控制的 3rd party library 或外部程式配置的 host 記憶體也能被 page-lock,以用於 async copy 或 mapping。Page-locked host memory 可被系統中所有 GPU 用於 async copy 與 mapped memory。
在 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];
}
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
用 cudaMallocHost 或 cudaHostAlloc 配置的 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 | — |
對 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 的三種方式 | cudaMallocManaged、cudaMallocFromPoolAsync(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 已不再需要 |
Related Notes
- 02-Programming-GPUs/02-CUDA-Cpp-Memory-Management
- 02-Programming-GPUs/03-CUDA-Cpp-Sync-and-Workflow
- 02-Programming-GPUs/07-SIMT-Device-Memory-Spaces
- 02-Programming-GPUs/09-SIMT-Atomics-Cooperative-Occupancy
- 02-Programming-GPUs/14-Async-Streams-and-Events
- 02-Programming-GPUs/15-Async-Callbacks-Ordering-Graphs
- 02-Programming-GPUs/17-NVCC-Compiler
- 01-Introduction-to-CUDA/04-GPU-Memory-Hierarchy
- 01-Introduction-to-CUDA/05-CUDA-Platform
- 02-Programming-GPUs/Practice-Programming-GPUs
- 00-Dashboard/Exam-Traps