| 575 | let _cachedVramMb: number | null = null; |
| 576 | |
| 577 | function probeNvidiaVramMb(): number | null { |
| 578 | if (_cachedVramMb !== null) return _cachedVramMb; |
| 579 | try { |
| 580 | // Synchronous, runs once per process (cached). ~50ms on typical systems. |
| 581 | const out = execSync("nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits", { |
| 582 | timeout: 3000, |
| 583 | encoding: "utf-8", |
| 584 | stdio: ["pipe", "pipe", "pipe"], |
| 585 | }).trim(); |
| 586 | const mb = parseInt(out.split("\n")[0] ?? "", 10); |
| 587 | if (Number.isFinite(mb) && mb > 0) { |
| 588 | _cachedVramMb = mb; |
| 589 | return mb; |
| 590 | } |
| 591 | } catch { |
| 592 | // nvidia-smi not available or no NVIDIA GPU |
| 593 | } |
| 594 | return null; |
| 595 | } |
| 596 | |
| 597 | function getGpuMemBudgetMb(): number { |
| 598 | const vram = probeNvidiaVramMb(); |