GPU 架構、Block 排程與 Synchronization (Transparent Scalability)

重點總覽 (Overview)

主題 核心概念 關鍵限制 / 數字
SM / Core 組織 GPU = 一陣列的 streaming multiprocessors (SMs);每個 SM 有多個 cores (CUDA cores) 共用控制邏輯與 on-chip memory A100:108 SMs × 64 cores = 6912 cores
Block scheduling Thread 以 block-by-block 指派到 SM;同一 block 的所有 thread 同時 落在同一個 SM 每個 SM 可同時容納的 block 數有限 (資源限制,見 04-Compute-Architecture-And-Scheduling/03-Resource-Partitioning-and-Occupancy)
Barrier synchronization __syncthreads() 讓 block 內所有 thread 互等,確保「沒人被留下」 必須由 block 內 每個 thread 執行,否則 deadlock / undefined
Transparent scalability block 之間 不能 同步 → runtime 可任意順序執行 block 同一份 binary 可在低階/高階 GPU 上以不同速度跑,無需改 code
Important

本章只給「程式設計師視角」的簡化架構圖。Warp 切分、SIMD 硬體、occupancy 等細節分別在 04-Compute-Architecture-And-Scheduling/02-Warps-SIMD-and-Control-Divergence04-Compute-Architecture-And-Scheduling/03-Resource-Partitioning-and-Occupancy。On-chip / global memory 細節見 Ch.5–6。


GPU 架構 (Architecture of a Modern GPU)

                       GPU
 ┌─────────────────────────────────────────────┐
 │   SM 0        SM 1        ...     SM (N-1)    │
 │ ┌────────┐ ┌────────┐           ┌────────┐   │
 │ │■■■■ cores│■■■■ cores│  ......  │■■■■ cores│   │  cores 共用:
 │ │■■■■     │■■■■     │           │■■■■     │   │   - Control logic
 │ │ Control │ Control │           │ Control │   │   - On-chip Memory
 │ │ Memory  │ Memory  │           │ Memory  │   │
 │ └────────┘ └────────┘           └────────┘   │
 └─────────────────────┬───────────────────────┘
                       │ (high-bandwidth bus)
 ┌─────────────────────┴───────────────────────┐
 │        Global Memory (off-chip DRAM)         │
 └─────────────────────────────────────────────┘
數量級記憶

Ampere A100 = 108 SMs,每 SM 64 cores → 6912 cores。考題常問「某 GPU 有幾個 core」= SM 數 × 每 SM core 數。


Block 排程 (Block Scheduling)

待執行清單:  B0 B1 B2 B3 B4 B5 B6 B7 B8 ...
                    │  runtime 依資源逐塊指派
                    ▼
   SM0          SM1          SM2
 ┌──────┐     ┌──────┐     ┌──────┐
 │ B0   │     │ B1   │     │ B2   │   ← 第一波同時執行
 │ B3   │     │ B4   │     │ B5   │
 │ B6   │     │ B7   │     │ B8   │   ← 某個 block 完成後,
 └──────┘     └──────┘     └──────┘     清單中下一個 block 才補上
為什麼「block-by-block 同時指派」很重要

這個保證讓同一 block 內的 thread 能彼此互動,而跨 block 的 thread 做不到


Barrier Synchronization (__syncthreads())

time ──────────────────────────────────────►
T0 ====●·····················|   (早到 → 等待)
T1 =========●···············|
T2 ==●·····················|
T3 ===============●·········|
 ⋮                          |   最後一個 thread 到達 barrier 後,
Tn ====================●    |   全部 thread 才一起往下執行
                       ▲ __syncthreads() barrier
        「●」= 到達 barrier   「·」= 等待時間

正確使用規則 (Usage Rules)

// ❌ INCORRECT use of __syncthreads() (Fig. 4.4)
if (threadIdx.x % 2 == 0) {       // line 04: 偶數 thread 走 then
    // ... do work A ...
    __syncthreads();              // line 06: barrier #1
} else {                          // 奇數 thread 走 else
    // ... do work B ...
    __syncthreads();              // line 10: barrier #2 (與 #1 不同!)
}
// block 內 thread 被分到兩個不同 barrier → 沒有任何 barrier
// 被全體到達 → undefined behavior / DEADLOCK
違規後果

錯誤使用 barrier 會導致錯誤結果,或 thread 永遠互等 (deadlock)。程式設計師有責任避免。
邊角情況:跨 warp 的 thread 不保證 lockstep;若需 warp 內 的同步,要用 __syncwarp()(細節見 04-Compute-Architecture-And-Scheduling/02-Warps-SIMD-and-Control-Divergence)。

硬體如何保證 barrier 不死鎖


Transparent Scalability

同一個 grid (8 個 block),跑在兩種裝置上:

  低階裝置 (每波 2 blocks)        高階裝置 (每波 4 blocks)
 time│  B0  B1                  time│  B0  B1  B2  B3
   │   B2  B3                     │   B4  B5  B6  B7
   │   B4  B5                     ▼  (2 波完成)
   ▼   B6  B7
     (4 波完成 → 較慢)              (較快,code 完全相同)
執行波數 (waves)=grid 的 block 數每波可同時執行的 block 數
唯一的例外 (Exception)

「跨 block 不能同步」是一般規則。Cooperative Groups API 可以讓不同 block 的 thread 做 barrier sync,但有嚴格限制(必須確保所有參與 thread 確實同時在 SM 上執行)。一般 kernel 設計仍應假設 block 之間無法同步


考試/面試重點 (Exam / Test Patterns)

情境 / 關鍵字 答案 / 技巧
__syncthreads() 放在 if-then-else、兩 branch 各一個 兩個不同 barrier → 並非全體到達同一 barrier → undefined / deadlock。違規。
「跨不同 block 的 thread 能否同步?」 不能(一般 kernel)。唯一例外是 Cooperative Groups API。
「為何同一份 binary 能在低階與高階 GPU 上跑出不同速度?」 Transparent scalability:無跨 block 同步 → runtime 可任意順序/分波執行 block。
「block-by-block 指派保證了什麼?」 同一 block 的所有 thread 同時在同一 SM → 才能用 barrier syncshared memory
「一個 block 何時開始執行?」 runtime 確保該 block 所有 thread 的全部資源都到位後才啟動(防止 barrier deadlock)。
Ex.5:block 只有 32 thread,可省略 __syncthreads() 嗎? 不安全。warp 內 thread 因 control divergence / Volta 起的 independent thread scheduling 不保證 lockstep;需要時用 __syncwarp()
「A100 有幾個 core?」 108 SMs × 64 cores/SM = 6912
barrier 比喻 「沒人被留下 (no one is left behind)」;早到的等晚到的,最後一個到達後全體續行。