refactor to pass less redundant data from ipc

This commit is contained in:
Egor 2025-09-26 14:09:41 -07:00
parent 48338b9904
commit caaf2427d3
6 changed files with 53 additions and 89 deletions

View file

@ -45,8 +45,8 @@ const checkModelWarnings = (
}; };
interface GpuCapabilities { interface GpuCapabilities {
cuda: { supported: boolean }; cuda: { devices: readonly string[] };
rocm: { supported: boolean }; rocm: { devices: readonly string[] };
} }
interface GpuInfo { interface GpuInfo {
@ -63,7 +63,7 @@ const checkGpuWarnings = async (
if ( if (
backendSupport.cuda && backendSupport.cuda &&
!gpuCapabilities.cuda.supported && gpuCapabilities.cuda.devices.length === 0 &&
gpuInfo.hasNVIDIA gpuInfo.hasNVIDIA
) { ) {
warnings.push({ warnings.push({
@ -75,7 +75,7 @@ const checkGpuWarnings = async (
if ( if (
backendSupport.rocm && backendSupport.rocm &&
!gpuCapabilities.rocm.supported && gpuCapabilities.rocm.devices.length === 0 &&
gpuInfo.hasAMD gpuInfo.hasAMD
) { ) {
const platform = await window.electronAPI.kobold.getPlatform(); const platform = await window.electronAPI.kobold.getPlatform();

View file

@ -15,11 +15,7 @@ import type {
import { execa } from 'execa'; import { execa } from 'execa';
import { formatDeviceName } from '@/utils/format'; import { formatDeviceName } from '@/utils/format';
import { platform } from 'process'; import { platform } from 'process';
import { import { getVulkanInfo, detectLinuxGPUViaVulkan } from '@/utils/node/vulkan';
getVulkanInfo,
detectLinuxGPUViaVulkan,
detectVulkan,
} from '@/utils/node/vulkan';
const COMMON_EXEC_OPTIONS = { const COMMON_EXEC_OPTIONS = {
timeout: 3000, timeout: 3000,
@ -104,6 +100,25 @@ export async function detectGPUCapabilities() {
return gpuCapabilitiesCache; return gpuCapabilitiesCache;
} }
async function detectVulkan() {
try {
const vulkanInfo = await getVulkanInfo();
const devices: string[] = [];
for (const gpu of vulkanInfo.discreteGPUs) {
devices.push(formatDeviceName(gpu.deviceName));
}
return {
devices,
version: vulkanInfo.apiVersion || 'Unknown',
};
} catch {
return { devices: [], version: 'Unknown' };
}
}
async function detectCUDA() { async function detectCUDA() {
try { try {
const { stdout } = await execa('nvidia-smi', [], COMMON_EXEC_OPTIONS); const { stdout } = await execa('nvidia-smi', [], COMMON_EXEC_OPTIONS);
@ -122,7 +137,7 @@ async function detectCUDA() {
); );
if (hasError) { if (hasError) {
return { supported: false, devices: [] } as const; return { devices: [] } as const;
} }
const devices: string[] = []; const devices: string[] = [];
@ -156,16 +171,15 @@ async function detectCUDA() {
} }
return { return {
supported: devices.length > 0 || !!cudaVersion,
devices, devices,
version: cudaVersion, version: cudaVersion,
driverVersion, driverVersion,
} as const; } as const;
} }
return { supported: false, devices: [] } as const; return { devices: [] } as const;
} catch { } catch {
return { supported: false, devices: [] }; return { devices: [] };
} }
} }
@ -300,16 +314,15 @@ export async function detectROCm() {
} }
return { return {
supported: devices.length > 0,
devices, devices,
version, version,
driverVersion, driverVersion,
}; };
} }
return { supported: false, devices: [] }; return { devices: [] };
} catch { } catch {
return { supported: false, devices: [] }; return { devices: [] };
} }
} }
@ -322,19 +335,19 @@ function parseClInfoOutput(output: string) {
for (let i = 0; i < lines.length; i++) { for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim(); const line = lines[i].trim();
if (line.includes('Platform Name:')) { if (line.includes('Platform Name')) {
currentPlatform = line.split('Platform Name:')[1]?.trim() || ''; currentPlatform = line.split('Platform Name')[1]?.trim() || '';
continue; continue;
} }
if (line.includes('Device Type:') && line.includes('GPU')) { if (line.includes('Device Type') && line.includes('GPU')) {
const deviceName = findDeviceNameInClInfo(lines, i); const deviceName = findDeviceNameInClInfo(lines, i);
const computeUnits = findComputeUnitsInClInfo(lines, i); const computeUnits = findComputeUnitsInClInfo(lines, i);
if (deviceName && currentPlatform) { if (deviceName && currentPlatform) {
devices.push({ devices.push({
name: formatDeviceName(deviceName), name: formatDeviceName(deviceName),
isIntegrated: !isDiscreteGPU(deviceName, computeUnits), isIntegrated: !isDiscreteGPU(computeUnits),
}); });
} }
} }
@ -350,6 +363,9 @@ function findDeviceNameInClInfo(lines: string[], startIndex: number) {
j++ j++
) { ) {
const nextLine = lines[j].trim(); const nextLine = lines[j].trim();
if (nextLine.includes('Device Board Name (AMD)')) {
return nextLine.split('Device Board Name (AMD)')[1]?.trim() || '';
}
if (nextLine.includes('Board name:')) { if (nextLine.includes('Board name:')) {
return nextLine.split('Board name:')[1]?.trim() || ''; return nextLine.split('Board name:')[1]?.trim() || '';
} }
@ -361,6 +377,9 @@ function findDeviceNameInClInfo(lines: string[], startIndex: number) {
j++ j++
) { ) {
const nextLine = lines[j].trim(); const nextLine = lines[j].trim();
if (nextLine.startsWith('Device Name:')) {
return nextLine.split('Device Name:')[1]?.trim() || '';
}
if (nextLine.startsWith('Name:')) { if (nextLine.startsWith('Name:')) {
return nextLine.split('Name:')[1]?.trim() || ''; return nextLine.split('Name:')[1]?.trim() || '';
} }
@ -376,30 +395,15 @@ function findComputeUnitsInClInfo(lines: string[], startIndex: number) {
j++ j++
) { ) {
const nextLine = lines[j].trim(); const nextLine = lines[j].trim();
if (nextLine.includes('Max compute units:')) { if (nextLine.includes('Max compute units')) {
const units = nextLine.split('Max compute units:')[1]?.trim(); const units = nextLine.split('Max compute units')[1]?.trim();
return units ? parseInt(units, 10) : 0; return units ? parseInt(units, 10) : 0;
} }
} }
return 0; return 0;
} }
function isDiscreteGPU(deviceName: string, computeUnits: number) { const isDiscreteGPU = (computeUnits: number) => computeUnits > 12;
const lowerName = deviceName.toLowerCase();
if (
lowerName.includes('radeon(tm) graphics') ||
lowerName.includes('intel')
) {
return false;
}
if (computeUnits <= 2) {
return false;
}
return true;
}
async function detectCLBlast() { async function detectCLBlast() {
try { try {
@ -408,33 +412,17 @@ async function detectCLBlast() {
if (stdout.trim()) { if (stdout.trim()) {
const devices = parseClInfoOutput(stdout); const devices = parseClInfoOutput(stdout);
let version = 'Unknown'; const version = 'Available';
try {
const versionLine = stdout
.split('\n')
.find(
(line) =>
line.includes('OpenCL C version') ||
line.includes('CL_DEVICE_OPENCL_C_VERSION')
);
if (versionLine) {
const match = versionLine.match(/OpenCL C\s+(\d+\.\d+)/);
if (match) {
version = match[1];
}
}
} catch {}
return { return {
supported: devices.length > 0,
devices, devices,
version, version,
}; };
} }
return { supported: false, devices: [], version: 'Unknown' }; return { devices: [], version: 'Unknown' };
} catch { } catch {
return { supported: false, devices: [], version: 'Unknown' }; return { devices: [], version: 'Unknown' };
} }
} }

View file

@ -106,7 +106,7 @@ export async function getAvailableBackends(includeDisabled = false) {
const backends: BackendOption[] = []; const backends: BackendOption[] = [];
if (backendSupport.cuda) { if (backendSupport.cuda) {
const isSupported = hardwareCapabilities.cuda.supported; const isSupported = hardwareCapabilities.cuda.devices.length > 0;
if (isSupported || includeDisabled) { if (isSupported || includeDisabled) {
backends.push({ backends.push({
value: 'cuda', value: 'cuda',
@ -118,7 +118,7 @@ export async function getAvailableBackends(includeDisabled = false) {
} }
if (backendSupport.rocm) { if (backendSupport.rocm) {
const isSupported = hardwareCapabilities.rocm.supported; const isSupported = hardwareCapabilities.rocm.devices.length > 0;
if (isSupported || includeDisabled) { if (isSupported || includeDisabled) {
backends.push({ backends.push({
value: 'rocm', value: 'rocm',
@ -130,7 +130,7 @@ export async function getAvailableBackends(includeDisabled = false) {
} }
if (backendSupport.vulkan) { if (backendSupport.vulkan) {
const isSupported = hardwareCapabilities.vulkan.supported; const isSupported = hardwareCapabilities.vulkan.devices.length > 0;
if (isSupported || includeDisabled) { if (isSupported || includeDisabled) {
backends.push({ backends.push({
value: 'vulkan', value: 'vulkan',
@ -142,7 +142,7 @@ export async function getAvailableBackends(includeDisabled = false) {
} }
if (backendSupport.clblast) { if (backendSupport.clblast) {
const isSupported = hardwareCapabilities.clblast.supported; const isSupported = hardwareCapabilities.clblast.devices.length > 0;
if (isSupported || includeDisabled) { if (isSupported || includeDisabled) {
backends.push({ backends.push({
value: 'clblast', value: 'clblast',

View file

@ -14,24 +14,20 @@ export interface SystemMemoryInfo {
export interface GPUCapabilities { export interface GPUCapabilities {
cuda: { cuda: {
readonly supported: boolean;
readonly devices: readonly string[]; readonly devices: readonly string[];
readonly version?: string; readonly version?: string;
readonly driverVersion?: string; readonly driverVersion?: string;
}; };
rocm: { rocm: {
readonly supported: boolean;
readonly devices: readonly string[]; readonly devices: readonly string[];
readonly version?: string; readonly version?: string;
readonly driverVersion?: string; readonly driverVersion?: string;
}; };
vulkan: { vulkan: {
readonly supported: boolean;
readonly devices: readonly string[]; readonly devices: readonly string[];
readonly version?: string; readonly version?: string;
}; };
clblast: { clblast: {
readonly supported: boolean;
readonly devices: readonly CLBlastDevice[]; readonly devices: readonly CLBlastDevice[];
readonly version?: string; readonly version?: string;
}; };

View file

@ -161,23 +161,3 @@ export async function detectLinuxGPUViaVulkan() {
}; };
} }
} }
export async function detectVulkan() {
try {
const vulkanInfo = await getVulkanInfo();
const devices: string[] = [];
for (const gpu of vulkanInfo.discreteGPUs) {
devices.push(formatDeviceName(gpu.deviceName));
}
return {
supported: devices.length > 0,
devices,
version: vulkanInfo.apiVersion || 'Unknown',
};
} catch {
return { supported: false, devices: [], version: 'Unknown' };
}
}

View file

@ -62,7 +62,7 @@ export const createDriverItems = (hardwareInfo: HardwareInfo) => {
]; ];
} }
if (gpuCapabilities.cuda.supported) { if (gpuCapabilities.cuda.devices.length > 0) {
items.push({ items.push({
label: 'CUDA', label: 'CUDA',
value: gpuCapabilities.cuda.version value: gpuCapabilities.cuda.version
@ -78,7 +78,7 @@ export const createDriverItems = (hardwareInfo: HardwareInfo) => {
} }
} }
if (gpuCapabilities.rocm.supported) { if (gpuCapabilities.rocm.devices.length > 0) {
items.push({ items.push({
label: 'ROCm', label: 'ROCm',
value: gpuCapabilities.rocm.version value: gpuCapabilities.rocm.version
@ -94,7 +94,7 @@ export const createDriverItems = (hardwareInfo: HardwareInfo) => {
} }
} }
if (gpuCapabilities.vulkan.supported) { if (gpuCapabilities.vulkan.devices.length > 0) {
items.push({ items.push({
label: 'Vulkan', label: 'Vulkan',
value: gpuCapabilities.vulkan.version value: gpuCapabilities.vulkan.version
@ -108,7 +108,7 @@ export const createDriverItems = (hardwareInfo: HardwareInfo) => {
}); });
} }
if (gpuCapabilities.clblast.supported) { if (gpuCapabilities.clblast.devices.length > 0) {
items.push({ items.push({
label: 'CLBlast', label: 'CLBlast',
value: gpuCapabilities.clblast.version value: gpuCapabilities.clblast.version