mirror of
https://github.com/lone-cloud/gerbil
synced 2026-06-03 19:54:44 -07:00
better discrete device filtering
This commit is contained in:
parent
ddf42c41db
commit
b2533659c2
9 changed files with 195 additions and 80 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
import { Text, Group, Badge, Box } from '@mantine/core';
|
import { Text, Group, Badge, Box } from '@mantine/core';
|
||||||
import type { BackendOption } from '@/types';
|
import type { BackendOption } from '@/types';
|
||||||
|
import { GPUDevice } from '@/types/hardware';
|
||||||
|
|
||||||
type BackendSelectItemProps = Omit<BackendOption, 'value'>;
|
type BackendSelectItemProps = Omit<BackendOption, 'value'>;
|
||||||
|
|
||||||
|
|
@ -8,9 +9,7 @@ export const BackendSelectItem = ({
|
||||||
devices,
|
devices,
|
||||||
disabled = false,
|
disabled = false,
|
||||||
}: BackendSelectItemProps) => {
|
}: BackendSelectItemProps) => {
|
||||||
const renderDeviceName = (
|
const renderDeviceName = (device: string | GPUDevice) => {
|
||||||
device: string | { name: string; isIntegrated: boolean }
|
|
||||||
) => {
|
|
||||||
const deviceName = typeof device === 'string' ? device : device.name;
|
const deviceName = typeof device === 'string' ? device : device.name;
|
||||||
return deviceName.length > 25
|
return deviceName.length > 25
|
||||||
? `${deviceName.slice(0, 25)}...`
|
? `${deviceName.slice(0, 25)}...`
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ export const GpuDeviceSelector = ({
|
||||||
|
|
||||||
const getDiscreteDeviceCount = () => {
|
const getDiscreteDeviceCount = () => {
|
||||||
if (!selectedBackend?.devices) return 0;
|
if (!selectedBackend?.devices) return 0;
|
||||||
if (backend === 'clblast') {
|
if (backend === 'clblast' || backend === 'vulkan' || backend === 'rocm') {
|
||||||
return selectedBackend.devices.filter(
|
return selectedBackend.devices.filter(
|
||||||
(device) => typeof device === 'string' || !device.isIntegrated
|
(device) => typeof device === 'string' || !device.isIntegrated
|
||||||
).length;
|
).length;
|
||||||
|
|
@ -66,6 +66,25 @@ export const GpuDeviceSelector = ({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (backend === 'vulkan' || backend === 'rocm') {
|
||||||
|
const discreteDeviceOptions = selectedBackend.devices
|
||||||
|
.map((device, index) => {
|
||||||
|
if (typeof device === 'object' && device.isIntegrated) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const deviceName = typeof device === 'string' ? device : device.name;
|
||||||
|
return {
|
||||||
|
value: index.toString(),
|
||||||
|
label: `GPU ${index}: ${deviceName}`,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(
|
||||||
|
(option): option is NonNullable<typeof option> => option !== null
|
||||||
|
);
|
||||||
|
|
||||||
|
return [{ value: 'all', label: 'All GPUs' }, ...discreteDeviceOptions];
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{ value: 'all', label: 'All GPUs' },
|
{ value: 'all', label: 'All GPUs' },
|
||||||
...selectedBackend.devices.map((device, index) => {
|
...selectedBackend.devices.map((device, index) => {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { useEffect, useState, useCallback, useMemo } from 'react';
|
import { useEffect, useState, useCallback, useMemo } from 'react';
|
||||||
import type { BackendOption, BackendSupport } from '@/types';
|
import type { BackendOption, BackendSupport } from '@/types';
|
||||||
|
import { CPUCapabilities, GPUDevice } from '@/types/hardware';
|
||||||
|
|
||||||
export interface Warning {
|
export interface Warning {
|
||||||
type: 'warning' | 'info';
|
type: 'warning' | 'info';
|
||||||
|
|
@ -46,7 +47,9 @@ const checkModelWarnings = (
|
||||||
|
|
||||||
interface GpuCapabilities {
|
interface GpuCapabilities {
|
||||||
cuda: { devices: readonly string[] };
|
cuda: { devices: readonly string[] };
|
||||||
rocm: { devices: readonly string[] };
|
rocm: { devices: readonly GPUDevice[] };
|
||||||
|
vulkan: { devices: readonly GPUDevice[] };
|
||||||
|
clblast: { devices: readonly GPUDevice[] };
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GpuInfo {
|
interface GpuInfo {
|
||||||
|
|
@ -155,11 +158,9 @@ const checkCpuWarnings = (
|
||||||
|
|
||||||
const checkBackendWarnings = async (params?: {
|
const checkBackendWarnings = async (params?: {
|
||||||
backend: string;
|
backend: string;
|
||||||
cpuCapabilities: {
|
cpuCapabilities: CPUCapabilities | null;
|
||||||
devices: string[];
|
|
||||||
} | null;
|
|
||||||
availableBackends: BackendOption[];
|
availableBackends: BackendOption[];
|
||||||
}): Promise<Warning[]> => {
|
}) => {
|
||||||
const warnings: Warning[] = [];
|
const warnings: Warning[] = [];
|
||||||
|
|
||||||
const [backendSupport, gpuCapabilities, gpuInfo] = await Promise.all([
|
const [backendSupport, gpuCapabilities, gpuInfo] = await Promise.all([
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,12 @@ import type {
|
||||||
GPUCapabilities,
|
GPUCapabilities,
|
||||||
BasicGPUInfo,
|
BasicGPUInfo,
|
||||||
GPUMemoryInfo,
|
GPUMemoryInfo,
|
||||||
|
GPUDevice,
|
||||||
} from '@/types/hardware';
|
} from '@/types/hardware';
|
||||||
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 { getVulkanInfo, detectLinuxGPUViaVulkan } from '@/utils/node/vulkan';
|
import { getVulkanInfo, detectGPUViaVulkan } from '@/utils/node/vulkan';
|
||||||
|
|
||||||
const COMMON_EXEC_OPTIONS = {
|
const COMMON_EXEC_OPTIONS = {
|
||||||
timeout: 3000,
|
timeout: 3000,
|
||||||
|
|
@ -35,11 +36,14 @@ export async function detectCPU() {
|
||||||
const result = await safeExecute(async () => {
|
const result = await safeExecute(async () => {
|
||||||
const cpu = await siCpu();
|
const cpu = await siCpu();
|
||||||
|
|
||||||
const devices: string[] = [];
|
const devices: { name: string; detailedName: string }[] = [];
|
||||||
if (cpu.brand) {
|
if (cpu.brand) {
|
||||||
devices.push(
|
const name = formatDeviceName(cpu.brand);
|
||||||
`${formatDeviceName(cpu.brand)} (${cpu.cores} cores) @ ${cpu.speed} GHz`
|
|
||||||
);
|
devices.push({
|
||||||
|
name,
|
||||||
|
detailedName: `${name} (${cpu.cores} cores) @ ${cpu.speed} GHz`,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const capabilities = {
|
const capabilities = {
|
||||||
|
|
@ -50,11 +54,10 @@ export async function detectCPU() {
|
||||||
return capabilities;
|
return capabilities;
|
||||||
}, 'CPU detection failed');
|
}, 'CPU detection failed');
|
||||||
|
|
||||||
const fallbackCapabilities = {
|
cpuCapabilitiesCache = result || {
|
||||||
devices: [],
|
devices: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
cpuCapabilitiesCache = result || fallbackCapabilities;
|
|
||||||
return cpuCapabilitiesCache;
|
return cpuCapabilitiesCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,7 +67,7 @@ export async function detectGPU() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await safeExecute(
|
const result = await safeExecute(
|
||||||
() => detectLinuxGPUViaVulkan(),
|
() => detectGPUViaVulkan(),
|
||||||
'GPU detection failed'
|
'GPU detection failed'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -101,10 +104,15 @@ async function detectVulkan() {
|
||||||
try {
|
try {
|
||||||
const vulkanInfo = await getVulkanInfo();
|
const vulkanInfo = await getVulkanInfo();
|
||||||
|
|
||||||
const devices: string[] = [];
|
const devices: GPUDevice[] = [];
|
||||||
|
|
||||||
for (const gpu of vulkanInfo.discreteGPUs) {
|
for (const gpu of vulkanInfo.allGPUs) {
|
||||||
devices.push(formatDeviceName(gpu.deviceName));
|
const isIntegrated = gpu.isIntegrated;
|
||||||
|
|
||||||
|
devices.push({
|
||||||
|
name: isIntegrated ? gpu.deviceName : formatDeviceName(gpu.deviceName),
|
||||||
|
isIntegrated,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -187,21 +195,56 @@ export async function detectROCm() {
|
||||||
const { stdout } = await execa(rocminfoCommand, [], COMMON_EXEC_OPTIONS);
|
const { stdout } = await execa(rocminfoCommand, [], COMMON_EXEC_OPTIONS);
|
||||||
|
|
||||||
if (stdout.trim()) {
|
if (stdout.trim()) {
|
||||||
const devices: string[] = [];
|
const devices: GPUDevice[] = [];
|
||||||
|
|
||||||
if (platform === 'win32') {
|
if (platform === 'win32') {
|
||||||
const lines = stdout.split('\n');
|
const lines = stdout.split('\n');
|
||||||
|
for (let i = 0; i < lines.length; i++) {
|
||||||
|
const line = lines[i];
|
||||||
|
|
||||||
for (const line of lines) {
|
if (line.includes('Marketing Name:')) {
|
||||||
const trimmedLine = line.trim();
|
const name = line.split('Marketing Name:')[1]?.trim();
|
||||||
if (trimmedLine.startsWith('Name:')) {
|
if (name && !name.toLowerCase().includes('cpu')) {
|
||||||
const name = trimmedLine.split('Name:')[1]?.trim();
|
let deviceType = '';
|
||||||
if (
|
|
||||||
name &&
|
const searchRangeLines = 20;
|
||||||
!name.toLowerCase().includes('cpu') &&
|
const searchStartIndex = Math.max(0, i - searchRangeLines);
|
||||||
!devices.includes(formatDeviceName(name))
|
const searchEndIndex = Math.min(
|
||||||
) {
|
lines.length,
|
||||||
devices.push(formatDeviceName(name));
|
i + searchRangeLines
|
||||||
|
);
|
||||||
|
|
||||||
|
for (
|
||||||
|
let searchIndex = searchStartIndex;
|
||||||
|
searchIndex < searchEndIndex;
|
||||||
|
searchIndex++
|
||||||
|
) {
|
||||||
|
if (lines[searchIndex].includes('Device Type:')) {
|
||||||
|
deviceType =
|
||||||
|
lines[searchIndex].split('Device Type:')[1]?.trim() || '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deviceType !== 'CPU') {
|
||||||
|
let isIntegrated = true;
|
||||||
|
try {
|
||||||
|
const vulkanInfo = await getVulkanInfo();
|
||||||
|
const matchingGPU = vulkanInfo.allGPUs.find(
|
||||||
|
(gpu) =>
|
||||||
|
gpu.deviceName.includes(name) ||
|
||||||
|
name.includes(gpu.deviceName)
|
||||||
|
);
|
||||||
|
isIntegrated = matchingGPU ? matchingGPU.isIntegrated : false;
|
||||||
|
} catch {
|
||||||
|
isIntegrated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
devices.push({
|
||||||
|
name: isIntegrated ? name : formatDeviceName(name),
|
||||||
|
isIntegrated,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -235,7 +278,24 @@ export async function detectROCm() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deviceType !== 'CPU') {
|
if (deviceType !== 'CPU') {
|
||||||
devices.push(formatDeviceName(name));
|
// Check if integrated by cross-referencing with vulkan GPU list
|
||||||
|
let isIntegrated = true;
|
||||||
|
try {
|
||||||
|
const vulkanInfo = await getVulkanInfo();
|
||||||
|
const matchingGPU = vulkanInfo.allGPUs.find(
|
||||||
|
(gpu) =>
|
||||||
|
gpu.deviceName.includes(name) ||
|
||||||
|
name.includes(gpu.deviceName)
|
||||||
|
);
|
||||||
|
isIntegrated = matchingGPU ? matchingGPU.isIntegrated : false;
|
||||||
|
} catch {
|
||||||
|
isIntegrated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
devices.push({
|
||||||
|
name: isIntegrated ? name : formatDeviceName(name),
|
||||||
|
isIntegrated,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -301,8 +361,8 @@ export async function detectROCm() {
|
||||||
try {
|
try {
|
||||||
const vulkanInfo = await getVulkanInfo();
|
const vulkanInfo = await getVulkanInfo();
|
||||||
|
|
||||||
for (const gpu of vulkanInfo.discreteGPUs) {
|
for (const gpu of vulkanInfo.allGPUs) {
|
||||||
if (gpu.driverInfo) {
|
if (gpu.driverInfo && !gpu.isIntegrated) {
|
||||||
driverVersion = gpu.driverInfo;
|
driverVersion = gpu.driverInfo;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -324,7 +384,7 @@ export async function detectROCm() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseClInfoOutput(output: string) {
|
function parseClInfoOutput(output: string) {
|
||||||
const devices: { name: string; isIntegrated: boolean }[] = [];
|
const devices: GPUDevice[] = [];
|
||||||
const lines = output.split('\n');
|
const lines = output.split('\n');
|
||||||
|
|
||||||
let currentPlatform = '';
|
let currentPlatform = '';
|
||||||
|
|
@ -342,9 +402,11 @@ function parseClInfoOutput(output: string) {
|
||||||
const computeUnits = findComputeUnitsInClInfo(lines, i);
|
const computeUnits = findComputeUnitsInClInfo(lines, i);
|
||||||
|
|
||||||
if (deviceName && currentPlatform) {
|
if (deviceName && currentPlatform) {
|
||||||
|
const isIntegrated = !isDiscreteGPU(computeUnits);
|
||||||
|
|
||||||
devices.push({
|
devices.push({
|
||||||
name: formatDeviceName(deviceName),
|
name: isIntegrated ? deviceName : formatDeviceName(deviceName),
|
||||||
isIntegrated: !isDiscreteGPU(computeUnits),
|
isIntegrated,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,7 @@ export async function getAvailableBackends(includeDisabled = false) {
|
||||||
backends.push({
|
backends.push({
|
||||||
value: 'cpu',
|
value: 'cpu',
|
||||||
label: 'CPU',
|
label: 'CPU',
|
||||||
devices: cpuCapabilities?.devices,
|
devices: cpuCapabilities?.devices.map((device) => device.name) || [],
|
||||||
disabled: false,
|
disabled: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
18
src/types/hardware.d.ts
vendored
18
src/types/hardware.d.ts
vendored
|
|
@ -1,5 +1,5 @@
|
||||||
export interface CPUCapabilities {
|
export interface CPUCapabilities {
|
||||||
devices: string[];
|
devices: { name: string; detailedName: string }[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GPUMemoryInfo {
|
export interface GPUMemoryInfo {
|
||||||
|
|
@ -12,6 +12,11 @@ export interface SystemMemoryInfo {
|
||||||
type?: string;
|
type?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GPUDevice {
|
||||||
|
readonly name: string;
|
||||||
|
readonly isIntegrated: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface GPUCapabilities {
|
export interface GPUCapabilities {
|
||||||
cuda: {
|
cuda: {
|
||||||
readonly devices: readonly string[];
|
readonly devices: readonly string[];
|
||||||
|
|
@ -19,16 +24,16 @@ export interface GPUCapabilities {
|
||||||
readonly driverVersion?: string;
|
readonly driverVersion?: string;
|
||||||
};
|
};
|
||||||
rocm: {
|
rocm: {
|
||||||
readonly devices: readonly string[];
|
readonly devices: readonly GPUDevice[];
|
||||||
readonly version?: string;
|
readonly version?: string;
|
||||||
readonly driverVersion?: string;
|
readonly driverVersion?: string;
|
||||||
};
|
};
|
||||||
vulkan: {
|
vulkan: {
|
||||||
readonly devices: readonly string[];
|
readonly devices: readonly GPUDevice[];
|
||||||
readonly version?: string;
|
readonly version?: string;
|
||||||
};
|
};
|
||||||
clblast: {
|
clblast: {
|
||||||
readonly devices: readonly CLBlastDevice[];
|
readonly devices: readonly GPUDevice[];
|
||||||
readonly version?: string;
|
readonly version?: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -39,11 +44,6 @@ export interface BasicGPUInfo {
|
||||||
gpuInfo: string[];
|
gpuInfo: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CLBlastDevice {
|
|
||||||
readonly name: string;
|
|
||||||
readonly isIntegrated: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HardwareDetectionResult {
|
export interface HardwareDetectionResult {
|
||||||
readonly supported: boolean;
|
readonly supported: boolean;
|
||||||
readonly devices: readonly string[];
|
readonly devices: readonly string[];
|
||||||
|
|
|
||||||
7
src/types/index.d.ts
vendored
7
src/types/index.d.ts
vendored
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { GPUDevice } from './hardware';
|
||||||
|
|
||||||
export interface ConfigFile {
|
export interface ConfigFile {
|
||||||
name: string;
|
name: string;
|
||||||
path: string;
|
path: string;
|
||||||
|
|
@ -72,10 +74,7 @@ export interface SelectOption {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BackendOption extends SelectOption {
|
export interface BackendOption extends SelectOption {
|
||||||
readonly devices?: readonly (
|
readonly devices?: readonly (string | GPUDevice)[];
|
||||||
| string
|
|
||||||
| { name: string; isIntegrated: boolean }
|
|
||||||
)[];
|
|
||||||
readonly disabled?: boolean;
|
readonly disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,13 @@ import { execa } from 'execa';
|
||||||
import { formatDeviceName } from '@/utils/format';
|
import { formatDeviceName } from '@/utils/format';
|
||||||
|
|
||||||
let vulkanInfoCache: {
|
let vulkanInfoCache: {
|
||||||
discreteGPUs: {
|
allGPUs: {
|
||||||
deviceName: string;
|
deviceName: string;
|
||||||
driverInfo?: string;
|
driverInfo?: string;
|
||||||
apiVersion?: string;
|
apiVersion?: string;
|
||||||
hasAMD: boolean;
|
hasAMD: boolean;
|
||||||
hasNVIDIA: boolean;
|
hasNVIDIA: boolean;
|
||||||
|
isIntegrated: boolean;
|
||||||
}[];
|
}[];
|
||||||
apiVersion?: string;
|
apiVersion?: string;
|
||||||
} | null = null;
|
} | null = null;
|
||||||
|
|
@ -25,19 +26,20 @@ export async function getVulkanInfo() {
|
||||||
reject: false,
|
reject: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const discreteGPUs: {
|
const allGPUs: {
|
||||||
deviceName: string;
|
deviceName: string;
|
||||||
driverInfo?: string;
|
driverInfo?: string;
|
||||||
apiVersion?: string;
|
apiVersion?: string;
|
||||||
hasAMD: boolean;
|
hasAMD: boolean;
|
||||||
hasNVIDIA: boolean;
|
hasNVIDIA: boolean;
|
||||||
|
isIntegrated: boolean;
|
||||||
}[] = [];
|
}[] = [];
|
||||||
let globalApiVersion: string | undefined;
|
let globalApiVersion: string | undefined;
|
||||||
|
|
||||||
if (stdout.trim()) {
|
if (stdout.trim()) {
|
||||||
const lines = stdout.split('\n');
|
const lines = stdout.split('\n');
|
||||||
let foundDiscreteGPU = false;
|
let foundGPU = false;
|
||||||
let currentGPU: (typeof discreteGPUs)[0] | null = null;
|
let currentGPU: (typeof allGPUs)[0] | null = null;
|
||||||
|
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
if (
|
if (
|
||||||
|
|
@ -51,15 +53,22 @@ export async function getVulkanInfo() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line.includes('PHYSICAL_DEVICE_TYPE_DISCRETE_GPU')) {
|
if (
|
||||||
foundDiscreteGPU = true;
|
line.includes('PHYSICAL_DEVICE_TYPE_DISCRETE_GPU') ||
|
||||||
|
line.includes('PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU')
|
||||||
|
) {
|
||||||
|
foundGPU = true;
|
||||||
|
const isIntegrated = line.includes(
|
||||||
|
'PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU'
|
||||||
|
);
|
||||||
currentGPU = {
|
currentGPU = {
|
||||||
deviceName: '',
|
deviceName: '',
|
||||||
hasAMD: false,
|
hasAMD: false,
|
||||||
hasNVIDIA: false,
|
hasNVIDIA: false,
|
||||||
|
isIntegrated,
|
||||||
};
|
};
|
||||||
} else if (
|
} else if (
|
||||||
foundDiscreteGPU &&
|
foundGPU &&
|
||||||
currentGPU &&
|
currentGPU &&
|
||||||
line.includes('deviceName') &&
|
line.includes('deviceName') &&
|
||||||
line.includes('=')
|
line.includes('=')
|
||||||
|
|
@ -79,17 +88,13 @@ export async function getVulkanInfo() {
|
||||||
name.toLowerCase().includes('gtx');
|
name.toLowerCase().includes('gtx');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (foundGPU && currentGPU && line.includes('driverInfo')) {
|
||||||
foundDiscreteGPU &&
|
|
||||||
currentGPU &&
|
|
||||||
line.includes('driverInfo')
|
|
||||||
) {
|
|
||||||
const mesaMatch = line.match(/Mesa\s+(.+)/);
|
const mesaMatch = line.match(/Mesa\s+(.+)/);
|
||||||
if (mesaMatch) {
|
if (mesaMatch) {
|
||||||
currentGPU.driverInfo = `Mesa ${mesaMatch[1].trim()}`;
|
currentGPU.driverInfo = `Mesa ${mesaMatch[1].trim()}`;
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
foundDiscreteGPU &&
|
foundGPU &&
|
||||||
currentGPU &&
|
currentGPU &&
|
||||||
line.includes('apiVersion') &&
|
line.includes('apiVersion') &&
|
||||||
line.includes('=')
|
line.includes('=')
|
||||||
|
|
@ -101,35 +106,35 @@ export async function getVulkanInfo() {
|
||||||
globalApiVersion = match[1];
|
globalApiVersion = match[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (foundDiscreteGPU && currentGPU && line.includes('GPU')) {
|
} else if (foundGPU && currentGPU && line.includes('GPU')) {
|
||||||
if (currentGPU.deviceName) {
|
if (currentGPU.deviceName) {
|
||||||
discreteGPUs.push(currentGPU);
|
allGPUs.push(currentGPU);
|
||||||
}
|
}
|
||||||
foundDiscreteGPU = false;
|
foundGPU = false;
|
||||||
currentGPU = null;
|
currentGPU = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (foundDiscreteGPU && currentGPU && currentGPU.deviceName) {
|
if (foundGPU && currentGPU && currentGPU.deviceName) {
|
||||||
discreteGPUs.push(currentGPU);
|
allGPUs.push(currentGPU);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vulkanInfoCache = {
|
vulkanInfoCache = {
|
||||||
discreteGPUs,
|
allGPUs,
|
||||||
apiVersion: globalApiVersion,
|
apiVersion: globalApiVersion,
|
||||||
};
|
};
|
||||||
|
|
||||||
return vulkanInfoCache;
|
return vulkanInfoCache;
|
||||||
} catch {
|
} catch {
|
||||||
vulkanInfoCache = {
|
vulkanInfoCache = {
|
||||||
discreteGPUs: [],
|
allGPUs: [],
|
||||||
};
|
};
|
||||||
return vulkanInfoCache;
|
return vulkanInfoCache;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function detectLinuxGPUViaVulkan() {
|
export async function detectGPUViaVulkan() {
|
||||||
try {
|
try {
|
||||||
const vulkanInfo = await getVulkanInfo();
|
const vulkanInfo = await getVulkanInfo();
|
||||||
|
|
||||||
|
|
@ -137,7 +142,7 @@ export async function detectLinuxGPUViaVulkan() {
|
||||||
let hasNVIDIA = false;
|
let hasNVIDIA = false;
|
||||||
const gpuInfo: string[] = [];
|
const gpuInfo: string[] = [];
|
||||||
|
|
||||||
for (const gpu of vulkanInfo.discreteGPUs) {
|
for (const gpu of vulkanInfo.allGPUs.filter((g) => !g.isIntegrated)) {
|
||||||
gpuInfo.push(formatDeviceName(gpu.deviceName));
|
gpuInfo.push(formatDeviceName(gpu.deviceName));
|
||||||
|
|
||||||
if (gpu.hasAMD) {
|
if (gpu.hasAMD) {
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ export const createHardwareItems = (hardwareInfo: HardwareInfo) => [
|
||||||
label: 'CPU',
|
label: 'CPU',
|
||||||
value:
|
value:
|
||||||
hardwareInfo.cpu.devices.length > 0
|
hardwareInfo.cpu.devices.length > 0
|
||||||
? hardwareInfo.cpu.devices[0]
|
? hardwareInfo.cpu.devices[0].detailedName
|
||||||
: 'Unknown',
|
: 'Unknown',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -147,12 +147,42 @@ export const createHardwareItems = (hardwareInfo: HardwareInfo) => [
|
||||||
}`
|
}`
|
||||||
: 'Detecting...',
|
: 'Detecting...',
|
||||||
},
|
},
|
||||||
...(hardwareInfo.gpu.gpuInfo.length > 0
|
...(() => {
|
||||||
? hardwareInfo.gpu.gpuInfo.map((gpu, index) => ({
|
const discreteGPUs = [];
|
||||||
label: `GPU ${index > 0 ? index + 1 : ''}`.trim(),
|
|
||||||
value: gpu,
|
if (hardwareInfo.gpuCapabilities.vulkan.devices.length > 0) {
|
||||||
}))
|
discreteGPUs.push(
|
||||||
: [{ label: 'GPU', value: 'No GPU detected' }]),
|
...hardwareInfo.gpuCapabilities.vulkan.devices.filter(
|
||||||
|
(gpu) => !gpu.isIntegrated
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (hardwareInfo.gpuCapabilities.rocm.devices.length > 0) {
|
||||||
|
discreteGPUs.push(
|
||||||
|
...hardwareInfo.gpuCapabilities.rocm.devices.filter(
|
||||||
|
(gpu) => !gpu.isIntegrated
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (hardwareInfo.gpuCapabilities.clblast.devices.length > 0) {
|
||||||
|
discreteGPUs.push(
|
||||||
|
...hardwareInfo.gpuCapabilities.clblast.devices.filter(
|
||||||
|
(gpu) => !gpu.isIntegrated
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uniqueDiscreteGPUs = discreteGPUs.filter(
|
||||||
|
(gpu, index, arr) => arr.findIndex((g) => g.name === gpu.name) === index
|
||||||
|
);
|
||||||
|
|
||||||
|
return uniqueDiscreteGPUs.length > 0
|
||||||
|
? uniqueDiscreteGPUs.map((gpu, index) => ({
|
||||||
|
label: `GPU ${index > 0 ? index + 1 : ''}`.trim(),
|
||||||
|
value: gpu.name,
|
||||||
|
}))
|
||||||
|
: [{ label: 'GPU', value: 'No discrete GPU detected' }];
|
||||||
|
})(),
|
||||||
...(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(),
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue