mirror of
https://github.com/lone-cloud/gerbil
synced 2026-06-03 19:54:44 -07:00
more hardware + driver display improvements
This commit is contained in:
parent
c2287b1d5c
commit
3ef91d1198
6 changed files with 334 additions and 143 deletions
|
|
@ -109,15 +109,15 @@ const checkVramWarnings = async (backend: string): Promise<Warning[]> => {
|
|||
if (gpuMemoryInfo) {
|
||||
const lowVramThreshold = 8;
|
||||
const validGpus = gpuMemoryInfo.filter(
|
||||
(gpu) => typeof gpu.totalMemoryGB === 'number'
|
||||
(gpu) => gpu.totalMemoryGB !== null && gpu.totalMemoryGB !== ''
|
||||
);
|
||||
const lowVramGpus = validGpus.filter(
|
||||
(gpu) => gpu.totalMemoryGB! < lowVramThreshold
|
||||
(gpu) => parseFloat(gpu.totalMemoryGB!) < lowVramThreshold
|
||||
);
|
||||
|
||||
if (validGpus.length > 0 && lowVramGpus.length === validGpus.length) {
|
||||
const memoryDetails = lowVramGpus
|
||||
.map((gpu) => `${gpu.totalMemoryGB!.toFixed(1)}GB`)
|
||||
.map((gpu) => `${parseFloat(gpu.totalMemoryGB!).toFixed(1)}GB`)
|
||||
.join(', ');
|
||||
|
||||
warnings.push({
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
/* eslint-disable no-comments/disallowComments */
|
||||
import si from 'systeminformation';
|
||||
import {
|
||||
cpu as siCpu,
|
||||
cpuFlags,
|
||||
graphics as siGraphics,
|
||||
mem as siMem,
|
||||
memLayout as siMemLayout,
|
||||
} from 'systeminformation';
|
||||
import { safeExecute } from '@/utils/node/logging';
|
||||
import { getGPUData } from '@/utils/node/gpu';
|
||||
import { getGPUData, isDiscreteBusAddress } from '@/utils/node/gpu';
|
||||
import type {
|
||||
CPUCapabilities,
|
||||
GPUCapabilities,
|
||||
|
|
@ -12,10 +18,25 @@ import { execa } from 'execa';
|
|||
import { formatDeviceName } from '@/utils/format';
|
||||
import { platform } from 'process';
|
||||
|
||||
const COMMON_EXEC_OPTIONS = {
|
||||
timeout: 3000,
|
||||
reject: false,
|
||||
};
|
||||
|
||||
let cpuCapabilitiesCache: CPUCapabilities | null = null;
|
||||
let basicGPUInfoCache: BasicGPUInfo | null = null;
|
||||
let gpuCapabilitiesCache: GPUCapabilities | null = null;
|
||||
let gpuMemoryInfoCache: GPUMemoryInfo[] | null = null;
|
||||
let vulkanInfoCache: {
|
||||
discreteGPUs: {
|
||||
deviceName: string;
|
||||
driverInfo?: string;
|
||||
apiVersion?: string;
|
||||
hasAMD: boolean;
|
||||
hasNVIDIA: boolean;
|
||||
}[];
|
||||
apiVersion?: string;
|
||||
} | null = null;
|
||||
|
||||
export async function detectCPU() {
|
||||
if (cpuCapabilitiesCache) {
|
||||
|
|
@ -23,7 +44,7 @@ export async function detectCPU() {
|
|||
}
|
||||
|
||||
const result = await safeExecute(async () => {
|
||||
const [cpu, flags] = await Promise.all([si.cpu(), si.cpuFlags()]);
|
||||
const [cpu, flags] = await Promise.all([siCpu(), cpuFlags()]);
|
||||
|
||||
const devices: string[] = [];
|
||||
if (cpu.brand) {
|
||||
|
|
@ -61,37 +82,11 @@ export async function detectGPU() {
|
|||
}
|
||||
|
||||
const result = await safeExecute(async () => {
|
||||
const graphics = await si.graphics();
|
||||
|
||||
let hasAMD = false;
|
||||
let hasNVIDIA = false;
|
||||
const gpuInfo: string[] = [];
|
||||
|
||||
for (const controller of graphics.controllers) {
|
||||
// Check vendor for AMD
|
||||
if (
|
||||
controller.vendor?.toLowerCase().includes('amd') ||
|
||||
controller.vendor?.toLowerCase().includes('ati')
|
||||
) {
|
||||
hasAMD = true;
|
||||
}
|
||||
|
||||
if (controller.vendor?.toLowerCase().includes('nvidia')) {
|
||||
hasNVIDIA = true;
|
||||
}
|
||||
|
||||
if (controller.model) {
|
||||
gpuInfo.push(controller.model);
|
||||
}
|
||||
if (platform === 'linux') {
|
||||
return detectLinuxGPUViaVulkan();
|
||||
} else {
|
||||
return detectGPUViaSI();
|
||||
}
|
||||
|
||||
const basicInfo = {
|
||||
hasAMD,
|
||||
hasNVIDIA,
|
||||
gpuInfo: gpuInfo.length > 0 ? gpuInfo : ['No GPU information available'],
|
||||
};
|
||||
basicGPUInfoCache = basicInfo;
|
||||
return basicInfo;
|
||||
}, 'GPU detection failed');
|
||||
|
||||
const fallbackGPUInfo = {
|
||||
|
|
@ -104,6 +99,192 @@ export async function detectGPU() {
|
|||
return basicGPUInfoCache;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
async function getVulkanInfo() {
|
||||
if (vulkanInfoCache) {
|
||||
return vulkanInfoCache;
|
||||
}
|
||||
|
||||
try {
|
||||
const { stdout } = await execa(
|
||||
'vulkaninfo',
|
||||
['--summary'],
|
||||
COMMON_EXEC_OPTIONS
|
||||
);
|
||||
|
||||
const discreteGPUs: {
|
||||
deviceName: string;
|
||||
driverInfo?: string;
|
||||
apiVersion?: string;
|
||||
hasAMD: boolean;
|
||||
hasNVIDIA: boolean;
|
||||
}[] = [];
|
||||
let globalApiVersion: string | undefined;
|
||||
|
||||
if (stdout.trim()) {
|
||||
const lines = stdout.split('\n');
|
||||
let foundDiscreteGPU = false;
|
||||
let currentGPU: (typeof discreteGPUs)[0] | null = null;
|
||||
|
||||
for (const line of lines) {
|
||||
if (
|
||||
!globalApiVersion &&
|
||||
line.includes('apiVersion') &&
|
||||
line.includes('=')
|
||||
) {
|
||||
const match = line.match(/=\s*(\d+\.\d+(?:\.\d+)?)/);
|
||||
if (match) {
|
||||
globalApiVersion = match[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (line.includes('PHYSICAL_DEVICE_TYPE_DISCRETE_GPU')) {
|
||||
foundDiscreteGPU = true;
|
||||
currentGPU = {
|
||||
deviceName: '',
|
||||
hasAMD: false,
|
||||
hasNVIDIA: false,
|
||||
};
|
||||
} else if (
|
||||
foundDiscreteGPU &&
|
||||
currentGPU &&
|
||||
line.includes('deviceName') &&
|
||||
line.includes('=')
|
||||
) {
|
||||
const parts = line.split('=');
|
||||
if (parts.length >= 2) {
|
||||
const name = parts[1]?.trim();
|
||||
if (name) {
|
||||
currentGPU.deviceName = name;
|
||||
currentGPU.hasAMD =
|
||||
name.toLowerCase().includes('amd') ||
|
||||
name.toLowerCase().includes('radeon');
|
||||
currentGPU.hasNVIDIA =
|
||||
name.toLowerCase().includes('nvidia') ||
|
||||
name.toLowerCase().includes('geforce') ||
|
||||
name.toLowerCase().includes('rtx') ||
|
||||
name.toLowerCase().includes('gtx');
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
foundDiscreteGPU &&
|
||||
currentGPU &&
|
||||
line.includes('driverInfo')
|
||||
) {
|
||||
const mesaMatch = line.match(/Mesa\s+(.+)/);
|
||||
if (mesaMatch) {
|
||||
currentGPU.driverInfo = `Mesa ${mesaMatch[1].trim()}`;
|
||||
}
|
||||
} else if (
|
||||
foundDiscreteGPU &&
|
||||
currentGPU &&
|
||||
line.includes('apiVersion') &&
|
||||
line.includes('=')
|
||||
) {
|
||||
const match = line.match(/=\s*(\d+\.\d+(?:\.\d+)?)/);
|
||||
if (match) {
|
||||
currentGPU.apiVersion = match[1];
|
||||
if (!globalApiVersion) {
|
||||
globalApiVersion = match[1];
|
||||
}
|
||||
}
|
||||
} else if (foundDiscreteGPU && currentGPU && line.includes('GPU')) {
|
||||
if (currentGPU.deviceName) {
|
||||
discreteGPUs.push(currentGPU);
|
||||
}
|
||||
foundDiscreteGPU = false;
|
||||
currentGPU = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundDiscreteGPU && currentGPU && currentGPU.deviceName) {
|
||||
discreteGPUs.push(currentGPU);
|
||||
}
|
||||
}
|
||||
|
||||
vulkanInfoCache = {
|
||||
discreteGPUs,
|
||||
apiVersion: globalApiVersion,
|
||||
};
|
||||
|
||||
return vulkanInfoCache;
|
||||
} catch {
|
||||
vulkanInfoCache = {
|
||||
discreteGPUs: [],
|
||||
};
|
||||
return vulkanInfoCache;
|
||||
}
|
||||
}
|
||||
|
||||
async function detectLinuxGPUViaVulkan() {
|
||||
try {
|
||||
const vulkanInfo = await getVulkanInfo();
|
||||
|
||||
let hasAMD = false;
|
||||
let hasNVIDIA = false;
|
||||
const gpuInfo: string[] = [];
|
||||
|
||||
for (const gpu of vulkanInfo.discreteGPUs) {
|
||||
gpuInfo.push(formatDeviceName(gpu.deviceName));
|
||||
|
||||
if (gpu.hasAMD) {
|
||||
hasAMD = true;
|
||||
}
|
||||
if (gpu.hasNVIDIA) {
|
||||
hasNVIDIA = true;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
hasAMD,
|
||||
hasNVIDIA,
|
||||
gpuInfo: gpuInfo.length > 0 ? gpuInfo : ['No GPU information available'],
|
||||
};
|
||||
} catch {
|
||||
return {
|
||||
hasAMD: false,
|
||||
hasNVIDIA: false,
|
||||
gpuInfo: ['GPU detection failed'],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function detectGPUViaSI() {
|
||||
const graphics = await siGraphics();
|
||||
|
||||
let hasAMD = false;
|
||||
let hasNVIDIA = false;
|
||||
const gpuInfo: string[] = [];
|
||||
|
||||
const discreteControllers = graphics.controllers.filter(
|
||||
(controller) =>
|
||||
controller.busAddress && isDiscreteBusAddress(controller.busAddress)
|
||||
);
|
||||
|
||||
for (const controller of discreteControllers) {
|
||||
if (
|
||||
controller.vendor?.toLowerCase().includes('amd') ||
|
||||
controller.vendor?.toLowerCase().includes('ati')
|
||||
) {
|
||||
hasAMD = true;
|
||||
}
|
||||
|
||||
if (controller.vendor?.toLowerCase().includes('nvidia')) {
|
||||
hasNVIDIA = true;
|
||||
}
|
||||
|
||||
if (controller.model) {
|
||||
gpuInfo.push(controller.model);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
hasAMD,
|
||||
hasNVIDIA,
|
||||
gpuInfo: gpuInfo.length > 0 ? gpuInfo : ['No GPU information available'],
|
||||
};
|
||||
}
|
||||
|
||||
export async function detectGPUCapabilities() {
|
||||
// WARNING: we're not worrying about the users that update their system
|
||||
// during runtime and not restart. Should we be though?
|
||||
|
|
@ -125,10 +306,7 @@ export async function detectGPUCapabilities() {
|
|||
|
||||
async function detectCUDA() {
|
||||
try {
|
||||
const { stdout } = await execa('nvidia-smi', [], {
|
||||
timeout: 5000,
|
||||
reject: false,
|
||||
});
|
||||
const { stdout } = await execa('nvidia-smi', [], COMMON_EXEC_OPTIONS);
|
||||
|
||||
if (stdout.trim()) {
|
||||
const errorPatterns = [
|
||||
|
|
@ -159,11 +337,13 @@ async function detectCUDA() {
|
|||
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
|
||||
|
|
@ -193,10 +373,7 @@ async function detectCUDA() {
|
|||
export async function detectROCm() {
|
||||
try {
|
||||
const rocminfoCommand = platform === 'win32' ? 'hipInfo' : 'rocminfo';
|
||||
const { stdout } = await execa(rocminfoCommand, [], {
|
||||
timeout: 5000,
|
||||
reject: false,
|
||||
});
|
||||
const { stdout } = await execa(rocminfoCommand, [], COMMON_EXEC_OPTIONS);
|
||||
|
||||
if (stdout.trim()) {
|
||||
const devices: string[] = [];
|
||||
|
|
@ -258,10 +435,10 @@ export async function detectROCm() {
|
|||
|
||||
if (platform === 'linux' || platform === 'darwin') {
|
||||
try {
|
||||
const { stdout: amdSmiOutput } = await execa('amd-smi', {
|
||||
timeout: 3000,
|
||||
reject: false,
|
||||
});
|
||||
const { stdout: amdSmiOutput } = await execa(
|
||||
'amd-smi',
|
||||
COMMON_EXEC_OPTIONS
|
||||
);
|
||||
|
||||
if (amdSmiOutput.trim()) {
|
||||
const match =
|
||||
|
|
@ -275,10 +452,11 @@ export async function detectROCm() {
|
|||
} catch {}
|
||||
} else {
|
||||
try {
|
||||
const { stdout: hipccOutput } = await execa('hipcc', ['--version'], {
|
||||
timeout: 3000,
|
||||
reject: false,
|
||||
});
|
||||
const { stdout: hipccOutput } = await execa(
|
||||
'hipcc',
|
||||
['--version'],
|
||||
COMMON_EXEC_OPTIONS
|
||||
);
|
||||
|
||||
if (hipccOutput.trim()) {
|
||||
const hipVersionMatch = hipccOutput.match(
|
||||
|
|
@ -301,16 +479,24 @@ export async function detectROCm() {
|
|||
'-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,
|
||||
}
|
||||
COMMON_EXEC_OPTIONS
|
||||
);
|
||||
|
||||
if (driverOutput.trim()) {
|
||||
driverVersion = driverOutput.trim();
|
||||
}
|
||||
} catch {}
|
||||
} else if (platform === 'linux') {
|
||||
try {
|
||||
const vulkanInfo = await getVulkanInfo();
|
||||
|
||||
for (const gpu of vulkanInfo.discreteGPUs) {
|
||||
if (gpu.driverInfo) {
|
||||
driverVersion = gpu.driverInfo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
@ -329,48 +515,19 @@ export async function detectROCm() {
|
|||
|
||||
async function detectVulkan() {
|
||||
try {
|
||||
const { stdout } = await execa('vulkaninfo', ['--summary'], {
|
||||
timeout: 5000,
|
||||
reject: false,
|
||||
});
|
||||
const vulkanInfo = await getVulkanInfo();
|
||||
|
||||
if (stdout.trim()) {
|
||||
const devices: string[] = [];
|
||||
const lines = stdout.split('\n');
|
||||
const devices: string[] = [];
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.includes('deviceName') && line.includes('=')) {
|
||||
const parts = line.split('=');
|
||||
if (parts.length >= 2) {
|
||||
const name = parts[1]?.trim();
|
||||
if (name) {
|
||||
devices.push(formatDeviceName(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let version = 'Unknown';
|
||||
try {
|
||||
const apiVersionLine = lines.find(
|
||||
(line) => line.includes('apiVersion') && line.includes('=')
|
||||
);
|
||||
if (apiVersionLine) {
|
||||
const match = apiVersionLine.match(/=\s*(\d+\.\d+(?:\.\d+)?)/);
|
||||
if (match) {
|
||||
version = match[1];
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
|
||||
return {
|
||||
supported: devices.length > 0,
|
||||
devices,
|
||||
version,
|
||||
};
|
||||
for (const gpu of vulkanInfo.discreteGPUs) {
|
||||
devices.push(formatDeviceName(gpu.deviceName));
|
||||
}
|
||||
|
||||
return { supported: false, devices: [], version: 'Unknown' };
|
||||
return {
|
||||
supported: devices.length > 0,
|
||||
devices,
|
||||
version: vulkanInfo.apiVersion || 'Unknown',
|
||||
};
|
||||
} catch {
|
||||
return { supported: false, devices: [], version: 'Unknown' };
|
||||
}
|
||||
|
|
@ -430,10 +587,7 @@ function findDeviceNameInClInfo(lines: string[], startIndex: number) {
|
|||
|
||||
async function detectCLBlast() {
|
||||
try {
|
||||
const { stdout } = await execa('clinfo', [], {
|
||||
timeout: 3000,
|
||||
reject: false,
|
||||
});
|
||||
const { stdout } = await execa('clinfo', [], COMMON_EXEC_OPTIONS);
|
||||
|
||||
if (stdout.trim()) {
|
||||
const devices = parseClInfoOutput(stdout);
|
||||
|
|
@ -485,7 +639,7 @@ export async function detectGPUMemory() {
|
|||
}
|
||||
|
||||
memoryInfo.push({
|
||||
totalMemoryGB: vram,
|
||||
totalMemoryGB: vram?.toFixed(2) || null,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -498,9 +652,9 @@ export async function detectGPUMemory() {
|
|||
|
||||
export const detectSystemMemory = async () => {
|
||||
try {
|
||||
const [memInfo, memLayout] = await Promise.all([si.mem(), si.memLayout()]);
|
||||
const [memInfo, memLayout] = await Promise.all([siMem(), siMemLayout()]);
|
||||
|
||||
const totalGB = Math.round(memInfo.total / 1024 ** 3);
|
||||
const totalGB = (memInfo.total / 1024 ** 3).toFixed(2);
|
||||
|
||||
let speed: number | undefined;
|
||||
let type: string | undefined;
|
||||
|
|
@ -532,7 +686,7 @@ export const detectSystemMemory = async () => {
|
|||
};
|
||||
} catch {
|
||||
return {
|
||||
totalGB: Math.round((await si.mem()).total / 1024 ** 3),
|
||||
totalGB: ((await siMem()).total / 1024 ** 3).toFixed(2),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import si from 'systeminformation';
|
||||
import { mem, cpuTemperature, currentLoad } from 'systeminformation';
|
||||
import { BrowserWindow } from 'electron';
|
||||
import { platform } from 'process';
|
||||
import { spawn } from 'child_process';
|
||||
|
|
@ -95,14 +95,14 @@ export function stopMonitoring() {
|
|||
|
||||
async function collectAndSendCpuMetrics() {
|
||||
await tryExecute(async () => {
|
||||
const cpuData = await si.currentLoad();
|
||||
const cpuData = await currentLoad();
|
||||
const metrics: CpuMetrics = {
|
||||
usage: Math.round(cpuData.currentLoad),
|
||||
};
|
||||
|
||||
if (platform === 'linux') {
|
||||
try {
|
||||
const tempData = await si.cpuTemperature();
|
||||
const tempData = await cpuTemperature();
|
||||
metrics.temperature =
|
||||
tempData.main && tempData.main > 0
|
||||
? Math.round(tempData.main)
|
||||
|
|
@ -118,7 +118,7 @@ async function collectAndSendCpuMetrics() {
|
|||
|
||||
async function collectAndSendMemoryMetrics() {
|
||||
await tryExecute(async () => {
|
||||
const memData = await si.mem();
|
||||
const memData = await mem();
|
||||
const usedBytes = memData.active || memData.used;
|
||||
const totalBytes = memData.total;
|
||||
const metrics: MemoryMetrics = {
|
||||
|
|
|
|||
4
src/types/hardware.d.ts
vendored
4
src/types/hardware.d.ts
vendored
|
|
@ -5,11 +5,11 @@ export interface CPUCapabilities {
|
|||
}
|
||||
|
||||
export interface GPUMemoryInfo {
|
||||
totalMemoryGB: number | null;
|
||||
totalMemoryGB: string | null;
|
||||
}
|
||||
|
||||
export interface SystemMemoryInfo {
|
||||
totalGB: number;
|
||||
totalGB: string;
|
||||
speed?: number;
|
||||
type?: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,23 +60,40 @@ async function initializeLinuxGPUCache() {
|
|||
(parseInt(memTotalData.trim(), 10) || 0) / (1024 * 1024 * 1024)
|
||||
);
|
||||
|
||||
if (memoryTotal > 0) {
|
||||
let hwmonPath: string | undefined;
|
||||
if (memoryTotal >= 1) {
|
||||
let isDiscrete = false;
|
||||
try {
|
||||
const hwmonEntries = await readdir(`${devicePath}/hwmon`);
|
||||
const hwmonEntry = hwmonEntries.find((e) =>
|
||||
e.startsWith('hwmon')
|
||||
const busAddress = await readFile(`${devicePath}/uevent`, 'utf8');
|
||||
const pciMatch = busAddress.match(
|
||||
/PCI_SLOT_NAME=([0-9a-f]{4}:[0-9a-f]{2}:[0-9a-f]{2}\.[0-9a-f])/i
|
||||
);
|
||||
if (hwmonEntry) {
|
||||
hwmonPath = `${devicePath}/hwmon/${hwmonEntry}`;
|
||||
|
||||
if (pciMatch) {
|
||||
const fullAddress = pciMatch[1];
|
||||
const busAddress = fullAddress.substring(5);
|
||||
|
||||
isDiscrete = isDiscreteBusAddress(busAddress);
|
||||
}
|
||||
} catch {}
|
||||
|
||||
gpus.push({
|
||||
devicePath,
|
||||
memoryTotal,
|
||||
hwmonPath,
|
||||
});
|
||||
if (isDiscrete) {
|
||||
let hwmonPath: string | undefined;
|
||||
try {
|
||||
const hwmonEntries = await readdir(`${devicePath}/hwmon`);
|
||||
const hwmonEntry = hwmonEntries.find((e) =>
|
||||
e.startsWith('hwmon')
|
||||
);
|
||||
if (hwmonEntry) {
|
||||
hwmonPath = `${devicePath}/hwmon/${hwmonEntry}`;
|
||||
}
|
||||
} catch {}
|
||||
|
||||
gpus.push({
|
||||
devicePath,
|
||||
memoryTotal,
|
||||
hwmonPath,
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
continue;
|
||||
|
|
@ -153,14 +170,14 @@ async function getWindowsGPUData() {
|
|||
'powershell',
|
||||
[
|
||||
'-Command',
|
||||
`$activeGpus = Get-CimInstance -ClassName Win32_VideoController | Where-Object { $_.Status -eq 'OK' } | Select-Object -ExpandProperty Name;
|
||||
`$activeGpus = Get-CimInstance -ClassName Win32_VideoController | Where-Object { $_.Status -eq 'OK' -and $_.Name -notlike '*Intel*UHD*' -and $_.Name -notlike '*Intel*Iris*' -and $_.Name -notlike '*Basic Display*' } | 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) {
|
||||
if($vramGB -ge 1) {
|
||||
Write-Output "$($props.DriverDesc)|$vramGB";
|
||||
}
|
||||
}
|
||||
|
|
@ -201,3 +218,26 @@ async function getWindowsGPUData() {
|
|||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export function isDiscreteBusAddress(busAddress?: string) {
|
||||
if (!busAddress) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!/^[0-9a-f]{2}:\d{2}\.\d$/i.test(busAddress)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const busNumber = parseInt(busAddress.substring(0, 2), 16);
|
||||
const deviceNumber = parseInt(busAddress.substring(3, 5), 16);
|
||||
|
||||
if (busNumber === 0 && deviceNumber === 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (busNumber > 0 && busNumber <= 15) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,14 +66,14 @@ export const createDriverItems = (hardwareInfo: HardwareInfo) => {
|
|||
items.push({
|
||||
label: 'CUDA',
|
||||
value: gpuCapabilities.cuda.version
|
||||
? `v${gpuCapabilities.cuda.version}`
|
||||
? gpuCapabilities.cuda.version
|
||||
: 'Available',
|
||||
});
|
||||
|
||||
if (gpuCapabilities.cuda.driverVersion) {
|
||||
items.push({
|
||||
label: 'NVIDIA Driver',
|
||||
value: `v${gpuCapabilities.cuda.driverVersion}`,
|
||||
value: gpuCapabilities.cuda.driverVersion,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -82,14 +82,14 @@ export const createDriverItems = (hardwareInfo: HardwareInfo) => {
|
|||
items.push({
|
||||
label: 'ROCm',
|
||||
value: gpuCapabilities.rocm.version
|
||||
? `v${gpuCapabilities.rocm.version}`
|
||||
? gpuCapabilities.rocm.version
|
||||
: 'Available',
|
||||
});
|
||||
|
||||
if (gpuCapabilities.rocm.driverVersion) {
|
||||
items.push({
|
||||
label: 'AMD Driver',
|
||||
value: `v${gpuCapabilities.rocm.driverVersion}`,
|
||||
value: gpuCapabilities.rocm.driverVersion,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -98,7 +98,7 @@ export const createDriverItems = (hardwareInfo: HardwareInfo) => {
|
|||
items.push({
|
||||
label: 'Vulkan',
|
||||
value: gpuCapabilities.vulkan.version
|
||||
? `v${gpuCapabilities.vulkan.version}`
|
||||
? gpuCapabilities.vulkan.version
|
||||
: 'Available',
|
||||
});
|
||||
} else {
|
||||
|
|
@ -112,7 +112,7 @@ export const createDriverItems = (hardwareInfo: HardwareInfo) => {
|
|||
items.push({
|
||||
label: 'CLBlast',
|
||||
value: gpuCapabilities.clblast.version
|
||||
? `v${gpuCapabilities.clblast.version}`
|
||||
? gpuCapabilities.clblast.version
|
||||
: 'Available',
|
||||
});
|
||||
} else {
|
||||
|
|
@ -135,18 +135,17 @@ export const createHardwareItems = (hardwareInfo: HardwareInfo) => [
|
|||
},
|
||||
{
|
||||
label: 'RAM',
|
||||
value:
|
||||
hardwareInfo.systemMemory && hardwareInfo.systemMemory.totalGB > 0
|
||||
? `${hardwareInfo.systemMemory.totalGB.toFixed(1)} GB${
|
||||
hardwareInfo.systemMemory.type
|
||||
? ` ${hardwareInfo.systemMemory.type}`
|
||||
: ''
|
||||
}${
|
||||
hardwareInfo.systemMemory.speed
|
||||
? ` @ ${hardwareInfo.systemMemory.speed} MHz`
|
||||
: ''
|
||||
}`
|
||||
: 'Detecting...',
|
||||
value: hardwareInfo.systemMemory
|
||||
? `${hardwareInfo.systemMemory.totalGB} GB${
|
||||
hardwareInfo.systemMemory.type
|
||||
? ` ${hardwareInfo.systemMemory.type}`
|
||||
: ''
|
||||
}${
|
||||
hardwareInfo.systemMemory.speed
|
||||
? ` @ ${hardwareInfo.systemMemory.speed} MHz`
|
||||
: ''
|
||||
}`
|
||||
: 'Detecting...',
|
||||
},
|
||||
...(hardwareInfo.gpu.gpuInfo.length > 0
|
||||
? hardwareInfo.gpu.gpuInfo.map((gpu, index) => ({
|
||||
|
|
@ -157,9 +156,7 @@ export const createHardwareItems = (hardwareInfo: HardwareInfo) => [
|
|||
...(hardwareInfo.gpuMemory && hardwareInfo.gpuMemory.length > 0
|
||||
? hardwareInfo.gpuMemory.map((mem, index) => ({
|
||||
label: `VRAM ${index > 0 ? index + 1 : ''}`.trim(),
|
||||
value: mem.totalMemoryGB
|
||||
? `${mem.totalMemoryGB.toFixed(1)} GB`
|
||||
: 'Unknown',
|
||||
value: mem.totalMemoryGB ? `${mem.totalMemoryGB} GB` : 'Unknown',
|
||||
}))
|
||||
: []),
|
||||
];
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue