進階啟動與 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 端的效能。

3.1.1 cudaLaunchKernelEx

最初版本引入 triple chevron <<<>>> 記法時,kernel 的執行配置只有四個可程式化參數:

部分 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 內含 gridDimblockDimdynamicSmemBytesstream,再加上 attrs(屬性陣列指標)與 numAttrs(陣列長度)。

Tip

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
Important

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 各維度須可被偏好維度整除
Warning

使用 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 隱式算出 <<<>>> 第一參數
Warning

多項非法組合需注意:

  • __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 逐次啟動改變維度