Improve unified memory usage on the RTX Spark
This commit is contained in:
1 parent
73ebae13a4
commit
221cac39a0
2 files changed
+43
-19
No files matched your search
@@ -1,13 +1,19 @@
|
||||
"""Unified memory (integrated GPU) support, e.g. NVIDIA DGX Spark (GB10).
|
||||
"""Unified memory (integrated GPU) support, e.g. NVIDIA DGX Spark (GB10) and
|
||||
the Windows RTX Spark (N1X).
|
||||
|
||||
On these devices the CPU and GPU share the same physical memory, so moving a
|
||||
module to the CPU frees nothing. Worse, device -> host copies are extremely
|
||||
slow (~100MB/s on GB10), so every "offload to cpu" of a large transformer or
|
||||
text encoder stalls for minutes. When a unified memory device is detected we
|
||||
make module level moves to the CPU a no-op (dtype casts still apply). Tensor
|
||||
level .cpu()/.to('cpu') is left alone since saving, numpy, etc. need it.
|
||||
slow (~100MB/s on GB10 under Linux, ~0.5-2GB/s pageable on Windows/WDDM), so
|
||||
every "offload to cpu" of a large transformer or text encoder stalls. When a
|
||||
unified memory device is detected we make module level moves to the CPU a
|
||||
no-op (dtype casts still apply). Tensor level .cpu()/.to('cpu') is left alone
|
||||
since saving, numpy, etc. need it.
|
||||
|
||||
Set AITK_DISABLE_UNIFIED_MEMORY=1 to turn this off.
|
||||
Note for Windows: WDDM gives CUDA a fixed budget (~80% of system RAM, e.g.
|
||||
~45GB of 54GB) that host allocations do not count against. nvidia-smi / Task
|
||||
Manager only show the small dedicated segment (8GB); the real pool is what
|
||||
torch.cuda.mem_get_info() reports. If a job needs to keep modules on the CPU
|
||||
to stay under that budget, set AITK_DISABLE_UNIFIED_MEMORY=1 to turn this off.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
@@ -20,8 +26,8 @@ _patched = False
|
||||
def is_unified_memory() -> bool:
|
||||
if os.environ.get("AITK_DISABLE_UNIFIED_MEMORY", "0") == "1":
|
||||
return False
|
||||
# linux only (DGX Spark). The Windows RTX Spark stack does not behave the same way
|
||||
if not sys.platform.startswith("linux"):
|
||||
# macOS has no CUDA; MPS unified memory is handled elsewhere
|
||||
if sys.platform == "darwin":
|
||||
return False
|
||||
# NVIDIA only. ROCm APUs report integrated too, but may have a dedicated VRAM carveout
|
||||
if torch.version.hip is not None:
|
||||
|
||||
+29
-11
@@ -36,11 +36,20 @@ const NV_BATCH_FLUSH_MS = 100;
|
||||
const CPU_TEMP_REFRESH_MS = 5000;
|
||||
|
||||
// Power limits for GPUs whose driver reports none (nvidia-smi gives [N/A]).
|
||||
// GB10 (DGX Spark) is a unified SoC with no settable GPU limit; 140 W is
|
||||
// NVIDIA's rated TDP for the GB10 superchip.
|
||||
const KNOWN_POWER_LIMITS_W: Record<string, number> = {
|
||||
'NVIDIA GB10': 140,
|
||||
};
|
||||
// These unified SoCs have no settable GPU limit, so show the rated TDP of the
|
||||
// whole chip. GB10 (DGX Spark) is 140 W. RTX Spark N1X: the 5120-core part is
|
||||
// laptop-only, rated 45-80 W (OEM configurable); the 6144-core part is 140 W
|
||||
// on desktop and 45-80 W in laptops but shares its name, so it falls through
|
||||
// to the desktop figure.
|
||||
const KNOWN_POWER_LIMITS_W: [RegExp, number][] = [
|
||||
[/\bGB10\b/, 140],
|
||||
[/RTX Spark.*5120-core/, 80],
|
||||
[/RTX Spark/, 140],
|
||||
];
|
||||
|
||||
function knownPowerLimit(name: string): number {
|
||||
return KNOWN_POWER_LIMITS_W.find(([re]) => re.test(name))?.[1] ?? NaN;
|
||||
}
|
||||
|
||||
function parseGpuLine(line: string): GpuInfo | null {
|
||||
const [
|
||||
@@ -76,7 +85,7 @@ function parseGpuLine(line: string): GpuInfo | null {
|
||||
},
|
||||
power: {
|
||||
draw: parseFloat(powerDraw),
|
||||
limit: isNaN(parseFloat(powerLimit)) ? (KNOWN_POWER_LIMITS_W[name] ?? NaN) : parseFloat(powerLimit),
|
||||
limit: isNaN(parseFloat(powerLimit)) ? knownPowerLimit(name) : parseFloat(powerLimit),
|
||||
},
|
||||
clocks: {
|
||||
graphics: parseInt(clockGraphics),
|
||||
@@ -88,19 +97,28 @@ function parseGpuLine(line: string): GpuInfo | null {
|
||||
};
|
||||
}
|
||||
|
||||
// Integrated NVIDIA GPUs that share system RAM with the CPU.
|
||||
const UNIFIED_MEMORY_GPU = /\b(GB10|RTX Spark)\b/i;
|
||||
|
||||
/**
|
||||
* Unified-memory GPUs (GB10 / DGX Spark) have no dedicated VRAM, so
|
||||
* nvidia-smi reports memory as [N/A]. Report the system RAM pool they share
|
||||
* instead, like the Mac path does for Apple silicon.
|
||||
* Unified-memory GPUs (GB10 / DGX Spark, RTX Spark) have no dedicated VRAM.
|
||||
* On Linux nvidia-smi reports their memory as [N/A]; on Windows (WDDM) it
|
||||
* reports only the small dedicated segment (8 GB) even though CUDA can use
|
||||
* most of system RAM. Report the system RAM pool they share instead, like
|
||||
* the Mac path does for Apple silicon.
|
||||
*/
|
||||
function isSharedMemoryGpu(g: GpuInfo): boolean {
|
||||
return isNaN(g.memory.total) || UNIFIED_MEMORY_GPU.test(g.name);
|
||||
}
|
||||
|
||||
function withSharedMemory(gpu: GPUApiResponse, cpu: CpuInfo | null): GPUApiResponse {
|
||||
if (!cpu || !gpu.gpus.some(g => isNaN(g.memory.total))) return gpu;
|
||||
if (!cpu || !gpu.gpus.some(isSharedMemoryGpu)) return gpu;
|
||||
const total = Math.round(cpu.totalMemory);
|
||||
const free = Math.round(cpu.availableMemory);
|
||||
return {
|
||||
...gpu,
|
||||
gpus: gpu.gpus.map(g =>
|
||||
isNaN(g.memory.total) ? { ...g, memory: { total, free, used: total - free, shared: true } } : g,
|
||||
isSharedMemoryGpu(g) ? { ...g, memory: { total, free, used: total - free, shared: true } } : g,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user