Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions src/lib/inference/nim.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,94 @@ describe("nim", () => {
}
});

// Regression #3988: WSL2 d3d12 shims (e.g. Snapdragon X "nvidia-smi.exe")
// return a generic name like "JMJWOA-Generic-GPU" for non-NVIDIA hardware.
// The primary path used to accept any name from nvidia-smi, which made the
// preflight report "NVIDIA GPU detected" on hosts with no NVIDIA hardware.
it("rejects WDDM placeholder names on hosts without NVIDIA firmware (#3988)", () => {
const runCapture = vi.fn((cmd: string | string[]) => {
if (!Array.isArray(cmd)) throw new Error("expected argv array");
if (
cmd[0] === "nvidia-smi" &&
cmd.some((a: string) => a.includes("name,memory.total"))
) {
return "JMJWOA-Generic-GPU, 65471\n";
}
return "";
});
const { nimModule, restore } = loadNimWithMockedRunner(runCapture);

try {
// Snapdragon X WSL2 has no DMI / devicetree NVIDIA platform marker, so
// the firmware classification falls through to "linux" and the
// placeholder name is not vouched for.
withFirmwareModel("Microsoft Corporation Virtual Machine", () => {
expect(nimModule.detectGpu()).toBeNull();
});
} finally {
restore();
}
});

// Even when the WDDM shim returns the placeholder with an `NVIDIA ` prefix
// (e.g. "NVIDIA JMJWOA-Generic-GPU"), `\bNVIDIA\b` alone is not enough to
// vouch for the device on generic Linux firmware — the placeholder family
// must keep requiring a firmware platform vouch. Regression guard for the
// CodeRabbit review comment on #4062.
it("rejects vendor-prefixed WDDM placeholders on generic firmware (#3988)", () => {
const runCapture = vi.fn((cmd: string | string[]) => {
if (!Array.isArray(cmd)) throw new Error("expected argv array");
if (
cmd[0] === "nvidia-smi" &&
cmd.some((a: string) => a.includes("name,memory.total"))
) {
return "NVIDIA JMJWOA-Generic-GPU, 65471\n";
}
return "";
});
const { nimModule, restore } = loadNimWithMockedRunner(runCapture);

try {
withFirmwareModel("Microsoft Corporation Virtual Machine", () => {
expect(nimModule.detectGpu()).toBeNull();
});
} finally {
restore();
}
});

// Real DGX Spark legitimately reports "NVIDIA JMJWOA-Generic-GPU" via the
// primary nvidia-smi path on some firmware revisions (#3510). The Spark
// firmware platform tag must continue to vouch for the device even when
// the name itself does not match a known NVIDIA family.
it("accepts placeholder names when firmware confirms NVIDIA platform (#3510)", () => {
const runCapture = vi.fn((cmd: string | string[]) => {
if (!Array.isArray(cmd)) throw new Error("expected argv array");
if (
cmd[0] === "nvidia-smi" &&
cmd.some((a: string) => a.includes("name,memory.total"))
) {
return "JMJWOA-Generic-GPU, 131072\n";
}
return "";
});
const { nimModule, restore } = loadNimWithMockedRunner(runCapture);

try {
withFirmwareModel("NVIDIA DGX Spark", () => {
expect(nimModule.detectGpu()).toMatchObject({
type: "nvidia",
name: "JMJWOA-Generic-GPU",
count: 1,
totalMemoryMB: 131072,
platform: "spark",
});
});
} finally {
restore();
}
});

