windows vram display in about, better rocm display on windows, amd/nvidia driver display

This commit is contained in:
Egor 2025-09-26 00:28:42 -07:00
parent 61b730c3f7
commit c2287b1d5c
5 changed files with 173 additions and 44 deletions

View file

@ -108,13 +108,14 @@ const checkVramWarnings = async (backend: string): Promise<Warning[]> => {
if (gpuMemoryInfo) {
const lowVramThreshold = 8;
const lowVramGpus = gpuMemoryInfo.filter(
(gpu) =>
typeof gpu.totalMemoryGB === 'number' &&
gpu.totalMemoryGB < lowVramThreshold
const validGpus = gpuMemoryInfo.filter(
(gpu) => typeof gpu.totalMemoryGB === 'number'
);
const lowVramGpus = validGpus.filter(
(gpu) => gpu.totalMemoryGB! < lowVramThreshold
);
if (lowVramGpus.length > 0) {
if (validGpus.length > 0 && lowVramGpus.length === validGpus.length) {
const memoryDetails = lowVramGpus
.map((gpu) => `${gpu.totalMemoryGB!.toFixed(1)}GB`)
.join(', ');

View file

@ -28,7 +28,7 @@ export async function detectCPU() {
const devices: string[] = [];
if (cpu.brand) {
devices.push(
`${formatDeviceName(cpu.brand)} (${cpu.physicalCores} cores, ${cpu.speed} GHz)`
`${formatDeviceName(cpu.brand)} (${cpu.cores} cores) @ ${cpu.speed} GHz`
);
}
@ -125,17 +125,12 @@ export async function detectGPUCapabilities() {
async function detectCUDA() {
try {
const { stdout } = await execa(
'nvidia-smi',
['--query-gpu=name,driver_version', '--format=csv,noheader,nounits'],
{
timeout: 5000,
reject: false,
}
);
const { stdout } = await execa('nvidia-smi', [], {
timeout: 5000,
reject: false,
});
if (stdout.trim()) {
// Check for error messages that indicate nvidia-smi failed
const errorPatterns = [
'NVIDIA-SMI has failed',
'No devices found',
@ -152,24 +147,39 @@ async function detectCUDA() {
return { supported: false, devices: [] } as const;
}
const lines = stdout.trim().split('\n');
const devices: string[] = [];
let version: string | undefined;
let cudaVersion: string | undefined;
let driverVersion: string | undefined;
for (const line of lines) {
const parts = line.split(',');
const rawName = parts[0]?.trim() || 'Unknown NVIDIA GPU';
devices.push(formatDeviceName(rawName));
const cudaMatch = stdout.match(/CUDA Version:\s*(\d+\.\d+)/);
if (cudaMatch) {
cudaVersion = cudaMatch[1];
}
if (!version && parts[1]?.trim()) {
version = parts[1].trim();
const driverMatch = stdout.match(
/Driver Version:\s*(\d+\.\d+(?:\.\d+)?)/
);
if (driverMatch) {
driverVersion = driverMatch[1];
}
const gpuNameMatch = stdout.match(/\|\s+\d+\s+([^|]+)\s+On\s+\|/g);
if (gpuNameMatch) {
for (const match of gpuNameMatch) {
const name = match
.replace(/\|\s+\d+\s+([^|]+)\s+On\s+\|/, '$1')
.trim();
if (name) {
devices.push(formatDeviceName(name));
}
}
}
return {
supported: devices.length > 0,
supported: devices.length > 0 || !!cudaVersion,
devices,
version,
version: cudaVersion,
driverVersion,
} as const;
}
@ -245,27 +255,69 @@ export async function detectROCm() {
}
let version: string | undefined;
try {
const { stdout: amdSmiOutput } = await execa('amd-smi', {
timeout: 3000,
reject: false,
});
if (amdSmiOutput.trim()) {
const match =
amdSmiOutput.match(/ROCm version:\s*(\d+\.\d+\.\d+)/i) ||
amdSmiOutput.match(/version\s*(\d+\.\d+\.\d+)/i) ||
amdSmiOutput.match(/(\d+\.\d+\.\d+)/);
if (match) {
version = match[1];
if (platform === 'linux' || platform === 'darwin') {
try {
const { stdout: amdSmiOutput } = await execa('amd-smi', {
timeout: 3000,
reject: false,
});
if (amdSmiOutput.trim()) {
const match =
amdSmiOutput.match(/ROCm version:\s*(\d+\.\d+\.\d+)/i) ||
amdSmiOutput.match(/version\s*(\d+\.\d+\.\d+)/i) ||
amdSmiOutput.match(/(\d+\.\d+\.\d+)/);
if (match) {
version = match[1];
}
}
}
} catch {}
} catch {}
} else {
try {
const { stdout: hipccOutput } = await execa('hipcc', ['--version'], {
timeout: 3000,
reject: false,
});
if (hipccOutput.trim()) {
const hipVersionMatch = hipccOutput.match(
/HIP version:\s*(\d+\.\d+(?:\.\d+)?)/i
);
if (hipVersionMatch) {
version = hipVersionMatch[1];
}
}
} catch {}
}
let driverVersion: string | undefined;
if (platform === 'win32') {
try {
const { stdout: driverOutput } = await execa(
'powershell',
[
'-Command',
`Get-CimInstance -ClassName Win32_VideoController | Where-Object { $_.Name -like '*AMD*' -or $_.Name -like '*Radeon*' } | Select-Object -First 1 -ExpandProperty DriverVersion`,
],
{
timeout: 3000,
reject: false,
}
);
if (driverOutput.trim()) {
driverVersion = driverOutput.trim();
}
} catch {}
}
return {
supported: devices.length > 0,
devices,
version,
driverVersion,
};
}
@ -422,7 +474,7 @@ export async function detectGPUMemory() {
}
const result = await safeExecute(async () => {
const gpuData = await getGPUData();
const gpuData = await getGPUData(true);
const memoryInfo: GPUMemoryInfo[] = [];
for (const gpu of gpuData) {

View file

@ -19,11 +19,13 @@ export interface GPUCapabilities {
readonly supported: boolean;
readonly devices: readonly string[];
readonly version?: string;
readonly driverVersion?: string;
};
rocm: {
readonly supported: boolean;
readonly devices: readonly string[];
readonly version?: string;
readonly driverVersion?: string;
};
vulkan: {
readonly supported: boolean;

View file

@ -1,6 +1,7 @@
import { readFile, readdir } from 'fs/promises';
import { join } from 'path';
import { platform } from 'process';
import { execa } from 'execa';
interface CachedGPUInfo {
devicePath: string;
@ -19,9 +20,11 @@ let linuxGpuCache: CachedGPUInfo[] | null = null;
let linuxCachePromise: Promise<CachedGPUInfo[]> | null = null;
export async function getGPUData() {
export async function getGPUData(forNonMetrics = false) {
if (platform === 'linux') {
return getLinuxGPUData();
} else if (platform === 'win32' && forNonMetrics) {
return getWindowsGPUData();
} else {
return [];
}
@ -143,3 +146,58 @@ async function getLinuxGPUData() {
return [];
}
}
async function getWindowsGPUData() {
try {
const { stdout } = await execa(
'powershell',
[
'-Command',
`$activeGpus = Get-CimInstance -ClassName Win32_VideoController | Where-Object { $_.Status -eq 'OK' } | Select-Object -ExpandProperty Name;
$gpuKeys = Get-ChildItem 'HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}' | Where-Object { $_.PSChildName -match '^\\d{4}$' };
foreach($key in $gpuKeys) {
$props = Get-ItemProperty $key.PSPath -ErrorAction SilentlyContinue;
if($props.DriverDesc -and $props.'HardwareInformation.qwMemorySize' -and $activeGpus -contains $props.DriverDesc) {
$vramBytes = $props.'HardwareInformation.qwMemorySize';
$vramGB = [math]::Round($vramBytes/1GB, 2);
if($vramGB -gt 0.5) {
Write-Output "$($props.DriverDesc)|$vramGB";
}
}
}`,
],
{
timeout: 10000,
reject: false,
}
);
if (!stdout.trim()) {
return [];
}
const gpus: GPUData[] = [];
const lines = stdout.trim().split('\n');
const seenVram = new Set<number>();
for (const line of lines) {
const parts = line.trim().split('|');
if (parts.length === 2) {
const vramGB = parseFloat(parts[1]);
if (vramGB > 0 && !seenVram.has(vramGB)) {
seenVram.add(vramGB);
gpus.push({
usage: 0,
memoryUsed: 0,
memoryTotal: vramGB,
temperature: undefined,
});
}
}
}
return gpus;
} catch {
return [];
}
}

View file

@ -32,9 +32,11 @@ export const createSoftwareItems = (versionInfo: SystemVersionInfo) => [
{ label: 'Electron', value: versionInfo.electronVersion },
{
label: 'Node.js',
value: versionInfo.nodeJsSystemVersion
? `${versionInfo.nodeVersion} (System: ${versionInfo.nodeJsSystemVersion})`
: versionInfo.nodeVersion,
value:
versionInfo.nodeJsSystemVersion &&
versionInfo.nodeJsSystemVersion !== versionInfo.nodeVersion
? `${versionInfo.nodeVersion} (system: ${versionInfo.nodeJsSystemVersion})`
: versionInfo.nodeVersion,
},
{ label: 'Chromium', value: versionInfo.chromeVersion },
{ label: 'V8', value: versionInfo.v8Version },
@ -67,6 +69,13 @@ export const createDriverItems = (hardwareInfo: HardwareInfo) => {
? `v${gpuCapabilities.cuda.version}`
: 'Available',
});
if (gpuCapabilities.cuda.driverVersion) {
items.push({
label: 'NVIDIA Driver',
value: `v${gpuCapabilities.cuda.driverVersion}`,
});
}
}
if (gpuCapabilities.rocm.supported) {
@ -76,6 +85,13 @@ export const createDriverItems = (hardwareInfo: HardwareInfo) => {
? `v${gpuCapabilities.rocm.version}`
: 'Available',
});
if (gpuCapabilities.rocm.driverVersion) {
items.push({
label: 'AMD Driver',
value: `v${gpuCapabilities.rocm.driverVersion}`,
});
}
}
if (gpuCapabilities.vulkan.supported) {