mirror of
https://github.com/lone-cloud/gerbil
synced 2026-06-03 19:54:44 -07:00
windows vram display in about, better rocm display on windows, amd/nvidia driver display
This commit is contained in:
parent
ee710c4ac1
commit
d628896699
5 changed files with 173 additions and 44 deletions
|
|
@ -108,13 +108,14 @@ const checkVramWarnings = async (backend: string): Promise<Warning[]> => {
|
||||||
|
|
||||||
if (gpuMemoryInfo) {
|
if (gpuMemoryInfo) {
|
||||||
const lowVramThreshold = 8;
|
const lowVramThreshold = 8;
|
||||||
const lowVramGpus = gpuMemoryInfo.filter(
|
const validGpus = gpuMemoryInfo.filter(
|
||||||
(gpu) =>
|
(gpu) => typeof gpu.totalMemoryGB === 'number'
|
||||||
typeof gpu.totalMemoryGB === 'number' &&
|
);
|
||||||
gpu.totalMemoryGB < lowVramThreshold
|
const lowVramGpus = validGpus.filter(
|
||||||
|
(gpu) => gpu.totalMemoryGB! < lowVramThreshold
|
||||||
);
|
);
|
||||||
|
|
||||||
if (lowVramGpus.length > 0) {
|
if (validGpus.length > 0 && lowVramGpus.length === validGpus.length) {
|
||||||
const memoryDetails = lowVramGpus
|
const memoryDetails = lowVramGpus
|
||||||
.map((gpu) => `${gpu.totalMemoryGB!.toFixed(1)}GB`)
|
.map((gpu) => `${gpu.totalMemoryGB!.toFixed(1)}GB`)
|
||||||
.join(', ');
|
.join(', ');
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ export async function detectCPU() {
|
||||||
const devices: string[] = [];
|
const devices: string[] = [];
|
||||||
if (cpu.brand) {
|
if (cpu.brand) {
|
||||||
devices.push(
|
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() {
|
async function detectCUDA() {
|
||||||
try {
|
try {
|
||||||
const { stdout } = await execa(
|
const { stdout } = await execa('nvidia-smi', [], {
|
||||||
'nvidia-smi',
|
timeout: 5000,
|
||||||
['--query-gpu=name,driver_version', '--format=csv,noheader,nounits'],
|
reject: false,
|
||||||
{
|
});
|
||||||
timeout: 5000,
|
|
||||||
reject: false,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (stdout.trim()) {
|
if (stdout.trim()) {
|
||||||
// Check for error messages that indicate nvidia-smi failed
|
|
||||||
const errorPatterns = [
|
const errorPatterns = [
|
||||||
'NVIDIA-SMI has failed',
|
'NVIDIA-SMI has failed',
|
||||||
'No devices found',
|
'No devices found',
|
||||||
|
|
@ -152,24 +147,39 @@ async function detectCUDA() {
|
||||||
return { supported: false, devices: [] } as const;
|
return { supported: false, devices: [] } as const;
|
||||||
}
|
}
|
||||||
|
|
||||||
const lines = stdout.trim().split('\n');
|
|
||||||
const devices: string[] = [];
|
const devices: string[] = [];
|
||||||
let version: string | undefined;
|
let cudaVersion: string | undefined;
|
||||||
|
let driverVersion: string | undefined;
|
||||||
|
|
||||||
for (const line of lines) {
|
const cudaMatch = stdout.match(/CUDA Version:\s*(\d+\.\d+)/);
|
||||||
const parts = line.split(',');
|
if (cudaMatch) {
|
||||||
const rawName = parts[0]?.trim() || 'Unknown NVIDIA GPU';
|
cudaVersion = cudaMatch[1];
|
||||||
devices.push(formatDeviceName(rawName));
|
}
|
||||||
|
|
||||||
if (!version && parts[1]?.trim()) {
|
const driverMatch = stdout.match(
|
||||||
version = parts[1].trim();
|
/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 {
|
return {
|
||||||
supported: devices.length > 0,
|
supported: devices.length > 0 || !!cudaVersion,
|
||||||
devices,
|
devices,
|
||||||
version,
|
version: cudaVersion,
|
||||||
|
driverVersion,
|
||||||
} as const;
|
} as const;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -245,27 +255,69 @@ export async function detectROCm() {
|
||||||
}
|
}
|
||||||
|
|
||||||
let version: string | undefined;
|
let version: string | undefined;
|
||||||
try {
|
|
||||||
const { stdout: amdSmiOutput } = await execa('amd-smi', {
|
|
||||||
timeout: 3000,
|
|
||||||
reject: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (amdSmiOutput.trim()) {
|
if (platform === 'linux' || platform === 'darwin') {
|
||||||
const match =
|
try {
|
||||||
amdSmiOutput.match(/ROCm version:\s*(\d+\.\d+\.\d+)/i) ||
|
const { stdout: amdSmiOutput } = await execa('amd-smi', {
|
||||||
amdSmiOutput.match(/version\s*(\d+\.\d+\.\d+)/i) ||
|
timeout: 3000,
|
||||||
amdSmiOutput.match(/(\d+\.\d+\.\d+)/);
|
reject: false,
|
||||||
if (match) {
|
});
|
||||||
version = match[1];
|
|
||||||
|
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 {
|
return {
|
||||||
supported: devices.length > 0,
|
supported: devices.length > 0,
|
||||||
devices,
|
devices,
|
||||||
version,
|
version,
|
||||||
|
driverVersion,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -422,7 +474,7 @@ export async function detectGPUMemory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await safeExecute(async () => {
|
const result = await safeExecute(async () => {
|
||||||
const gpuData = await getGPUData();
|
const gpuData = await getGPUData(true);
|
||||||
const memoryInfo: GPUMemoryInfo[] = [];
|
const memoryInfo: GPUMemoryInfo[] = [];
|
||||||
|
|
||||||
for (const gpu of gpuData) {
|
for (const gpu of gpuData) {
|
||||||
|
|
|
||||||
2
src/types/hardware.d.ts
vendored
2
src/types/hardware.d.ts
vendored
|
|
@ -19,11 +19,13 @@ export interface GPUCapabilities {
|
||||||
readonly supported: boolean;
|
readonly supported: boolean;
|
||||||
readonly devices: readonly string[];
|
readonly devices: readonly string[];
|
||||||
readonly version?: string;
|
readonly version?: string;
|
||||||
|
readonly driverVersion?: string;
|
||||||
};
|
};
|
||||||
rocm: {
|
rocm: {
|
||||||
readonly supported: boolean;
|
readonly supported: boolean;
|
||||||
readonly devices: readonly string[];
|
readonly devices: readonly string[];
|
||||||
readonly version?: string;
|
readonly version?: string;
|
||||||
|
readonly driverVersion?: string;
|
||||||
};
|
};
|
||||||
vulkan: {
|
vulkan: {
|
||||||
readonly supported: boolean;
|
readonly supported: boolean;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { readFile, readdir } from 'fs/promises';
|
import { readFile, readdir } from 'fs/promises';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { platform } from 'process';
|
import { platform } from 'process';
|
||||||
|
import { execa } from 'execa';
|
||||||
|
|
||||||
interface CachedGPUInfo {
|
interface CachedGPUInfo {
|
||||||
devicePath: string;
|
devicePath: string;
|
||||||
|
|
@ -19,9 +20,11 @@ let linuxGpuCache: CachedGPUInfo[] | null = null;
|
||||||
|
|
||||||
let linuxCachePromise: Promise<CachedGPUInfo[]> | null = null;
|
let linuxCachePromise: Promise<CachedGPUInfo[]> | null = null;
|
||||||
|
|
||||||
export async function getGPUData() {
|
export async function getGPUData(forNonMetrics = false) {
|
||||||
if (platform === 'linux') {
|
if (platform === 'linux') {
|
||||||
return getLinuxGPUData();
|
return getLinuxGPUData();
|
||||||
|
} else if (platform === 'win32' && forNonMetrics) {
|
||||||
|
return getWindowsGPUData();
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
@ -143,3 +146,58 @@ async function getLinuxGPUData() {
|
||||||
return [];
|
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 [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,11 @@ export const createSoftwareItems = (versionInfo: SystemVersionInfo) => [
|
||||||
{ label: 'Electron', value: versionInfo.electronVersion },
|
{ label: 'Electron', value: versionInfo.electronVersion },
|
||||||
{
|
{
|
||||||
label: 'Node.js',
|
label: 'Node.js',
|
||||||
value: versionInfo.nodeJsSystemVersion
|
value:
|
||||||
? `${versionInfo.nodeVersion} (System: ${versionInfo.nodeJsSystemVersion})`
|
versionInfo.nodeJsSystemVersion &&
|
||||||
: versionInfo.nodeVersion,
|
versionInfo.nodeJsSystemVersion !== versionInfo.nodeVersion
|
||||||
|
? `${versionInfo.nodeVersion} (system: ${versionInfo.nodeJsSystemVersion})`
|
||||||
|
: versionInfo.nodeVersion,
|
||||||
},
|
},
|
||||||
{ label: 'Chromium', value: versionInfo.chromeVersion },
|
{ label: 'Chromium', value: versionInfo.chromeVersion },
|
||||||
{ label: 'V8', value: versionInfo.v8Version },
|
{ label: 'V8', value: versionInfo.v8Version },
|
||||||
|
|
@ -67,6 +69,13 @@ export const createDriverItems = (hardwareInfo: HardwareInfo) => {
|
||||||
? `v${gpuCapabilities.cuda.version}`
|
? `v${gpuCapabilities.cuda.version}`
|
||||||
: 'Available',
|
: 'Available',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (gpuCapabilities.cuda.driverVersion) {
|
||||||
|
items.push({
|
||||||
|
label: 'NVIDIA Driver',
|
||||||
|
value: `v${gpuCapabilities.cuda.driverVersion}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gpuCapabilities.rocm.supported) {
|
if (gpuCapabilities.rocm.supported) {
|
||||||
|
|
@ -76,6 +85,13 @@ export const createDriverItems = (hardwareInfo: HardwareInfo) => {
|
||||||
? `v${gpuCapabilities.rocm.version}`
|
? `v${gpuCapabilities.rocm.version}`
|
||||||
: 'Available',
|
: 'Available',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (gpuCapabilities.rocm.driverVersion) {
|
||||||
|
items.push({
|
||||||
|
label: 'AMD Driver',
|
||||||
|
value: `v${gpuCapabilities.rocm.driverVersion}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gpuCapabilities.vulkan.supported) {
|
if (gpuCapabilities.vulkan.supported) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue