more hardware + driver display improvements

This commit is contained in:
Egor 2025-09-26 03:15:38 -07:00
parent c2287b1d5c
commit 3ef91d1198
6 changed files with 334 additions and 143 deletions

View file

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

View file

@ -1,7 +1,13 @@
/* eslint-disable no-comments/disallowComments */ /* 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 { safeExecute } from '@/utils/node/logging';
import { getGPUData } from '@/utils/node/gpu'; import { getGPUData, isDiscreteBusAddress } from '@/utils/node/gpu';
import type { import type {
CPUCapabilities, CPUCapabilities,
GPUCapabilities, GPUCapabilities,
@ -12,10 +18,25 @@ import { execa } from 'execa';
import { formatDeviceName } from '@/utils/format'; import { formatDeviceName } from '@/utils/format';
import { platform } from 'process'; import { platform } from 'process';
const COMMON_EXEC_OPTIONS = {
timeout: 3000,
reject: false,
};
let cpuCapabilitiesCache: CPUCapabilities | null = null; let cpuCapabilitiesCache: CPUCapabilities | null = null;
let basicGPUInfoCache: BasicGPUInfo | null = null; let basicGPUInfoCache: BasicGPUInfo | null = null;
let gpuCapabilitiesCache: GPUCapabilities | null = null; let gpuCapabilitiesCache: GPUCapabilities | null = null;
let gpuMemoryInfoCache: GPUMemoryInfo[] | 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() { export async function detectCPU() {
if (cpuCapabilitiesCache) { if (cpuCapabilitiesCache) {
@ -23,7 +44,7 @@ export async function detectCPU() {
} }
const result = await safeExecute(async () => { 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[] = []; const devices: string[] = [];
if (cpu.brand) { if (cpu.brand) {
@ -61,37 +82,11 @@ export async function detectGPU() {
} }
const result = await safeExecute(async () => { const result = await safeExecute(async () => {
const graphics = await si.graphics(); if (platform === 'linux') {
return detectLinuxGPUViaVulkan();
let hasAMD = false; } else {
let hasNVIDIA = false; return detectGPUViaSI();
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);
}
} }
const basicInfo = {
hasAMD,
hasNVIDIA,
gpuInfo: gpuInfo.length > 0 ? gpuInfo : ['No GPU information available'],
};
basicGPUInfoCache = basicInfo;
return basicInfo;
}, 'GPU detection failed'); }, 'GPU detection failed');
const fallbackGPUInfo = { const fallbackGPUInfo = {
@ -104,6 +99,192 @@ export async function detectGPU() {
return basicGPUInfoCache; 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() { export async function detectGPUCapabilities() {
// WARNING: we're not worrying about the users that update their system // WARNING: we're not worrying about the users that update their system
// during runtime and not restart. Should we be though? // during runtime and not restart. Should we be though?
@ -125,10 +306,7 @@ export async function detectGPUCapabilities() {
async function detectCUDA() { async function detectCUDA() {
try { try {
const { stdout } = await execa('nvidia-smi', [], { const { stdout } = await execa('nvidia-smi', [], COMMON_EXEC_OPTIONS);
timeout: 5000,
reject: false,
});
if (stdout.trim()) { if (stdout.trim()) {
const errorPatterns = [ const errorPatterns = [
@ -159,11 +337,13 @@ async function detectCUDA() {
const driverMatch = stdout.match( const driverMatch = stdout.match(
/Driver Version:\s*(\d+\.\d+(?:\.\d+)?)/ /Driver Version:\s*(\d+\.\d+(?:\.\d+)?)/
); );
if (driverMatch) { if (driverMatch) {
driverVersion = driverMatch[1]; driverVersion = driverMatch[1];
} }
const gpuNameMatch = stdout.match(/\|\s+\d+\s+([^|]+)\s+On\s+\|/g); const gpuNameMatch = stdout.match(/\|\s+\d+\s+([^|]+)\s+On\s+\|/g);
if (gpuNameMatch) { if (gpuNameMatch) {
for (const match of gpuNameMatch) { for (const match of gpuNameMatch) {
const name = match const name = match
@ -193,10 +373,7 @@ async function detectCUDA() {
export async function detectROCm() { export async function detectROCm() {
try { try {
const rocminfoCommand = platform === 'win32' ? 'hipInfo' : 'rocminfo'; const rocminfoCommand = platform === 'win32' ? 'hipInfo' : 'rocminfo';
const { stdout } = await execa(rocminfoCommand, [], { const { stdout } = await execa(rocminfoCommand, [], COMMON_EXEC_OPTIONS);
timeout: 5000,
reject: false,
});
if (stdout.trim()) { if (stdout.trim()) {
const devices: string[] = []; const devices: string[] = [];
@ -258,10 +435,10 @@ export async function detectROCm() {
if (platform === 'linux' || platform === 'darwin') { if (platform === 'linux' || platform === 'darwin') {
try { try {
const { stdout: amdSmiOutput } = await execa('amd-smi', { const { stdout: amdSmiOutput } = await execa(
timeout: 3000, 'amd-smi',
reject: false, COMMON_EXEC_OPTIONS
}); );
if (amdSmiOutput.trim()) { if (amdSmiOutput.trim()) {
const match = const match =
@ -275,10 +452,11 @@ export async function detectROCm() {
} catch {} } catch {}
} else { } else {
try { try {
const { stdout: hipccOutput } = await execa('hipcc', ['--version'], { const { stdout: hipccOutput } = await execa(
timeout: 3000, 'hipcc',
reject: false, ['--version'],
}); COMMON_EXEC_OPTIONS
);
if (hipccOutput.trim()) { if (hipccOutput.trim()) {
const hipVersionMatch = hipccOutput.match( const hipVersionMatch = hipccOutput.match(
@ -301,16 +479,24 @@ export async function detectROCm() {
'-Command', '-Command',
`Get-CimInstance -ClassName Win32_VideoController | Where-Object { $_.Name -like '*AMD*' -or $_.Name -like '*Radeon*' } | Select-Object -First 1 -ExpandProperty DriverVersion`, `Get-CimInstance -ClassName Win32_VideoController | Where-Object { $_.Name -like '*AMD*' -or $_.Name -like '*Radeon*' } | Select-Object -First 1 -ExpandProperty DriverVersion`,
], ],
{ COMMON_EXEC_OPTIONS
timeout: 3000,
reject: false,
}
); );
if (driverOutput.trim()) { if (driverOutput.trim()) {
driverVersion = driverOutput.trim(); driverVersion = driverOutput.trim();
} }
} catch {} } 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 { return {
@ -329,48 +515,19 @@ export async function detectROCm() {
async function detectVulkan() { async function detectVulkan() {
try { try {
const { stdout } = await execa('vulkaninfo', ['--summary'], { const vulkanInfo = await getVulkanInfo();
timeout: 5000,
reject: false,
});
if (stdout.trim()) { const devices: string[] = [];
const devices: string[] = [];
const lines = stdout.split('\n');
for (const line of lines) { for (const gpu of vulkanInfo.discreteGPUs) {
if (line.includes('deviceName') && line.includes('=')) { devices.push(formatDeviceName(gpu.deviceName));
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,
};
} }
return { supported: false, devices: [], version: 'Unknown' }; return {
supported: devices.length > 0,
devices,
version: vulkanInfo.apiVersion || 'Unknown',
};
} catch { } catch {
return { supported: false, devices: [], version: 'Unknown' }; return { supported: false, devices: [], version: 'Unknown' };
} }
@ -430,10 +587,7 @@ function findDeviceNameInClInfo(lines: string[], startIndex: number) {
async function detectCLBlast() { async function detectCLBlast() {
try { try {
const { stdout } = await execa('clinfo', [], { const { stdout } = await execa('clinfo', [], COMMON_EXEC_OPTIONS);
timeout: 3000,
reject: false,
});
if (stdout.trim()) { if (stdout.trim()) {
const devices = parseClInfoOutput(stdout); const devices = parseClInfoOutput(stdout);
@ -485,7 +639,7 @@ export async function detectGPUMemory() {
} }
memoryInfo.push({ memoryInfo.push({
totalMemoryGB: vram, totalMemoryGB: vram?.toFixed(2) || null,
}); });
} }
@ -498,9 +652,9 @@ export async function detectGPUMemory() {
export const detectSystemMemory = async () => { export const detectSystemMemory = async () => {
try { 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 speed: number | undefined;
let type: string | undefined; let type: string | undefined;
@ -532,7 +686,7 @@ export const detectSystemMemory = async () => {
}; };
} catch { } catch {
return { return {
totalGB: Math.round((await si.mem()).total / 1024 ** 3), totalGB: ((await siMem()).total / 1024 ** 3).toFixed(2),
}; };
} }
}; };

View file

@ -1,4 +1,4 @@
import si from 'systeminformation'; import { mem, cpuTemperature, currentLoad } from 'systeminformation';
import { BrowserWindow } from 'electron'; import { BrowserWindow } from 'electron';
import { platform } from 'process'; import { platform } from 'process';
import { spawn } from 'child_process'; import { spawn } from 'child_process';
@ -95,14 +95,14 @@ export function stopMonitoring() {
async function collectAndSendCpuMetrics() { async function collectAndSendCpuMetrics() {
await tryExecute(async () => { await tryExecute(async () => {
const cpuData = await si.currentLoad(); const cpuData = await currentLoad();
const metrics: CpuMetrics = { const metrics: CpuMetrics = {
usage: Math.round(cpuData.currentLoad), usage: Math.round(cpuData.currentLoad),
}; };
if (platform === 'linux') { if (platform === 'linux') {
try { try {
const tempData = await si.cpuTemperature(); const tempData = await cpuTemperature();
metrics.temperature = metrics.temperature =
tempData.main && tempData.main > 0 tempData.main && tempData.main > 0
? Math.round(tempData.main) ? Math.round(tempData.main)
@ -118,7 +118,7 @@ async function collectAndSendCpuMetrics() {
async function collectAndSendMemoryMetrics() { async function collectAndSendMemoryMetrics() {
await tryExecute(async () => { await tryExecute(async () => {
const memData = await si.mem(); const memData = await mem();
const usedBytes = memData.active || memData.used; const usedBytes = memData.active || memData.used;
const totalBytes = memData.total; const totalBytes = memData.total;
const metrics: MemoryMetrics = { const metrics: MemoryMetrics = {

View file

@ -5,11 +5,11 @@ export interface CPUCapabilities {
} }
export interface GPUMemoryInfo { export interface GPUMemoryInfo {
totalMemoryGB: number | null; totalMemoryGB: string | null;
} }
export interface SystemMemoryInfo { export interface SystemMemoryInfo {
totalGB: number; totalGB: string;
speed?: number; speed?: number;
type?: string; type?: string;
} }

View file

@ -60,23 +60,40 @@ async function initializeLinuxGPUCache() {
(parseInt(memTotalData.trim(), 10) || 0) / (1024 * 1024 * 1024) (parseInt(memTotalData.trim(), 10) || 0) / (1024 * 1024 * 1024)
); );
if (memoryTotal > 0) { if (memoryTotal >= 1) {
let hwmonPath: string | undefined; let isDiscrete = false;
try { try {
const hwmonEntries = await readdir(`${devicePath}/hwmon`); const busAddress = await readFile(`${devicePath}/uevent`, 'utf8');
const hwmonEntry = hwmonEntries.find((e) => const pciMatch = busAddress.match(
e.startsWith('hwmon') /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 {} } catch {}
gpus.push({ if (isDiscrete) {
devicePath, let hwmonPath: string | undefined;
memoryTotal, try {
hwmonPath, 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 { } catch {
continue; continue;
@ -153,14 +170,14 @@ async function getWindowsGPUData() {
'powershell', 'powershell',
[ [
'-Command', '-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}$' }; $gpuKeys = Get-ChildItem 'HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}' | Where-Object { $_.PSChildName -match '^\\d{4}$' };
foreach($key in $gpuKeys) { foreach($key in $gpuKeys) {
$props = Get-ItemProperty $key.PSPath -ErrorAction SilentlyContinue; $props = Get-ItemProperty $key.PSPath -ErrorAction SilentlyContinue;
if($props.DriverDesc -and $props.'HardwareInformation.qwMemorySize' -and $activeGpus -contains $props.DriverDesc) { if($props.DriverDesc -and $props.'HardwareInformation.qwMemorySize' -and $activeGpus -contains $props.DriverDesc) {
$vramBytes = $props.'HardwareInformation.qwMemorySize'; $vramBytes = $props.'HardwareInformation.qwMemorySize';
$vramGB = [math]::Round($vramBytes/1GB, 2); $vramGB = [math]::Round($vramBytes/1GB, 2);
if($vramGB -gt 0.5) { if($vramGB -ge 1) {
Write-Output "$($props.DriverDesc)|$vramGB"; Write-Output "$($props.DriverDesc)|$vramGB";
} }
} }
@ -201,3 +218,26 @@ async function getWindowsGPUData() {
return []; 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;
}

View file

@ -66,14 +66,14 @@ export const createDriverItems = (hardwareInfo: HardwareInfo) => {
items.push({ items.push({
label: 'CUDA', label: 'CUDA',
value: gpuCapabilities.cuda.version value: gpuCapabilities.cuda.version
? `v${gpuCapabilities.cuda.version}` ? gpuCapabilities.cuda.version
: 'Available', : 'Available',
}); });
if (gpuCapabilities.cuda.driverVersion) { if (gpuCapabilities.cuda.driverVersion) {
items.push({ items.push({
label: 'NVIDIA Driver', label: 'NVIDIA Driver',
value: `v${gpuCapabilities.cuda.driverVersion}`, value: gpuCapabilities.cuda.driverVersion,
}); });
} }
} }
@ -82,14 +82,14 @@ export const createDriverItems = (hardwareInfo: HardwareInfo) => {
items.push({ items.push({
label: 'ROCm', label: 'ROCm',
value: gpuCapabilities.rocm.version value: gpuCapabilities.rocm.version
? `v${gpuCapabilities.rocm.version}` ? gpuCapabilities.rocm.version
: 'Available', : 'Available',
}); });
if (gpuCapabilities.rocm.driverVersion) { if (gpuCapabilities.rocm.driverVersion) {
items.push({ items.push({
label: 'AMD Driver', label: 'AMD Driver',
value: `v${gpuCapabilities.rocm.driverVersion}`, value: gpuCapabilities.rocm.driverVersion,
}); });
} }
} }
@ -98,7 +98,7 @@ export const createDriverItems = (hardwareInfo: HardwareInfo) => {
items.push({ items.push({
label: 'Vulkan', label: 'Vulkan',
value: gpuCapabilities.vulkan.version value: gpuCapabilities.vulkan.version
? `v${gpuCapabilities.vulkan.version}` ? gpuCapabilities.vulkan.version
: 'Available', : 'Available',
}); });
} else { } else {
@ -112,7 +112,7 @@ export const createDriverItems = (hardwareInfo: HardwareInfo) => {
items.push({ items.push({
label: 'CLBlast', label: 'CLBlast',
value: gpuCapabilities.clblast.version value: gpuCapabilities.clblast.version
? `v${gpuCapabilities.clblast.version}` ? gpuCapabilities.clblast.version
: 'Available', : 'Available',
}); });
} else { } else {
@ -135,18 +135,17 @@ export const createHardwareItems = (hardwareInfo: HardwareInfo) => [
}, },
{ {
label: 'RAM', label: 'RAM',
value: value: hardwareInfo.systemMemory
hardwareInfo.systemMemory && hardwareInfo.systemMemory.totalGB > 0 ? `${hardwareInfo.systemMemory.totalGB} GB${
? `${hardwareInfo.systemMemory.totalGB.toFixed(1)} GB${ hardwareInfo.systemMemory.type
hardwareInfo.systemMemory.type ? ` ${hardwareInfo.systemMemory.type}`
? ` ${hardwareInfo.systemMemory.type}` : ''
: '' }${
}${ hardwareInfo.systemMemory.speed
hardwareInfo.systemMemory.speed ? ` @ ${hardwareInfo.systemMemory.speed} MHz`
? ` @ ${hardwareInfo.systemMemory.speed} MHz` : ''
: '' }`
}` : 'Detecting...',
: 'Detecting...',
}, },
...(hardwareInfo.gpu.gpuInfo.length > 0 ...(hardwareInfo.gpu.gpuInfo.length > 0
? hardwareInfo.gpu.gpuInfo.map((gpu, index) => ({ ? hardwareInfo.gpu.gpuInfo.map((gpu, index) => ({
@ -157,9 +156,7 @@ export const createHardwareItems = (hardwareInfo: HardwareInfo) => [
...(hardwareInfo.gpuMemory && hardwareInfo.gpuMemory.length > 0 ...(hardwareInfo.gpuMemory && hardwareInfo.gpuMemory.length > 0
? hardwareInfo.gpuMemory.map((mem, index) => ({ ? hardwareInfo.gpuMemory.map((mem, index) => ({
label: `VRAM ${index > 0 ? index + 1 : ''}`.trim(), label: `VRAM ${index > 0 ? index + 1 : ''}`.trim(),
value: mem.totalMemoryGB value: mem.totalMemoryGB ? `${mem.totalMemoryGB} GB` : 'Unknown',
? `${mem.totalMemoryGB.toFixed(1)} GB`
: 'Unknown',
})) }))
: []), : []),
]; ];