第五章練習題 (Practice - Technical Appendices)
Related Concepts
- 05-Technical-Appendices/01-Compute-Capabilities
- 05-Technical-Appendices/02-CUDA-Environment-Variables
- 05-Technical-Appendices/03-Cpp-Language-Features
- 05-Technical-Appendices/04-Cpp-Standard-Library-and-Lambdas
- 05-Technical-Appendices/05-Cpp-Language-Restrictions
- 05-Technical-Appendices/06-Function-and-Variable-Annotations
- 05-Technical-Appendices/07-Synchronization-and-Atomic-Functions
- 05-Technical-Appendices/08-Warp-Functions-and-Macros
- 05-Technical-Appendices/09-Compiler-Hints-and-Warp-Matrix
- 05-Technical-Appendices/10-Floating-Point-Fundamentals
- 05-Technical-Appendices/11-Math-Functions-and-Intrinsics
- 05-Technical-Appendices/12-Memory-Barrier-Pipeline-Cooperative-APIs
- 05-Technical-Appendices/13-CUDA-Device-Runtime
- 05-Technical-Appendices/14-CUDA-Cpp-Memory-Model
- 05-Technical-Appendices/15-CUDA-Cpp-Execution-Model
作答前可先用這張表喚起記憶;每列是「情境/關鍵字 → 答案」。
| 情境 / 關鍵字 | 答案 |
|---|---|
| architecture-specific (a) vs family-specific (f) | a 從 CC 9.0、後綴 a、僅 exact CC;f 從 CC 10.0、後綴 f、同 family;含括 a ⊇ f ⊇ baseline |
| 跨所有 CC 不變的硬上限 | warp size=32、max threads/block=1024、max 32-bit reg/thread=255、grid x-dim=2³¹−1、block z-dim=64 |
CUDA_VISIBLE_DEVICES 遇無效 index |
截斷:只有排在無效 index「之前」的 device 可見;ordinal 由列舉順序決定,count 只算可見 |
*_PTX_JIT vs *_JIT 覆蓋 / module loading 預設 |
CUDA_FORCE/DISABLE_PTX_JIT 永遠覆蓋對應 _JIT;CUDA_MODULE_LOADING 預設 LAZY |
| C++11 device 不支援整組 / C++20 兩大缺席 | Concurrency 群組(std::atomic/memory model/thread_local/例外傳播);Modules + Coroutines |
device printf 回傳 / 上限 / buffer |
回傳「解析的引數數」;上限 32 引數;1 MB 環狀緩衝,程式結束「不」自動 flush |
device malloc heap 預設 / 對齊 / 互通 |
預設 8 MB(須配置前設);16-byte 對齊;不可與 cudaFree/cudaMemcpy 互通 |
__global__ 參數總大小 / host→device 傳遞 |
≤ 32,764 bytes,經 constant memory;raw memcpy「跳過 copy constructor」、destructor 可能早於 kernel 完成 |
| 哪些 function 不支援 recursion | __global__/__tile_global__/__tile__ 不支援;__device__/__host__ __device__ 可 |
__launch_bounds__ 第一參數 PTX / 與 __maxnreg__ |
maxThreadsPerBlock → .maxntid;__launch_bounds__ 與 __maxnreg__ 不可並用 |
| fence 三 scope / 是否保證可見性 | block / device / system;fence「只排序,不保證可見性」(可見性靠 volatile 或 atomic) |
atomic 五種 / 推薦 / __nv_atomic 五級 scope |
Extended/Standard/Built-in/Tile/Legacy;推薦 Extended;scope = THREAD/BLOCK/CLUSTER/DEVICE/SYSTEM |
| 為何 Volta+ 的 warp intrinsic 必帶 mask | thread 可獨立排程,mask 明示參與 lane 並在硬體執行前「強制收斂」;warp *_sync 不提供 memory ordering |
WMMA 最低 CC / mptr 對齊 / __CUDA_ARCH__ 值 |
CC 7.0;mptr 256-bit 對齊;__CUDA_ARCH__ = compute_<ver> × 10(compute_80 → 800) |
| IEEE-754 三限制 / 可移植預設旗標 | 無動態 rounding、無例外偵測、SNaN 不 signaling;-ftz=false -prec-div=true -prec-sqrt=true,不開 fast_math |
fdividef vs __fdividef / 取整 |
fdividef 0 ULP(同 x/y);intrinsic __fdividef 2 ULP;取整用 rint(單指令)勿用 round(多指令) |
| global vs shared 上 atomic float add 的 denormal | global 永遠 flush-to-zero;shared 永遠支援 denormal(不論 -ftz) |
| device runtime stream / 同步替代 / 多 GPU | 只 cudaStreamCreateWithFlags(NonBlocking);無 Synchronize,用 cudaStreamTailLaunch;不支援多 GPU |
| thread scope 四級(記憶體模型)/ data race | system ⊃ device ⊃ block ⊃ thread;非 atomic + 無 happens-before → UB |
| device thread forward progress / 反覆 query | parallel FP;spin-loop「之外」單次 query 不夠,須「迴圈內反覆」cudaStreamQuery 才保證推進 |
Question 1 - Compute Capability 的特性分層與不變上限 [recall]
CC 的三層特性集(baseline / architecture-specific / family-specific)各自的相容承諾與含括關係為何?
compute_100、compute_100f、compute_100a三個 target 各能在哪些 device 上執行?哪些技術上限跨所有 CC 不變?
baseline(compute_NN,引入後所有後續 CC 皆可用)⊇ 反過來被含括:architecture-specific(後綴 a,CC 9.0 起,僅 exact CC)⊇ family-specific(後綴 f,CC 10.0 起,同 family)⊇ baseline;即 a ⊇ f ⊇ baseline。
compute_100:所有 CC 10.0 及之後;compute_100f:同 family(10.0 與 10.3);compute_100a:僅 CC 10.0。
不變上限:warp size=32、max threads/block=1024、max 32-bit registers/thread=255、grid x-dim=2³¹−1、y/z-dim=65535、block z-dim=64。NVIDIA GPU 一律 little-endian。
Question 2 - CUDA_VISIBLE_DEVICES 的截斷與 ordinal [application]
在一台四 GPU 機器上設
CUDA_VISIBLE_DEVICES=2,1,-1,3,程式裡cudaGetDeviceCount()回傳多少?cudaSetDevice(0)會選到哪顆實體 GPU?若改設為空字串又如何?
遇到無效 index(-1)會截斷清單,只有排在它「之前」的 device 可見,故只有實體 2 與 1 可見,cudaGetDeviceCount() 回傳 2(device 3 在 -1 之後不可見)。
列舉順序決定 ordinal:ordinal 0 = 列舉最前的實體 device 2,所以 cudaSetDevice(0) 選到實體 GPU 2。
設為空字串時「沒有任何 GPU 可見」(未設定才是全部可見)。
Question 3 - JIT 快取、Module Loading 與 Override 規則 [recall]
CUDA_LAUNCH_BLOCKING=1的用途與代價是什麼?CUDA_MODULE_LOADING的預設值與 LAZY/EAGER 差異?CUDA_FORCE_PTX_JIT與CUDA_FORCE_JIT、CUDA_DISABLE_PTX_JIT與CUDA_DISABLE_JIT的覆蓋關係為何?
CUDA_LAUNCH_BLOCKING=1 關閉非同步執行,讓 CUDA API 錯誤「對齊到觸發它的那個呼叫」便於除錯;代價是程式變慢,是除錯工具非效能設定。
CUDA_MODULE_LOADING 預設 LAZY:延後到取得 function handle 才載入,降低 startup 時間與 GPU 記憶體佔用;EAGER 在初始化即全載,launch 開銷可預測但 startup/記憶體較高。
*_PTX_JIT 版永遠覆蓋對應的 *_JIT 版:CUDA_FORCE_PTX_JIT > CUDA_FORCE_JIT、CUDA_DISABLE_PTX_JIT > CUDA_DISABLE_JIT。
Question 4 - C++ 標準在 Device Code 的支援與限制 [recall]
nvcc 用哪個旗標選 C++ 標準、傳入後做什麼?C++11 在 device code 不支援哪「一整組」特性?C++20 又缺席哪兩大功能?libcu++ 是什麼、解決什麼問題?
用 --std=c++03/11/14/17/20/23;傳入會開啟該版「全部語言特性」,並以對應 dialect 一併驅動 host 的 preprocessor/compiler/linker。
C++11 device code 不支援整個「Concurrency 群組」:std::atomic、memory model、bidirectional fences、thread_local、propagating exceptions(另有 GC 最小支援、extended integral types)。C++20 缺席 Modules 與 Coroutines(Concepts/<=>/consteval/constinit/char8_t 皆可用)。
libcu++ 是 CUDA 版 C++ 標準庫(cuda::std::),host/device 皆可用,提供 device 上 std::atomic/memory model 等的替代品與 extended types(__int128/__half/__nv_bfloat16/__float128)。
Question 5 - device printf 與 device malloc heap [recall]
device
printf()的回傳值與標準 C 有何不同、引數上限多少?它的 host-side buffer 預設多大、什麼性質、程式結束會不會自動 flush?device 端malloc()從哪配置、預設 heap 多大、配置出的記憶體能否用cudaFree釋放?
device printf() 回傳「解析的引數數」(非字元數):無引數→0、format 為 NULL→-1、內部錯誤→-2;引數上限 32 個(不含 format string),多出的被忽略。
Buffer 預設 1 MB、固定大小的「環狀」緩衝(cudaLimitPrintfFifoSize 可調),滿了覆蓋舊輸出;只在 kernel launch/同步/blocking memcpy/module load-unload/context 銷毀/host callback 前 flush,「程式結束不會」自動 flush。
device malloc() 從 device heap 配置、回傳 16-byte 對齊;heap 預設 8 MB(須在任何配置前用 cudaLimitMallocHeapSize 設)。device heap 與 host runtime API 記憶體互不相通,「不可」用 cudaFree/cudaMemcpy 操作。
Question 6 - Lambda 執行空間、Extended Lambda 與 nvstd::function [recall]
lambda 的執行空間如何決定?哪種 lambda 才能當
__global__引數?什麼是 extended lambda、它的捕捉有哪些限制、*this捕捉解決什麼問題?nvstd::function能否跨 host/device 邊界傳遞?
由「最內層 enclosing function scope 的執行空間」決定;無 scope 則為 __host__。只有執行空間為 __device__ 或 __host__ __device__ 的 lambda 能當 __global__ 引數,global/namespace scope lambda 不可。
Extended lambda = 定義在 __host__/__host__ __device__ 函式內、帶執行空間標註的 lambda(需 --extended-lambda);只能 by value 捕捉、陣列維度 ≤ 7、host-device 不可 init-capture、存在/順序不可依賴 __CUDA_ARCH__。C++17 *this 捕捉複製「物件本身」而非 this 指標,避免 GPU 上存取 host this->member 的 runtime error。
nvstd::function(<nvfunctional>)host/device 皆可用,但「不可」跨 host/device 邊界傳遞或初始化;其 operator() 僅 __device__。
Question 7 - 通用語言限制與 host→device 傳參的兩個陷阱 [analysis]
device code 不支援哪些 ISO C++ 功能(至少四項)?
__global__參數總大小上限、經哪段記憶體傳遞?當從 host 啟動 kernel、參數是帶 user-defined copy constructor 與 non-trivial destructor 的 class 時,CUDA Runtime 的處理會「偏離標準 C++」造成哪兩個陷阱?
不支援:RTTI(typeid/dynamic_cast)、例外(try/catch/throw)、long double、trigraphs,以及 __global__/__tile_global__/__tile__ 的 recursion。__global__ 參數經 constant memory 傳遞,總大小上限 32,764 bytes,且不可 variadic、不可 std::initializer_list。
陷阱一:CUDA Runtime 用 raw memcpy 複製參數到 device,「跳過 user-defined copy constructor」,其副作用不會發生(如指向自身成員的指標在 device 端失效)。
陷阱二:kernel 啟動與 host 非同步,若參數有 non-trivial destructor,它可能在「kernel 完成前」就於 host 端執行,破壞有副作用的邏輯。
Question 8 - __launch_bounds__ / __maxnreg__ / __grid_constant__ [application]
你的 kernel 啟動時報「too many resources requested for launch」,
__launch_bounds__如何幫忙、它的第一個參數對應哪個 PTX directive?__launch_bounds__與__maxnreg__能否同時用?想讓 grid 內所有 thread 共用一份唯讀參數位址、省去 per-thread copy,該用什麼?
__launch_bounds__(maxThreadsPerBlock[, minBlocksPerMultiprocessor]) 告訴編譯器啟動上限,據此推導暫存器上限 L 並壓低暫存器用量,確保指定數量的 block 能常駐 SM;建議至少加單引數版以避免該錯誤。第一個參數 maxThreadsPerBlock 編成 PTX .maxntid。
__launch_bounds__ 與 __maxnreg__(編成 .maxnreg)「不可」同時套在同一 kernel。
用 __grid_constant__:const-qualified 非 reference 的 __global__ 參數,全 thread 共用單一位址、唯讀、具 kernel 生命週期(修改它為 UB)。
Question 9 - 同步原語與 Memory Fence 的三層 Scope [recall]
__syncthreads()等待的對象是什麼、放在條件式中需要什麼前提?三層 memory fence(__threadfence_block/__threadfence/__threadfence_system)各對哪些觀察者生效?fence 能不能保證寫入「可見」?
__syncthreads() 等到 block 內「所有未退出 thread」都到達同一呼叫點或已退出,並建立 strongly happens-before 的記憶體排序;放在條件式中只有當條件「對整個 block uniform」時才合法,否則可能 hang 或 UB。
__threadfence_block:呼叫 thread 所在 block 內所有 thread;__threadfence:本 device 內任一 thread;__threadfence_system:device 內所有 thread + host thread + 所有 peer device 的 thread。
fence「只排序,不保證可見性與原子性」;可見性需另用 volatile(繞過 L1)或 atomic 達成。
Question 10 - Atomic 五種提供方式、五級 Scope 與 atomicCAS [analysis]
CUDA 提供哪五種 atomic、哪種推薦?Legacy atomic 的記憶體序與 scope 後綴慣例為何?Built-in
__nv_atomic_*的 thread scope 有哪五級、對order/scope引數有何硬性要求?用atomicCAS自製浮點atomicAdd時,為何「必須用整數位元樣式比較」?
五種:Extended(cuda::atomic/atomic_ref,推薦)、Standard(cuda::std::atomic)、Built-in(__nv_atomic_*,CUDA 12.8+)、Tile、Legacy(atomic<Op>)。Legacy 僅 memory_order_relaxed、不引入 fence,scope 後綴:無=device、_block=block、_system=system。
Built-in 五級 scope:__NV_THREAD_SCOPE_THREAD/BLOCK/CLUSTER/DEVICE/SYSTEM(CLUSTER 需 sm_90+);order 與 scope 必須是「整數字面量、不能是變數」,且僅 device、不可作用於 local memory、不可取位址。
浮點 CAS 迴圈須以 bit_cast 後的 unsigned 比較,因為 NaN != NaN:若直接用浮點比較,遇 NaN 永遠不相等會導致迴圈無法收斂而 hang。
Question 11 - Warp 函式為何 Volta+ 必帶 mask 與 __CUDA_ARCH__ [recall]
所有 warp
*_syncintrinsic(__shfl_sync/__ballot_sync/__reduce_*_sync等)為何在 Volta 之後必須帶 mask?mask 的「呼叫/非呼叫 thread」bit 規則是什麼、不同 mask 何時可並發?warp*_sync提供 memory ordering 嗎?__CUDA_ARCH__在哪裡有定義、-arch=compute_80,code=sm_90時其值為何?
Volta 起 thread 可獨立排程、不再保證 lock-step;mask 明確列出「應參與的 lane 集合」並在硬體執行前「強制收斂」,這是舊式無 mask 的 __shfl/__any/__ballot 被 *_sync 取代的原因(全員 0xFFFFFFFF 效率最佳)。
規則:每個呼叫 thread 的 bit 必須=1、非呼叫 thread 的 bit=0(已退出 thread 被忽略),參與者須以「相同 mask」執行;不同 thread 可用「彼此 disjoint」的 mask 並發呼叫,即使 divergent 也合法。warp *_sync 「不」提供任何 memory ordering / barrier。
__CUDA_ARCH__ 只在 device code 有定義,值 = compute_<version> × 10,取「虛擬架構」compute_80 → 800(非 sm_90)。
Question 12 - 編譯器提示與 Warp Matrix (WMMA) [recall]
#pragma unroll無引數、1、-1三種情況各做什麼?__builtin_assume(pred)在執行期為 false 時的後果?WMMA 需要的最低 compute capability、mptr的對齊要求、mma_sync在satf=true時對 NaN 的處理各為何?為何不可直接互傳 fragment?
#pragma unroll 無引數:trip count 為常數時「完全展開」;1(或 0):停用展開;-1(非正或 > INT_MAX):忽略 pragma 並發警告。必須緊接在迴圈正前方。
__builtin_assume(pred) 執行期為 false 是 undefined behavior(引數有副作用則 unspecified)。
WMMA 需 CC 7.0+(bfloat16/tf32/double 需 8.0)、全 warp 協作;mptr 須 256-bit 對齊;satf=true 時 ±Inf → ±MAX_NORM、NaN → +0。
fragment 是「不透明、架構特定的 ABI 結構」,不同 link-compatible 架構(如 sm_70/sm_75)layout 不同,互傳會致錯誤/損毀;應先 store_matrix_sync 存到記憶體再以指標傳遞。
Question 13 - IEEE-754 符合度、FMA 與 Denormal [recall]
CUDA 遵循哪版 IEEE-754、有哪三項主要限制?FMA(
a*b+c)為什麼比分開的乘加更精確?denormal 是什麼、用哪個旗標關閉、它被包在哪個總開關裡?global 與 shared memory 上的 atomic single-precision add 對 denormal 的處理有何差別?
遵循 IEEE 754-2019,限制:無動態可設 rounding mode(只能用特定命名的 device intrinsic 選常數模式)、無浮點例外偵測機制、SNaN 不 signaling(當 quiet 處理)。
FMA 計算 a*b+c 只「round 一次」(非乘一次、加一次共兩次),且乘法階段保留 double-width 乘積,可防 subtractive cancellation,因此更精確。
denormal(subnormal)是 exponent 全 0、用以漸進填補最小 normal 與 0 之間空隙的值,運算較慢;-ftz=true(flush-to-zero)可沖成 0,包含於 --use_fast_math。
不論 -ftz:global 上 atomic float add「永遠 flush-to-zero」(同 add.rn.ftz.f32),shared 上「永遠支援 denormal」(同 add.rn.f32)。
Question 14 - 標準數學函式 vs Intrinsic 的精度取捨 [application]
你的 kernel 想加速三角/除法運算,正在標準庫函式(
cuda::std::/Math API)與 intrinsic(__sinf/__fdividef)之間取捨。intrinsic 有哪三個共同特性、受哪些浮點旗標影響?fdividef與__fdividef名字只差兩個底線,精度有何不同?把浮點取整成整數該用rint還是round、為什麼?--use_fast_math做什麼?
intrinsic 三特性:加 __ 前綴、「只在 device code」可用、映射較少原生指令(更快但較不精確);其行為「不受」-prec-div/-prec-sqrt/-fmad 影響,唯一例外是 -ftz=true。
非標準函式 fdividef(x,y) 是 0 ULP、等同 x/y;intrinsic __fdividef(x,y) 對 |y| ∈ [2⁻¹²⁶, 2¹²⁶] 是 2 ULP——兩者精度不同。
取整用 rint/rintf(device 上映射成「單一指令」),勿用 round/roundf(映射成「多條指令」);trunc/ceil/floor 也都是單指令。
--use_fast_math 把一組 device Math API 函式(含 cuda::std::)自動換成對應 intrinsic(如 sinf→__sinf、x/y→__fdividef),更快但降低精度。
Question 15 - Pipeline、mbarrier 與 Cooperative Groups [recall]
__pipeline_memcpy_async的size_and_align只能是哪些值、追蹤哪個方向的複製?tiled_partition<Size>對Size的限制?cg::reduce何時走硬體加速?grid.sync()為何不能用<<<>>>啟動、需要哪個 API 與哪個 CC?
__pipeline_memcpy_async 只追蹤「global → shared」的非同步複製,size_and_align 只能是 4、8 或 16(且等於兩端指標的對齊);zfill 部分補零。
tiled_partition<Size> 的 Size 須為 2 的次方且 ≤ 1024,父群大小須整除 Size;shfl_up/shfl_down/shfl_xor/ballot 僅 ≤ 32。
cg::reduce 在 CC 8.0+ 且運算為 add/min/max 或 AND/OR/XOR、且「只有 4-byte 型別」時走硬體加速,否則退回 shuffle-based。
grid.sync()(跨 grid 同步)須用 cudaLaunchCooperativeKernel(非 <<<>>>)以保證 block co-residency,僅 CC 6.0+ 支援(先查 cudaDevAttrCooperativeLaunch)。
Question 16 - Device Runtime 的 API 子集與 Stream 替代 [application]
你在 kernel 內(Dynamic Parallelism)要建 stream、做同步、配置記憶體。device runtime 建 stream 必須傳什麼 flag、用哪個 API?為何沒有
cudaStreamSynchronize、想確認子 kernel 完成該怎麼辦?cudaStreamFireAndForget與cudaStreamTailLaunch的根本差異?device runtime 支援多 GPU 嗎?
建 stream 必須用 cudaStreamCreateWithFlags(cudaStreamNonBlocking)(cudaStreamCreate() 不可用);event 須傳 cudaEventDisableTiming。stream handle 不可傳給 parent/child,視為建立它的 grid 私有。
device runtime「無同步函式」(cudaStreamSynchronize/Query/cudaDeviceSynchronize 皆不在子集);要確認 stream 子 kernel 完成,改把一個 kernel 送進 cudaStreamTailLaunch。
cudaStreamFireAndForget:立即排程、不相依於先前 grid,且無 grid 能相依其完成;cudaStreamTailLaunch:排程「在自己完成之後」才啟動,達成類似 cudaDeviceSynchronize 的效果(兩者皆需 64-bit 編譯、不可定義 CUDA_FORCE_CDP1_IF_SUPPORTED)。
不支援多 GPU,只能操作當前執行的 device(但可查詢任意 device 屬性)。
Question 17 - CUDA C++ 記憶體模型:Thread Scope 與 Data Race [recall]
CUDA C++ 為何要在標準記憶體模型上加 thread scope?四個 scope 由大到小是哪些、
thread_scope_device的精確範圍?一個 atomic 操作「何時才真的是 atomic」?加上 scope 後的 data race 定義與後果為何?
因為 CUDA 的同步成本「非均勻」:執行緒距離越遠成本越高(block 內極低、跨多 GPU/CPU 很高),故在 cuda:: namespace 用 thread scope 表達這種成本,預設仍保留標準 C++ 語法語意。
由大到小:thread_scope_system ⊃ _device ⊃ _block ⊃ _thread;thread_scope_device 涵蓋「同一 device 且同一 memory synchronization domain」內的 GPU 執行緒。std::/cuda::std:: 等同以 thread_scope_system 實例化。
atomic 操作只在它「指定的 scope」內保證 atomic:scope 不是 system 時自動成立(system scope 需額外裝置屬性如 pageableMemoryAccess/concurrentManagedAccess/hostNativeAtomicSupported)。
Data race:兩個可能並行的衝突動作,至少一個「在涵蓋對方執行緒的 scope 下不是 atomic」且彼此無 happens-before → 未定義行為(UB)。
Question 18 - CUDA C++ 執行模型:Forward Progress [analysis]
CUDA 對 device thread 提供哪種前向進度(forward progress)、其前提是什麼?某個 device thread 開始推進後,推進保證會「傳染」到哪個範圍?為什麼 host 端「在 spin-loop 之外只呼叫一次」
cudaStreamQuery不足以解開等待者,而「迴圈內反覆呼叫」就可以?兩個 kernel 放在不同 stream 等待彼此時為何可能 starvation?
提供 parallel forward progress [intro.progress.9],前提是 host 實作提供 concurrent FP [intro.progress.7];parallel FP 在 thread「執行第一步前不保證開始」,一旦執行一步就升級為 concurrent FP。
傳染範圍:若屬 Cooperative Grid → 整個 grid 最終推進;否則 → 整個 thread-block cluster(蘊含整個 thread block);其他 cluster 的 thread「不保證」推進。
CUDA 只保證「每次 API 呼叫最終 return 或確保至少一個 device thread 推進」;單次 query 不保證 producer 被排上去(parallel FP 不保證自動開始),唯有「迴圈內反覆 query」才持續觸發、保證 producer 最終推進並設旗標。
跨不同 stream 且無事件/依賴連結時,排程可任意挑推進對象(可能總挑「等待者」而餓死「設旗標者」);須用 stream ordering 或顯式依賴串接才能可靠解開。
第五章 Technical Appendices 是「規格與語言契約」的速查層,15 篇可濃縮為下表,每列抓一個最易考的核心對照:
| 主題 (筆記) | 一句話核心考點 |
|---|---|
| 01 Compute Capabilities | a ⊇ f ⊇ baseline;a 僅 exact CC(9.0 起)、f 同 family(10.0 起);warp=32、threads/block=1024、reg=255 |
| 02 Environment Variables | CUDA_VISIBLE_DEVICES 遇無效 index 截斷;module loading 預設 LAZY;*_PTX_JIT 覆蓋 *_JIT |
| 03 C++ Language Features | --std 開全部特性;C++11 缺整個 Concurrency 群組、C++20 缺 Modules+Coroutines;libcu++ 跨 host/device |
| 04 C Stdlib & Lambdas | printf 回傳引數數、上限 32、1 MB 環狀不自動 flush;malloc heap 8 MB/16-byte/不互通;extended lambda 限制多 |
| 05 Language Restrictions | 無 RTTI/例外/long double;__global__ 無 recursion、參數 ≤ 32,764 bytes;host→device raw memcpy 跳 ctor |
| 06 Function & Variable Annotations | __launch_bounds__(.maxntid) 與 __maxnreg__ 不可並用;__restrict__ 增暫存器壓力;__grid_constant__ 唯讀共址 |
| 07 Sync & Atomic Functions | __syncthreads 需 uniform;fence 只排序不保證可見性;atomic 五種推薦 Extended;浮點 CAS 用整數比較防 NaN hang |
| 08 Warp Functions & Macros | Volta+ *_sync 必帶 mask 以強制收斂、不提供 ordering;__CUDA_ARCH__=compute×10、僅 device;__trap 毀 context |
| 09 Compiler Hints & Warp Matrix | #pragma unroll 1=停用、-1=忽略;__builtin_assume false→UB;WMMA CC 7.0、mptr 256-bit、fragment 架構特定 |
| 10 Floating-Point Fundamentals | IEEE 754-2019 但無動態 rounding/無例外/SNaN 不 signaling;FMA 只 round 一次;-ftz 沖 denormal |
| 11 Math Functions & Intrinsics | intrinsic 快但 device-only、只受 -ftz;fdividef 0 ULP vs __fdividef 2 ULP;取整用 rint 非 round |
| 12 Memory Barrier/Pipeline/CG | __pipeline size_and_align 只 4/8/16(global→shared);tiled_partition Size 2 次方 ≤1024;grid.sync 需 cooperative launch |
| 13 CUDA Device Runtime | stream 只 NonBlocking、無 Synchronize(用 tail launch);fire-and-forget vs tail;不支援多 GPU |
| 14 CUDA C++ Memory Model | scope system⊃device⊃block⊃thread;atomic 只在指定 scope 內 atomic;非 atomic+無 happens-before → UB |
| 15 CUDA C++ Execution Model | device 為 parallel FP(前提 host concurrent FP);推進傳染止於 cluster;spin-loop 內須「反覆」query |
貫穿全章的共同精神:host 與 device 是兩個獨立執行空間,凡跨空間引用記憶體/位址/型別、或依賴 __CUDA_ARCH__ 改變介面,幾乎都是 UB;規格上限(CC、參數大小、對齊、scope)與版本/旗標契約絕不能為了便利而違反;正確性靠明確的同步/依賴/scope,不可建立在「碰巧並行」或「碰巧可見」之上。