it("detects GB10 unified-memory GPUs as Spark-capable NVIDIA devices", () => {
const runCapture = vi.fn((cmd: string | string[]) => {
if (!Array.isArray(cmd)) throw new Error("expected argv array");
Expand Down
51 changes: 44 additions & 7 deletions src/lib/inference/nim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,30 @@ import { VLLM_PORT } from "../core/ports";
const UNIFIED_MEMORY_GPU_TAGS = ["GB10", "Thor", "Orin", "Xavier", "Jetson", "Tegra"];
const NIM_STATUS_PROBE_TIMEOUT_MS = 5000;

// On Windows-on-ARM (Snapdragon X) WSL2 hosts, a d3d12/WDDM shim publishes a
// `nvidia-smi.exe` that returns a placeholder name (e.g. "JMJWOA-Generic-GPU")
// even though the system has no NVIDIA hardware. Real DGX Spark legitimately
// reports the same string (see #3510), distinguished by the firmware platform.
// Accept a name as NVIDIA when it either advertises the vendor explicitly or
// matches a known NVIDIA product family; otherwise the caller must cross-check
// against `detectNvidiaPlatform()` before trusting the nvidia-smi output.
const NVIDIA_GPU_NAME_PATTERN =
/\bNVIDIA\b|\b(GeForce|Tesla|Quadro|RTX|GTX|TITAN|H100|H200|A100|A40|A10|L40|L4|GB1\d|GB200|GB300|Grace[\s_-]+Hopper)\b/i;

// Names that have been observed both on legitimate NVIDIA unified-memory
// hardware (DGX Spark — #3510) and on Windows-on-ARM WSL2 d3d12 shims with no
// NVIDIA silicon. Even with an `NVIDIA ` vendor prefix the name alone is not
// sufficient — the caller must cross-check `detectNvidiaPlatform()`.
const NVIDIA_GPU_NAME_DENYLIST_PATTERN = /\bJMJWOA-Generic-GPU\b/i;

function isPlausibleNvidiaGpuName(name: string): boolean {
return (
!!name &&
!NVIDIA_GPU_NAME_DENYLIST_PATTERN.test(name) &&
NVIDIA_GPU_NAME_PATTERN.test(name)
);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

export interface NimModel {
name: string;
image: string;
Expand Down Expand Up @@ -277,23 +301,36 @@ export function detectGpu(): GpuDetection | null {
parsed.push({ name, memoryMB });
}
if (parsed.length > 0) {
const totalMemoryMB = parsed.reduce(
const platform = detectNvidiaPlatform();
// Reject WDDM/d3d12 placeholder names on hosts where firmware does not
// confirm an NVIDIA platform. Otherwise a Snapdragon X WSL2 nvidia-smi
// shim returning "JMJWOA-Generic-GPU" would be reported as a real
// NVIDIA GPU. Real DGX Spark uses the same placeholder but has
// firmware platform "spark", which keeps the #3510 path working.
const firmwareConfirmsNvidia =
platform === "spark" || platform === "station" || platform === "jetson";
const trusted = firmwareConfirmsNvidia
? parsed
: parsed.filter((p: ParsedGpu) => isPlausibleNvidiaGpuName(p.name));
if (trusted.length === 0) {
return null;
}
const totalMemoryMB = trusted.reduce(
(sum: number, p: ParsedGpu) => sum + p.memoryMB,
0,
);
const firstName = parsed[0].name;
const firstName = trusted[0].name;
// Only surface a single name when every GPU reports the same model;
// a mixed-GPU host would otherwise be misreported as `Nx <firstName>`.
const allSameName =
!!firstName && parsed.every((p: ParsedGpu) => p.name === firstName);
const platform = detectNvidiaPlatform();
!!firstName && trusted.every((p: ParsedGpu) => p.name === firstName);
return {
type: "nvidia",
...(allSameName ? { name: firstName } : {}),
gpus: parsed.map((p) => ({ name: p.name, memoryMB: p.memoryMB })),
count: parsed.length,
gpus: trusted.map((p) => ({ name: p.name, memoryMB: p.memoryMB })),
count: trusted.length,
totalMemoryMB,
perGpuMB: parsed[0].memoryMB,
perGpuMB: trusted[0].memoryMB,
nimCapable: canRunNimWithMemory(totalMemoryMB),
platform,
spark: platform === "spark",
Expand Down
Loading