進階啟動與 Clusters (Advanced Launch and Clusters)
重點總覽
| 項目 | 重點 |
|---|---|
| 進階 API 定位 | 多為 host 端技巧,通常不需修改 kernel 程式碼,但能影響 GPU 工作執行與 CPU/GPU 兩側效能 |
triple chevron <<<>>> 的四個參數 |
block 維度、grid 維度、dynamic shared memory(預設 0)、stream(預設 default stream) |
cudaLaunchKernelEx |
以 cudaLaunchConfig_t 設定執行配置,並可額外傳入零或多個 cudaLaunchAttribute 來控制/提示其他啟動參數 |
cudaLaunchAttribute 用途範例 |
cudaLaunchAttributePreferredSharedMemoryCarveout(L1/shared 平衡)、cudaLaunchAttributeClusterDimension(cluster 大小) |
| Thread block clusters | compute capability 9.0+ 的可選 thread block 組織層級,保證同 cluster 的 blocks 同時在單一 GPC 執行 |
cudaLaunchAttributeClusterDimension |
指定「必需」cluster 維度,grid 各維度必須可被 cluster 維度整除;可在 runtime 逐次啟動改變 |
cudaLaunchAttributePreferredClusterDimension |
compute capability 10.0+,額外指定「偏好」cluster 維度;須為最小維度的整數倍 |
__cluster_dims__ |
編譯期固定 cluster 維度,grid 仍以 thread block 數計;cluster 數量由 grid/cluster 隱式算出 |
__block_size__ |
編譯期同時指定 block size 與 cluster size;啟用後 <<<>>> 第一參數變成「cluster 數」而非 block 數 |
進階 CUDA API 與功能的定位
本章涵蓋較進階的 CUDA API 與功能。這些技巧多半不需要修改 kernel 程式碼,而是從 host 端影響應用層行為,包含 GPU 工作的執行方式、效能,以及 CPU 端的效能。
- 通常以 host 端 API 呼叫或啟動屬性來達成。
- 既影響 GPU work execution,也影響 CPU/GPU 兩側效能表現。
3.1.1 cudaLaunchKernelEx
最初版本引入 triple chevron <<<>>> 記法時,kernel 的執行配置只有四個可程式化參數:
- thread block 維度
- grid 維度
- dynamic shared memory(選填,未指定為 0)
- stream(未指定則用 default stream)
部分 CUDA 功能可受惠於啟動時提供的額外屬性與提示。cudaLaunchKernelEx 讓程式能以 cudaLaunchConfig_t 結構設定上述執行配置參數,並可再傳入零或多個 cudaLaunchAttribute 來控制或建議其他啟動參數。
cudaLaunchConfig_t config = {0};
config.gridDim = numBlocks; // 等同 <<<>>> 第一參數
config.blockDim = threadsPerBlock; // 等同 <<<>>> 第二參數
config.attrs = attribute; // cudaLaunchAttribute 陣列
config.numAttrs = 1; // 屬性數量
cudaLaunchKernelEx(&config, kernel, args...);
cudaLaunchConfig_t 內含 gridDim、blockDim、dynamicSmemBytes、stream,再加上 attrs(屬性陣列指標)與 numAttrs(陣列長度)。
- 屬性陣列每個元素是
cudaLaunchAttribute,以id標示屬性種類,val為對應的值(union)。 - 範例屬性:
cudaLaunchAttributePreferredSharedMemoryCarveout(L1/Shared Memory 平衡,見 03-Advanced-CUDA/07-Async-Data-Copies-and-L1-Config)、cudaLaunchAttributeClusterDimension(指定 cluster 大小)。 - 完整支援屬性清單見 CUDA Runtime API Reference Documentation。
cudaLaunchKernelEx 相對 <<<>>> 的價值在於彈性:<<<>>> 只能表達四個固定參數,而 cudaLaunchKernelEx 可在不改動 kernel 原始碼的前提下,於每次啟動附加任意數量的屬性/提示(如 cluster 維度、shared memory carveout)。
triple chevron <<< grid, block, [smem], [stream] >>>
└─ 只有 4 個固定參數
cudaLaunchKernelEx(&config, kernel, args)
config: gridDim / blockDim / dynamicSmemBytes / stream
+ attrs[0..numAttrs-1] ← 可擴充的屬性陣列
├ cudaLaunchAttributeClusterDimension
├ cudaLaunchAttributePreferredSharedMemoryCarveout
└ ...(更多屬性)
3.1.2 Launching Clusters
Thread block clusters 是 compute capability 9.0 以上才有的可選 thread block 組織層級。它保證一個 cluster 內的所有 thread blocks 同時在單一 GPC(GPU Processing Cluster)上執行,使得超過單一 SM 容量的更大一群 threads 能彼此交換資料與同步。
Grid
└── Cluster (同時駐留在單一 GPC)
├── Thread Block 0 ┐
├── Thread Block 1 ├─ 可跨 block 交換資料 / 同步
└── Thread Block ... ┘
└── Threads
- cluster 讓多個 SM 上的 blocks能協作,突破單一 SM/單一 block 的規模限制。
- 用
<<<>>>啟動 cluster 時,cluster 大小是隱式決定的(由__cluster_dims__指定,見 §3.1.2.2)。 - 與
cudaLaunchKernelEx搭配時,則可**逐次啟動(per-launch)**地配置 cluster 大小。
grid 維度不受 cluster 啟動影響,仍以 thread block 數量枚舉;但 grid 各維度必須是 cluster 各維度的整數倍(即可被整除)。
3.1.2.1 用 cudaLaunchKernelEx 啟動 Clusters
與 <<<>>> 不同,使用 cudaLaunchKernelEx 時 cluster 大小可逐次啟動配置。透過 cudaLaunchAttributeClusterDimension 屬性指定 cluster 維度。
// Kernel 定義:無編譯期屬性附加在 kernel 上
__global__ void cluster_kernel(float *input, float* output) {}
int main() {
float *input, *output;
dim3 threadsPerBlock(16, 16);
dim3 numBlocks(N / threadsPerBlock.x, N / threadsPerBlock.y);
cudaLaunchConfig_t config = {0};
// grid 維度不受 cluster 影響,仍以 block 數枚舉;且須為 cluster size 的倍數
config.gridDim = numBlocks;
config.blockDim = threadsPerBlock;
cudaLaunchAttribute attribute[1];
attribute[0].id = cudaLaunchAttributeClusterDimension;
attribute[0].val.clusterDim.x = 2; // X 維度的 cluster 大小
attribute[0].val.clusterDim.y = 1;
attribute[0].val.clusterDim.z = 1;
config.attrs = attribute;
config.numAttrs = 1;
cudaLaunchKernelEx(&config, cluster_kernel, input, output);
}
此處 kernel 無任何編譯期 cluster 屬性,cluster 維度完全由 runtime 的 attribute 決定。
與 thread block clusters 相關的兩種 attribute:
| 屬性 id | 適用硬體 | 語意 | 約束 |
|---|---|---|---|
cudaLaunchAttributeClusterDimension |
CC 9.0+ | 指定**必需(required)**的 cluster 執行維度(clusterDim,3 維值) |
grid 的 x/y/z 必須可被對應 cluster 維度整除;等效於編譯期 __cluster_dims__,但可 runtime 改變 |
cudaLaunchAttributePreferredClusterDimension |
CC 10.0+ | 額外指定**偏好(preferred)**的 cluster 維度 | 必須是「最小 cluster 維度」的整數倍;grid 各維度須可被偏好維度整除 |
cudaLaunchAttributeClusterDimension的效果類似在 kernel 定義上加__cluster_dims__,差別在於可在 runtime 對同一 kernel 的不同啟動改變。- 使用 preferred 維度時,必須同時指定最小 cluster 維度(由
__cluster_dims__或cudaLaunchAttributeClusterDimension提供)。 - 所有 thread blocks 都會以「至少最小 cluster 維度」執行;在可能時採用 preferred 維度,但不保證所有 cluster 都以 preferred 維度執行。
使用 preferred cluster dimension 的 kernel 必須同時能在「最小」或「偏好」兩種 cluster 維度下都正確運作,因為部分 cluster 可能以最小維度執行、部分以偏好維度執行,實際維度不保證一致。
3.1.2.2 Blocks as Clusters
當 kernel 以 __cluster_dims__ 標註時,grid 中的 cluster 數量是隱式的,由 grid 大小除以指定 cluster 大小算出。
__cluster_dims__((2, 2, 2)) __global__ void foo();
// 每個 cluster 含 2x2x2 個 thread blocks → 8x8x8 個 clusters
foo<<<dim3(16, 16, 16), dim3(1024, 1, 1)>>>();
此例 grid 為 16x16x16 個 thread blocks,因每 cluster 是 2x2x2 blocks,故得 8x8x8 個 clusters。<<<>>> 第一參數仍是 block 數。
另一種方式是用 __block_size__ 標註,在 kernel 定義時同時指定 block size 與 cluster size。啟用後,<<<>>> 的 grid 維度改以 cluster 為單位而非 thread block。
// 每 block 多少 threads、每 cluster 多少 blocks,皆作為 kernel 的屬性處理
__block_size__((1024, 1, 1), (2, 2, 2)) __global__ void foo();
// 8x8x8 clusters
foo<<<dim3(8, 8, 8)>>>();
__block_size__ 需兩個欄位,各為 3 元素 tuple:第一個是 block 維度,第二個是 cluster 大小;第二個 tuple 若未傳入則預設為 (1,1,1)。
| 比較 | __cluster_dims__ |
__block_size__(含第二 tuple) |
|---|---|---|
| 指定內容 | 僅 cluster 維度 | block 維度 + cluster 維度 |
<<<>>> 第一參數語意 |
thread block 數 | cluster 數("Blocks as Clusters") |
| cluster 數量 | 由 grid/cluster 隱式算出 | 即 <<<>>> 第一參數 |
多項非法組合需注意:
__block_size__的第二 tuple 與__cluster_dims__不可同時指定。- 不可將
__block_size__與空的__cluster_dims__併用。 - 啟用 "Blocks as Clusters"(即
__block_size__帶第二 tuple)後,若要在啟動時指定 dynamic shared memory 與/或 stream,<<<>>>的第二個參數必須是佔位符1;填入其他值會導致 undefined behavior。
__block_size__((1024,1,1),(2,2,2)) → 啟用 Blocks as Clusters
foo<<< dim3(8,8,8) >>>(); // 第一參數 = cluster 數
foo<<< dim3(8,8,8), 1, stream >>>(); // 帶 smem/stream 時,第二參數必須是 1
▲
└─ 佔位符;其他值 = UB
考試/測驗重點
| 情境/關鍵字 | 答案 |
|---|---|
| triple chevron 可程式化的四個參數 | block 維度 / grid 維度 / dynamic shared memory / stream |
| 想在不改 kernel 原始碼下附加額外啟動屬性 | 用 cudaLaunchKernelEx + cudaLaunchConfig_t + cudaLaunchAttribute 陣列 |
cudaLaunchConfig_t 中存放屬性陣列的欄位 |
attrs(指標)與 numAttrs(數量) |
| 設定 L1/Shared Memory 平衡用哪個屬性 | cudaLaunchAttributePreferredSharedMemoryCarveout |
| Thread block clusters 起始 compute capability | 9.0 |
| cluster 提供什麼保證 | 同 cluster 的 blocks 同時在單一 GPC 執行,可跨 block 交換資料/同步 |
| 指定「必需」cluster 維度的屬性 | cudaLaunchAttributeClusterDimension |
| 指定「偏好」cluster 維度的屬性 / 起始 CC | cudaLaunchAttributePreferredClusterDimension / 10.0 |
| grid 維度與 cluster 維度的關係 | grid 各維度必須可被 cluster 各維度整除 |
| 用 preferred 維度時是否仍需最小維度 | 是,必須額外指定最小 cluster 維度 |
| preferred 維度是否保證所有 cluster 都採用 | 否;kernel 須能在最小或偏好維度下都正確運作 |
__cluster_dims__ 下 <<<>>> 第一參數語意 |
thread block 數(cluster 數隱式算出) |
__block_size__ 下 <<<>>> 第一參數語意 |
cluster 數(Blocks as Clusters) |
__block_size__ 兩個 tuple 的意義 / 第二個預設 |
(block 維度, cluster 維度);第二個未給預設 (1,1,1) |
__block_size__ 帶 smem/stream 時第二個 <<<>>> 參數 |
必須是佔位符 1,否則 undefined behavior |
__block_size__ 第二 tuple 與 __cluster_dims__ 同時指定 |
非法;且不可與空 __cluster_dims__ 併用 |
cudaLaunchAttributeClusterDimension vs __cluster_dims__ |
效果相似,但前者可在 runtime 逐次啟動改變維度 |
Related Notes
- 03-Advanced-CUDA/02-Advanced-Streams-and-Dependent-Launch
- 03-Advanced-CUDA/04-Using-PTX-and-Hardware-Model
- 03-Advanced-CUDA/05-Thread-Scopes-and-Scoped-Atomics
- 03-Advanced-CUDA/06-Asynchronous-Barriers-and-Pipelines
- 03-Advanced-CUDA/07-Async-Data-Copies-and-L1-Config
- 03-Advanced-CUDA/08-CUDA-Driver-API
- 02-Programming-GPUs/01-CUDA-Cpp-Kernels-and-Launch
- 02-Programming-GPUs/04-CUDA-Cpp-Errors-and-Specifiers
- 03-Advanced-CUDA/Practice-Advanced-CUDA
- 00-Dashboard/Exam-Traps