Green Contexts
重點總覽
| 項目 | 重點 |
|---|---|
| Green Context (GC) 本質 | 一個輕量 context,建立時即綁定一組特定 GPU 資源(目前是 SMs 與 work queues);GPU 工作只能用其 provisioned 的資源 |
| 核心價值 | 降低/控制共用資源造成的干擾,確保 latency-sensitive kernel 隨時有 SM 可立即啟動;亦可快速測試「用較少 SM」的效果 |
| 無需改 kernel | 只改 host 端:建立 green context + 在該 GC 上建立 stream。kernel 與啟動幾何皆不變 |
| 執行緒模型 | CUDA 13.1 起以 execution context (EC) 抽象暴露在 runtime;EC 可對應 primary context 或 green context,本節兩詞交替使用 |
| 建議用法 | green context runtime 暴露後,強烈建議直接用 CUDA runtime API(本節僅用 runtime API) |
| device resource | cudaDevResource,綁定特定 device;三型別:SM、workqueue config、pre-existing workqueue |
| resource descriptor | cudaDevResourceDesc_t,封裝一或多個 resource;GC 只能存取其建立時 descriptor 內的資源 |
| 建立四步驟 | 1) 取得資源 → 2) split SM 資源(+ 選配 WQ)→ 3) 產生 descriptor → 4) cudaGreenCtxCreate |
| launch work | cudaExecutionCtxStreamCreate 建立屬於 GC 的 stream,於其上 <<<>>> 啟動的 kernel 僅能用該 GC 資源 |
| 重要限制 | 即使分開 provisioned SM 與 WQ,並不保證 真正並行;只是「移除阻礙並行的因素」 |
Green Context 是什麼
green context (GC) 是一個 輕量 context,從建立那一刻起就與一組特定 GPU 資源綁定。使用者可在建立時 partition GPU 資源(目前是 streaming multiprocessors, SMs 與 work queues, WQs),使得 targeting 該 GC 的 GPU 工作 只能使用其 provisioned 的 SM 與 work queue。如此可減少或更好地控制因共用資源造成的干擾。一個應用程式可擁有多個 green context。
- 使用 green context 不需要任何 GPU code(kernel)變更,只需小幅 host 端改動(建立 green context、為其建立 stream)。
- 典型情境:確保某些 SM 永遠可供 latency-sensitive kernel 立即啟動(在無其他限制下);或快速測試「使用較少 SM」的效果而不改 kernel。
- green context 最早經由 CUDA Driver API 提供;CUDA 13.1 起 經由 execution context (EC) 抽象暴露在 CUDA runtime。
一個 execution context 目前可對應 primary context(runtime API 使用者一直隱式互動的 context)或 green context。本節在指 green context 時,「execution context」與「green context」交替使用。runtime 已暴露 green context 後,強烈建議直接用 CUDA runtime API。
Motivation / 何時使用
啟動 CUDA kernel 時,使用者 無法直接控制 kernel 會在幾顆 SM 上執行,只能透過改變 launch geometry(或任何影響每 SM 最大 active block 數的因素)間接影響。當多個 kernel 在 GPU 上並行(不同 stream 或 CUDA graph 的一部分),它們也可能 爭用相同 SM 資源。
green context 透過 partition SM 資源 解決此問題:某 GC 只能用建立時 provisioned 的特定 SM。
無 Green Context(kernel A 先佔滿全部 SM)
SM% │████████████████ A ███████████──┐
│ B 被延遲 → └─B 等 A ramp down 才能開始
└───────────────────────────────────────► time
有 Green Context(A 限 80% SM,B 保留專屬 SM)
SM% │████████ A ████████████████████
│░░░░ B 立即開始(有專屬 SM)░░░░
└───────────────────────────────────────► time
- 上圖對應原文 Figure 45:A 先啟動佔滿 SM,latency-sensitive 的 B 後啟動時無 SM 可用,必須等 A 的 thread block 結束。
- 用 GC 後,A 只能用 GC-A 的 SM(不論 launch config),B 被啟動時 保證有可用 SM 立即開始(除非有其他資源限制)。A 的 duration 可能因此變長,但 B 不再被「無 SM」延遲。
- 每個 GC 能用幾顆 SM 應由使用者在建立時 逐案決定。
Work Queues 的角色
SM 是可 provisioned 的一種資源;另一種是 work queues (WQs)。把 work queue 想成一個黑箱資源抽象,它(連同其他因素)會影響 GPU 工作的並行度。
- 若獨立的 GPU 工作(如不同 stream 上的 kernel)映射到 同一個 work queue,可能引入 false dependence,導致序列化執行。
- 即使 SM 可用,若 B 與 A 映射到同一 WQ,B 仍可能必須等 A 完整結束。
- 使用者可透過
CUDA_DEVICE_MAX_CONNECTIONS環境變數影響 GPU 上 work queue 數量上限。 - GC 讓使用者用「預期的並行 stream-ordered workload 數」表達最大並行度;driver 以此為 hint,盡量避免不同 EC 的工作用到同一 WQ。
即使為各 GC 分開 provisioned SM 與 work queue,仍不保證 獨立 GPU 工作真正並行執行。最好把 Green Contexts 整節技術視為「移除可能阻礙並行的因素(降低潛在干擾)」,而非保證並行。
GC vs MIG vs MPS
| 機制 | 切分粒度 | 何時設定 | SM 是否固定 | 與 GC 關係 |
|---|---|---|---|---|
| Green Context | 單一 process 內,per-context | 程式執行中、建立 GC 時 | 是,固定那 N 顆 SM | 最輕量(多數結構由 primary context 共享) |
| MIG | 把 GPU 靜態切成多個 instance(「小 GPU」) | 程式啟動前 | instance 級 | 可在某 MIG instance 內再用 GC(以該 instance 資源 partition) |
| MPS(動態) | process 級,active thread percentage 上限 | 啟動前以環境變數 | 否,任意 N 顆且隨時間變 | 不同 process;GC 在單一 process 內也適用 |
| MPS(靜態,13.1 起) | process 級靜態 partition | 程式啟動時指定 | 是 | 仍是 process 級;GC 可單一 process 內,且 GC 允許 SM oversubscription,MPS 靜態不允許 |
- MIG 無法 解決「同一應用內 B 被佔滿 SM 的 A 延遲」的問題(單一 instance 內仍會發生);解法是在 MIG 上 搭配 GC。
- MPS 的 active thread percentage 表示「不超過 x% 的 SM」但那 N 顆可以是任意且隨時間變;GC 的 N 顆是 固定特定 的 N 顆。
- 透過
cuCtxCreatedriver API + execution affinity 也能做 programmatic SM partition,但同樣是任意 N 顆、會變動。 - 建立 GC 遠比 MPS context 輕量,因許多底層結構由 primary context 擁有並共享。
Ease of Use(最小改動)
原本只能靠 launch geometry 間接影響 SM 用量:
int gpu_device_index = 0; // GPU ordinal
cudaSetDevice(gpu_device_index);
cudaStream_t strm1, strm2;
cudaStreamCreateWithFlags(&strm1, cudaStreamNonBlocking);
cudaStreamCreateWithFlags(&strm2, cudaStreamNonBlocking);
// 無法控制各 stream 上 kernel 能用幾顆 SM
code_that_launches_kernels_on_streams(strm1, strm2);
CUDA 13.1 起,只要加幾行 host code、不改 kernel,即可控制每個 stream 上 kernel 可用的 SM:
// 1) 取得全部 SM 資源
cudaDevResource initial_GPU_SM_resources{};
cudaDeviceGetDevResource(gpu_device_index, &initial_GPU_SM_resources,
cudaDevResourceTypeSm);
// 2) split:一組 16 SM、一組 8 SM
cudaDevSmResource result[2]{{}, {}};
cudaDevSmResourceGroupParams group_params[2] = {
{.smCount=16, .coscheduledSmCount=0, .preferredCoscheduledSmCount=0, .flags=0},
{.smCount=8, .coscheduledSmCount=0, .preferredCoscheduledSmCount=0, .flags=0}};
cudaDevSmResourceSplit(&result[0], 2, &initial_GPU_SM_resources, nullptr, 0,
&group_params[0]);
// 3) 各自產生 descriptor
cudaDevResourceDesc_t resource_desc1{}, resource_desc2{};
cudaDevResourceGenerateDesc(&resource_desc1, &result[0], 1);
cudaDevResourceGenerateDesc(&resource_desc2, &result[1], 1);
// 4) 建立兩個 green context
cudaExecutionContext_t my_green_ctx1{}, my_green_ctx2{};
cudaGreenCtxCreate(&my_green_ctx1, resource_desc1, gpu_device_index, 0);
cudaGreenCtxCreate(&my_green_ctx2, resource_desc2, gpu_device_index, 0);
// 唯一需改的呼叫端:改用 EC 版 stream 建立 API
cudaStream_t strm1, strm2;
cudaExecutionCtxStreamCreate(&strm1, my_green_ctx1, cudaStreamDefault, 0);
cudaExecutionCtxStreamCreate(&strm2, my_green_ctx2, cudaStreamDefault, 0);
// 其餘不變:strm1 上 kernel 最多 16 SM、strm2 上最多 8 SM
code_that_launches_kernels_on_streams(strm1, strm2);
唯一的呼叫端差異是 用 cudaExecutionCtxStreamCreate 取代 cudaStreamCreateWithFlags,函式內部與 kernel 完全不動。
許多 execution context API(如上例)接受 顯式的 cudaExecutionContext_t handle,因此 忽略 呼叫 thread 的 current context。這是從過去依賴 thread-local state (TLS) 的隱式 context 程式設計,轉向 顯式 context-based 程式設計,語意更清楚也帶來額外好處。
Device Resource 與 Resource Descriptor
green context 的核心是綁定特定 device 的 device resource (cudaDevResource);資源可被組合並封裝進 descriptor (cudaDevResourceDesc_t)。GC 只能存取建立時 descriptor 內封裝的資源。
struct {
enum cudaDevResourceType type;
union {
struct cudaDevSmResource sm; // SM 型
struct cudaDevWorkqueueConfigResource wqConfig; // WQ config 型
struct cudaDevWorkqueueResource wq; // pre-existing WQ 型
};
};
- 有效 type:
cudaDevResourceTypeSm、cudaDevResourceTypeWorkqueueConfig、cudaDevResourceTypeWorkqueue;cudaDevResourceTypeInvalid代表無效。 - 一個 GPU device 預設具備全部三型:涵蓋全部 SM 的 SM 資源、涵蓋全部 WQ 的 workqueue config 資源、及其對應的 workqueue 資源;皆可由
cudaDeviceGetDevResource取得。 - 查詢某 EC 或 stream 是否關聯某型資源:
cudaExecutionCtxGetDevResource(EC,可關聯多型)、cudaStreamGetDevResource(stream,只能關聯 SM 型)。 - 建議所有 device resource struct 都 zero-initialize。
| Struct | 關鍵欄位 | 由誰設定 |
|---|---|---|
cudaDevSmResource |
smCount(SM 數)、minSmPartitionSize(partition 最小 SM 數)、smCoscheduledAlignment(保證同 GPC 共排的 SM 數,與 cluster 相關;flags=0 時 smCount 為其倍數)、flags(0 或 cudaDevSmResourceGroupBackfill) |
由 split API 或 cudaDeviceGetDevResource 填,使用者勿直接設 |
cudaDevWorkqueueConfigResource |
device、wqConcurrencyLimit(避免 false dependency 的預期 stream-ordered workload 數)、sharingScope |
由使用者設(除 cudaDeviceGetDevResource 取得者外,無類似 split 的產生 API) |
cudaDevWorkqueueResource(pre-existing WQ) |
無使用者可設欄位 | 由 cudaDeviceGetDevResource 取得 |
sharingScope兩值:cudaDevWorkqueueConfigScopeDeviceCtx(預設,所有 WQ 資源跨所有 context 共享)與cudaDevWorkqueueConfigScopeGreenCtxBalanced(driver 盡量在各 GC 間用 不重疊 的 WQ,以wqConcurrencyLimit為 hint)。
建立 Green Context:四步驟
Step 1 Step 2 Step 3 Step 4
取得資源 → split SM 資源 → 產生 descriptor → 建立 GC
GetDevResource SplitByCount / Split GenerateDesc GreenCtxCreate
(device/EC/ (+ 選配 WQ config) (封裝一或多 resource) (provision 資源)
stream)
│
建立屬於 GC 的 stream ◄───────────────────┘
ExecutionCtxStreamCreate → <<< >>> 只用該 GC 資源
Step 1:取得可用 GPU 資源
三個可能起點:device、execution context、stream。
// device:
cudaError_t cudaDeviceGetDevResource(int device, cudaDevResource* resource,
cudaDevResourceType type);
// execution context:
cudaError_t cudaExecutionCtxGetDevResource(cudaExecutionContext_t ctx,
cudaDevResource* resource,
cudaDevResourceType type);
// stream(只支援 SM 型):
cudaError_t cudaStreamGetDevResource(cudaStream_t hStream,
cudaDevResource* resource,
cudaDevResourceType type);
- 三者都接受所有有效 type,唯一例外 是
cudaStreamGetDevResource只支援 SM 型。 - 通常起點是 GPU device。成功取得 SM 資源後可讀
sm.smCount、sm.minSmPartitionSize、sm.smCoscheduledAlignment。 - 取得 WQ config 資源時,若起點是 device,
wqConcurrencyLimit會等於CUDA_DEVICE_MAX_CONNECTIONS的值或其預設。
Step 2:partition SM 資源
把可用 SM 資源 靜態 split 成一或多個 partition(可能留下一個 remaining partition)。兩個 split API 都僅適用 SM 型資源:
| API | 能力 | signature 要點 |
|---|---|---|
cudaDevSmResourceSplitByCount |
只能建 同質 group(每組 minCount SM)+ 可選 remaining | result, *nbGroups, input, remaining, useFlags, minCount |
cudaDevSmResourceSplit |
可建 異質 group(單次呼叫不同 SM 數)+ 可選 remainder | result, nbGroups, input, remainder, flags, groupParams |
SplitByCount:請求把 input 切成 *nbGroups 組、每組 minCount SM。實際結果的 *nbGroups 可能變小(≤ 請求值)、實際 N 可能變大(≥ minCount),因架構特定的 granularity/alignment 要求。CC 9.0 範例:每 partition 最少 8 SM、SM 數須為 8 的倍數(useFlags=0)。
unsigned int min_SM_count = 8;
unsigned int actual_split_groups = 5; // 可能被更新
cudaDevResource actual_split_result[5] = {{}, {}, {}, {}, {}};
cudaDevResource remaining_partition = {};
cudaDevSmResourceSplitByCount(&actual_split_result[0], &actual_split_groups,
&avail_resources, &remaining_partition,
0 /*useFlags*/, min_SM_count);
result=nullptr可用來 查詢 會建立幾組;remaining=nullptr表示不在乎 leftover。- remaining(leftover)partition 不具備 與同質 group 相同的功能/效能保證。
useFlags預設 0,亦支援cudaDevSmResourceSplitIgnoreSmCoscheduling、cudaDevSmResourceSplitMaxPotentialClusterSize。- 任何 split 出的
cudaDevResource無法直接再 split,必須先以它建 descriptor 與 GC(即先做 Step 3、4)。
Split(異質):單次呼叫產生 non-overlapping 異質 partition,放入 result 陣列,各組 SM 數可不同但 絕不為 0。每組以 cudaDevSmResourceGroupParams 指定需求:
| 欄位 | 作用 | 值 |
|---|---|---|
smCount |
該組 SM 數 | 0 = discovery mode(探索);非 0 須為 2 的倍數且在 [2, input.sm.smCount],且 flags=0 時為實際 coscheduledSmCount 的倍數 |
coscheduledSmCount |
為發動 cluster 而「共排」的 SM 數(CC 9.0+),影響組大小與可支援 cluster 尺寸 | 0 = 用該架構預設;非 0 須為 2 的倍數且 ≤ 上限 |
preferredCoscheduledSmCount |
hint:嘗試把多個 coscheduledSmCount 的組合併成更大組(供 CC 10.0+ 的 preferred cluster dim) | 0 = 預設;非 0 須為實際 coscheduledSmCount 的倍數 |
flags |
是否允許 backfill | 0(resulting SM 為 coscheduled 倍數)或 cudaDevSmResourceGroupBackfill(盡量塞滿,backfilled SM 不提供 coschedule 保證) |
- discovery mode:把某組
smCount設 0,成功後該groupParams.smCount會被填入有效非 0 值(actual smCount);若result非 null,對應 group 的sm.smCount也設為同值。 groupParams各 entry 由左(index 0)到右評估,順序重要(順序不同可能導致後面的組沒 SM 可用)。coscheduledSmCount/preferredCoscheduledSmCount設 0 表示用預設值,兩者預設皆等於該 device(透過cudaDeviceGetDevResource取得的)SM 資源之smCoscheduledAlignment。- 回傳值依
result:result != nullptr時只有成功建立 nbGroups 個有效組才回cudaSuccess,否則回錯(不同錯誤可能同碼如CUDA_ERROR_INVALID_RESOURCE_CONFIGURATION,開發時用CUDA_LOG_FILE取得更詳細描述);result == nullptr是 dry-run,即使某組 smCount 為 0 也可能回cudaSuccess,適合探索。 - remainder(若存在)對 SM 數與 coschedule 無任何約束,由使用者自行探索。
不用 cluster 時:coscheduledSmCount/preferredCoscheduledSmCount 用最小值 2 或直接設 0 即可。用 cluster 時:依架構最大可攜 cluster 大小選 coscheduledSmCount;在 CC 10.0 (Blackwell)+ 用 preferred cluster 時,preferredCoscheduledSmCount 選 > 2 的值。backfill 組仍可支援 cluster(至少保證一個 coscheduledSmCount 大小)。
Step 2(續):加入 workqueue 資源
若也要指定 WQ 資源,須 顯式 建立(無類似 split 的 API):
cudaDevResource split_result[2] = {{}, {}};
// split_result[0] 由 split API 填(nbGroups=1);最後一個是 WQ 資源
split_result[1].type = cudaDevResourceTypeWorkqueueConfig;
split_result[1].wqConfig.device = 0; // device ordinal
split_result[1].wqConfig.sharingScope = cudaDevWorkqueueConfigScopeGreenCtxBalanced;
split_result[1].wqConfig.wqConcurrencyLimit = 4; // hint:最多 4 並行
wqConcurrencyLimit = 4 提示 driver 預期最多 4 個並行 stream-ordered workload;driver 盡量在可能時尊重此 hint 分配 work queue。
Step 3:建立 Resource Descriptor
cudaError_t cudaDevResourceGenerateDesc(cudaDevResourceDesc_t* phDesc,
cudaDevResource* resources,
unsigned int nbResources);
// 把 actual_split_result[2] 到 [4] 共 3 個資源封裝進一個 descriptor
cudaDevResourceDesc_t resource_desc;
cudaDevResourceGenerateDesc(&resource_desc, &actual_split_result[2], 3);
成功條件:
- 全部
nbResources個資源須屬 同一 GPU device。 - 多個 SM 型資源組合時,須來自 同一次 split 呼叫 且有 相同
coscheduledSmCount(若非 remainder 部分)。 - 最多只能有一個 workqueue config 或 workqueue 型資源。
- 被組合的資源須在
resources陣列中 連續配置。可同時組合不同型(如 SM + WQ)。
Step 4:建立 Green Context
cudaError_t cudaGreenCtxCreate(cudaExecutionContext_t* phCtx,
cudaDevResourceDesc_t desc,
int device, unsigned int flags);
cudaSetDevice(current_device); // 或 cudaInitDevice,先初始化 primary context
cudaExecutionContext_t green_ctx{};
cudaGreenCtxCreate(&green_ctx, resource_desc, current_device, 0);
flags應設 0。GC 只能存取 descriptor 內封裝的資源,這些資源於此步被 provisioned。- 建議 先以
cudaInitDevice或cudaSetDevice顯式初始化該 device 的 primary context,避免建立 GC 時額外的 primary context 初始化開銷。 - 建立成功後,可對該 EC 逐型呼叫
cudaExecutionCtxGetDevResource驗證其資源。
多 GC 與 oversubscription:多數情況各 GC 有 非重疊 的 SM 集合(如 GC1 用 result[2..4]、GC2 用 result[0..1],每顆 SM 只屬一個 GC)。但 SM oversubscription 也可能(如 GC2 用 result[0..2],則 result[2] 的 SM 被兩個 GC 共用)。
SM oversubscription 應 逐案謹慎使用。被 oversubscribed 的 SM 同時 provisioned 給多個 GC,可能再次引入干擾,違背 GC「降低干擾」的初衷。
Launching Work
在 GC 上啟動 kernel,先用 cudaExecutionCtxStreamCreate 為該 GC 建立 stream,於其上 <<<>>> 或 cudaLaunchKernel 啟動的 kernel 只能用該 stream 的 EC 可用資源:
cudaStream_t green_ctx_stream;
int priority = 0;
cudaExecutionCtxStreamCreate(&green_ctx_stream, green_ctx,
cudaStreamDefault, priority);
my_kernel<<<grid_dim, block_dim, 0, green_ctx_stream>>>();
cudaGetLastError();
- 當
green_ctx是 green context 時,傳入的預設 stream 建立 flag 等同cudaStreamNonBlocking。 - 只要使用者把屬於 GC 的 stream 傳給 library,library 也能輕鬆受惠於 GC。
CUDA Graphs 的細節
對 CUDA graph 中的 kernel,graph 被 launch 到的 stream 不決定 SM 資源——該 stream 僅用於 dependency tracking。節點的 EC 是在 node 建立時 決定的。
- stream capture:參與 capture 的 stream 之 EC 決定相關 graph node 的 EC。
- graph API:使用者須為每個相關 node 顯式設定 EC。加 kernel node 應用多型的
cudaGraphAddNode(typecudaGraphNodeTypeKernel),並設cudaKernelNodeParamsV2之.kernel.ctx欄位;應避免cudaGraphAddKernelNode(不允許指定 EC)。 - 同一 graph 內不同 node 可屬不同 EC。
- 驗證:Nsight Systems node tracing mode(
--cuda-graph-trace node)可觀察各 node 實際執行的 GC(預設 graph tracing mode 會把整個 graph 歸在 launch stream 的 GC 下,無法反映各 node 的 EC)。程式化驗證可用 driver APIcuGraphKernelNodeGetParams比對node_params.ctx(CUgraphNode與cudaGraphNode_t可互換,但需 includecuda.h並-lcuda)。
Thread Block Clusters
帶 thread block cluster 的 kernel 可像一般 kernel 一樣在 GC stream 上啟動,用該 GC 的 provisioned 資源。Step 2 已說明 split 時如何指定 coscheduled SM 數以利 cluster。仍應用 occupancy API 求最大可行 cluster 大小:
cudaLaunchConfig_t config = {0};
config.gridDim = grid_dim; // 須為 cluster dim 的倍數
config.blockDim = block_dim;
config.dynamicSmemBytes = expected_dynamic_shared_mem;
cudaLaunchAttribute attribute[1];
attribute[0].id = cudaLaunchAttributeClusterDimension;
attribute[0].val.clusterDim = {1, 1, 1};
config.attrs = attribute; config.numAttrs = 1;
config.stream = gc_stream; // 必須傳該 kernel 會用的 stream
int max_potential_cluster_size = 0;
cudaOccupancyMaxPotentialClusterSize(&max_potential_cluster_size, cluster_kernel, &config);
int num_clusters = 0;
cudaOccupancyMaxActiveClusters(&num_clusters, cluster_kernel, &config);
- 把 GC stream 設為
cudaLaunchConfig的stream,則cudaOccupancyMaxPotentialClusterSize與cudaOccupancyMaxActiveClusters會 把該 GC provisioned 的 SM 納入考量。 - 此用例對「被傳入 GC stream 的 library」與「GC 由 remaining 資源建立」的情況特別重要。
驗證 GC 使用
- Nsight Systems:不同 GC 的 kernel 出現在 CUDA HW timeline 的不同 Green Context row。
- Nsight Compute:Session 頁的 Green Context Resources 提供 provisioned 資源的 bitmask(可確認 GC 間無重疊或預期的 oversubscription 重疊);Details 的 Launch Statistics 列出該 GC provisioned 的 SM 數。
工具顯示的是 kernel 可存取 的 SM 數,不是 kernel 實際跑在幾顆 SM 上。實際用量取決於 kernel 本身(launch geometry 等)與同時段的其他工作。
Additional Execution Context APIs
| API | 用途 |
|---|---|
cudaExecutionCtxRecordEvent(ctx, event) |
錄一個 event,捕捉該 EC 此刻全部 work/activity;比對多 stream 的 EC 用 cudaEventRecord 方便 |
cudaExecutionCtxWaitEvent(ctx, event) |
讓 未來 提交給該 EC 的所有 work 等待 event 中捕捉的 work;比逐 stream cudaStreamWaitEvent 方便 |
cudaExecutionCtxSynchronize(ctx) |
CPU 端阻塞,直到該 EC 完成全部 work |
cudaExecutionCtxGetDevice(...) |
取得 EC 關聯的 device |
cudaExecutionCtxGetId(...) |
取得 EC 的唯一識別碼 |
cudaExecutionCtxDestroy(ctx) |
銷毀顯式建立的 EC |
cudaDeviceGetExecutionCtx(...) |
取得 device 的 primary context(作為 EC) |
若傳給 cudaExecutionCtxSynchronize 的 EC 不是 由 cudaGreenCtxCreate 建立,而是由 cudaDeviceGetExecutionCtx 取得(即 device 的 primary context),則該呼叫會 連同同一 device 上所有已建立的 green context 一起同步。
完整範例(critical kernel 提早完成)
情境:兩個 kernel 跑在兩條 non-blocking stream。先在 strm1 啟動長跑 kernel delay_kernel_us(block 數超過 SM 數、需多波),短暫等待後在 strm2 啟動短而關鍵的 critical_kernel。量測兩者 GPU duration 與「CPU 啟動到完成」時間。
無 GC(critical 在高 priority stream,但仍須等部分 block)
stream13 ████████ delay_kernel ███████████████████
stream14 ⟵ 等 0.9ms ⟶ ███ critical ███ ← 被延遲
有 GC(GC2=112 SM 給 delay,GC3=16 SM 給 critical,無重疊)
GC2(112SM) ████████ delay_kernel ██████████████████████ ← 變慢
GC3( 16SM) ███ critical ███ ← 幾乎即時開始
- 不用 GC、只靠高 priority stream:critical kernel 可在 delay kernel 部分 block 完成後開始,但仍須等某些長 block,故被延遲(原文範例為 0.9ms;若兩 stream 同 priority 會更晚)。
- 用兩個非重疊 GC(H100 132 SM,範例切 16 SM 給 critical、112 SM 給 delay)後,critical kernel 幾乎即時開始。
- 代價:critical 與 delay kernel 各自 duration 可能 變長(受限於各 GC 的 SM)。但 關鍵結果 是 critical work 能 顯著提早開始與完成。實際 SM split 應逐案實驗決定。
用「delay kernel」當長跑 kernel 的 proxy:每個 thread block 跑固定微秒數,且 block 數超過 GPU 可用 SM 數,以保證需要多波。
考試/測驗重點
| 主題 | 必記重點 |
|---|---|
| GC 定義 | 輕量 context,建立時綁定特定 GPU 資源(SMs / work queues);不需改 kernel,只改 host 端 |
| 暴露時程 | 最早 Driver API;CUDA 13.1 起以 execution context (EC) 抽象暴露於 runtime;建議直接用 runtime API |
| EC 對應 | EC = primary context 或 green context;許多 EC API 接受顯式 handle / 忽略 thread current context |
| 三種 resource type | cudaDevResourceTypeSm / cudaDevResourceTypeWorkqueueConfig / cudaDevResourceTypeWorkqueue(+ Invalid) |
| stream 限制 | cudaStreamGetDevResource 只支援 SM 型;stream 只能關聯 SM 型資源,EC 可關聯多型 |
| 建立四步驟 | GetDevResource → SmResourceSplit(ByCount) → GenerateDesc → GreenCtxCreate(flags=0) |
| SplitByCount vs Split | ByCount 只能同質 group;Split 可單次建異質 group + discovery mode(smCount=0) |
| split 結果保證 | 結果 smCount 為 2 的倍數、在 [2, input.smCount];flags=0 時為 actual coscheduledSmCount 的倍數 |
| coscheduledSmCount | 為發動 cluster 共排的 SM 數(CC 9.0+);preferredCoscheduledSmCount 供 CC 10.0+ preferred cluster dim(hint) |
| backfill flag | cudaDevSmResourceGroupBackfill:盡量塞滿 SM,backfilled SM 無 coschedule 保證 |
| descriptor 限制 | 同 device / 同次 split 且同 coscheduledSmCount / 至多一個 WQ 資源 / 陣列須連續 |
| WQ 資源 | 須顯式設 type、device、wqConcurrencyLimit、sharingScope;無 split 類產生 API |
| sharingScope | DeviceCtx(預設,全共享)/ GreenCtxBalanced(盡量非重疊 WQ,concurrencyLimit 為 hint) |
| launch | cudaExecutionCtxStreamCreate 建 GC stream;GC stream 預設 flag 等同 cudaStreamNonBlocking |
| CUDA graph | graph 的 launch stream 不決定 SM;node EC 在建 node 時設;graph API 用 cudaGraphAddNode 設 .kernel.ctx,避免 cudaGraphAddKernelNode |
| occupancy + GC | 傳 GC stream 給 cudaOccupancyMaxPotentialClusterSize / MaxActiveClusters 才會納入 GC 的 SM |
| primary ctx 同步 | cudaExecutionCtxSynchronize 對 primary context 會連同該 device 全部 GC 一起同步 |
| 重大保證 | 即使分開 provisioned SM/WQ,不保證 真正並行;只是移除阻礙並行的因素 |
| GC vs MIG/MPS | GC 固定特定 N 顆 SM、單 process 適用、最輕量、允許 SM oversubscription;MPS 靜態不允許 oversubscription |
| oversubscription | 同一 SM 可 provisioned 給多 GC,須逐案謹慎使用 |
| 工具顯示語意 | Nsight 顯示的是 kernel 可存取 的 SM 數,非實際使用數 |
Related Notes
- 04-CUDA-Features/03-CUDA-Graphs-Structure-and-Capture
- 04-CUDA-Features/04-CUDA-Graphs-Updating-and-Conditional
- 04-CUDA-Features/07-Cooperative-Groups-Deep-Dive
- 04-CUDA-Features/08-Programmatic-Dependent-Launch-Deep-Dive
- 04-CUDA-Features/16-Work-Stealing-Cluster-Launch-Control
- 04-CUDA-Features/25-Driver-Entry-Point-Access
- 03-Advanced-CUDA/01-Advanced-Launch-and-Clusters
- 03-Advanced-CUDA/08-CUDA-Driver-API
- 03-Advanced-CUDA/10-Tour-of-CUDA-Features
- 02-Programming-GPUs/15-Async-Callbacks-Ordering-Graphs
- 04-CUDA-Features/Practice-CUDA-Features
- 00-Dashboard/Exam-Traps