green-context SM provisioning vs the primary context
Subject: Green contexts: SM reservation, memory-bandwidth QoS, and
allocation-API stalls between co-tenant contexts
Environment: RTX 5060 Ti (sm_120, 36 SMs), Linux x86_64, CUDA 12.8 toolkit,
driver r570-class, single process, driver API green contexts
(cuDevSmResourceSplitByCount minCount=8 → cuDevResourceGenerateDesc →
cuGreenCtxCreate → cuGreenCtxStreamCreate).
What we do: a latency-critical kernel chain (many small dependent kernels,
real-time pose estimation at 60 Hz) is submitted to a stream of an 8-SM green
context. Heavier batch-style kernels (image rendering) run concurrently — in
the device’s PRIMARY context in configuration (a), or in a second green context
provisioned with the complementary 28 SMs in configuration (b).
What we observe (%smid instrumentation + wall-clock, locked clocks):
- Primary-context grids execute on ALL 36 SMs, INCLUDING the 8 SMs
provisioned to the green context (config a). - In config (a) the latency chain’s tail collapses under a primary-context
batch storm: p50 unchanged, p95 0.59 ms → 2.97 ms, max 5.25 ms. - In config (b) — identical storm submitted into the complementary green
context — the latency chain is essentially untouched (+1 us p50 at 100%
duty; +8 us with a 1.3x-oversubscribed storm grid). - Stream priorities (high for the latency chain, low for the storm) do not
change (2) measurably.
Doc discrepancy (the core of the question): the current CUDA Programming
Guide feature survey states: “when a program creates a green context which
uses some set of SMs, other contexts on the GPU will not schedule thread
blocks onto the SMs allocated to the green context”, i.e. RESERVATION.
Our r570/CUDA-12.8 measurement shows median-clean but TAIL violations
(p95 0.59 → 2.97 ms under a primary-context storm; %smid shows primary
blocks on carved SMs at least while the green context is idle).
Questions:
- Is (1)/(2) intended behavior — i.e., green-context SM provisioning CONFINES
work submitted to that green context but does NOT RESERVE those SMs against
kernels launched in the primary context (or other non-green contexts) of
the same process? - If yes: is the recommended pattern for protecting a latency-critical task
to place ALL other GPU workloads into green contexts over the complementary
SMs, leaving nothing compute-heavy in the primary context? - Is there any current or planned mechanism (short of MIG or MPS
active-thread-percentage) to make a green context’s SM set exclusive /
reserved device-wide within a single process? - Do the CUDA 13.x workqueue-configuration APIs
(cudaDevWorkqueueConfigScopeGreenCtxBalanced / wqConcurrencyLimit) change
any of the above, and are they supported on consumer Blackwell (sm_120)?
Additional observation A — DRAM/L2 contention dominates once SMs are carved:
with the latency chain and the batch renderer each confined to disjoint green
contexts (8+8 SMs), the latency chain’s added cost under the concurrent
renderer is +3.1 ms and is INVARIANT to the renderer’s carve size (8/16/28
SMs); a LibTorch inference co-tenant in a third disjoint carve adds a further
+5.2 ms, also SM-invariant. I.e. after SM partitioning, ALL remaining
interference we measure is memory-system contention.
- Is there any current or planned mechanism for DRAM-bandwidth or L2
partitioning at green-context granularity (an analog of MIG’s memory
slices, but sub-context within one process) on workstation/consumer
Blackwell — or is MIG on the professional parts the only bandwidth-QoS
path?
Additional observation B — allocation APIs stall ALL other threads for the
caller’s full queue depth: in a multi-threaded process (each thread
submitting to its own green context), if thread B issues cudaMalloc/cudaFree
or cudaHostAlloc/cudaFreeHost while B’s context has a deep async queue
(~65 ms of enqueued kernels), EVERY other thread’s CUDA calls (including
plain kernel launches into disjoint green contexts) block until B’s queue
drains — we measure the victim’s p50 going from 0.58 ms to 66 ms, i.e. the
full work-unit. By contrast cudaDeviceSynchronize from B affects no one but
B, and deep queues / second submission threads per se are clean. (Practical
consequence we hit immediately: any library that stages transfers through
per-call cudaHostAlloc — e.g. a framework’s pageable device-to-host copy
path — periodically freezes a co-resident real-time task for ~100 ms.)
- Is this queue-drain-while-holding-global-state behavior of the allocation
APIs expected and documented? Is there a recommended pattern beyond
“pre-allocate everything and never call alloc/free at runtime”, and is
per-context isolation of allocation-API serialization planned? This seems
directly relevant to the green-context latency-isolation use case, since
the victim task has no way to protect itself against a co-tenant’s
allocation calls.
Minimal standalone repros (~150-200 lines each, no external deps) available
on request: reservation/storm matrix (green_probe2l/2m) and the
allocation-stall matrix incl. clean controls — burst depth, single long
kernel, deviceSync, D2H variants (green_probe2o).