enhancement: filter active gpu on system monitor

This commit is contained in:
Faisal Amir 2025-07-03 23:36:53 +07:00
parent 19fc399ae1
commit 3a197d56c0

View File

@ -11,6 +11,7 @@ import { getActiveModels, stopModel } from '@/services/models'
import { Button } from '@/components/ui/button'
import { useTranslation } from '@/i18n/react-i18next-compat'
import { toNumber } from '@/utils/number'
import { useModelProvider } from '@/hooks/useModelProvider'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const Route = createFileRoute(route.systemMonitor as any)({
@ -19,28 +20,85 @@ export const Route = createFileRoute(route.systemMonitor as any)({
function SystemMonitor() {
const { t } = useTranslation()
const { hardwareData, systemUsage, setHardwareData, updateSystemUsage } =
const { hardwareData, systemUsage, updateHardwareDataPreservingGpuOrder, updateSystemUsage, updateGPUActivationFromDeviceString } =
useHardware()
const [activeModels, setActiveModels] = useState<string[]>([])
const { providers, getProviderByName } = useModelProvider()
const [isInitialized, setIsInitialized] = useState(false)
// Determine backend type and filter GPUs accordingly (same logic as hardware.tsx)
const llamacpp = providers.find((p) => p.provider === 'llamacpp')
const versionBackend = llamacpp?.settings.find((s) => s.key === "version_backend")?.controller_props.value
useEffect(() => {
// Initial data fetch
// Initial data fetch - use updateHardwareDataPreservingGpuOrder like hardware.tsx
getHardwareInfo().then((data) => {
setHardwareData(data as unknown as HardwareData)
updateHardwareDataPreservingGpuOrder(data as unknown as HardwareData)
})
getActiveModels().then(setActiveModels)
// Set up interval for real-time updates
const intervalId = setInterval(() => {
getSystemUsage().then((data) => {
// setHardwareData(data as unknown as HardwareData)
updateSystemUsage(data)
})
getActiveModels().then(setActiveModels)
}, 5000)
return () => clearInterval(intervalId)
}, [setHardwareData, setActiveModels, updateSystemUsage])
}, [updateHardwareDataPreservingGpuOrder, setActiveModels, updateSystemUsage])
// Initialize GPU activations from device setting on first load (same logic as hardware.tsx)
useEffect(() => {
if (hardwareData.gpus.length > 0 && !isInitialized) {
const llamacppProvider = getProviderByName('llamacpp')
const currentDeviceSetting = llamacppProvider?.settings.find(s => s.key === 'device')?.controller_props.value as string
if (currentDeviceSetting) {
updateGPUActivationFromDeviceString(currentDeviceSetting)
}
setIsInitialized(true)
}
}, [hardwareData.gpus.length, isInitialized, getProviderByName, updateGPUActivationFromDeviceString])
// Sync device setting when GPU activations change (only after initialization) - same logic as hardware.tsx
const { getActivatedDeviceString } = useHardware()
const { updateProvider } = useModelProvider()
const gpuActivationStates = hardwareData.gpus.map(gpu => gpu.activated)
useEffect(() => {
if (isInitialized && hardwareData.gpus.length > 0) {
const llamacppProvider = getProviderByName('llamacpp')
const backendType = llamacppProvider?.settings.find(s => s.key === 'version_backend')?.controller_props.value as string
const deviceString = getActivatedDeviceString(backendType)
if (llamacppProvider) {
const currentDeviceSetting = llamacppProvider.settings.find(s => s.key === 'device')
// Sync device string when GPU activations change (only after initialization)
if (currentDeviceSetting && currentDeviceSetting.controller_props.value !== deviceString) {
const updatedSettings = llamacppProvider.settings.map(setting => {
if (setting.key === 'device') {
return {
...setting,
controller_props: {
...setting.controller_props,
value: deviceString
}
}
}
return setting
})
updateProvider('llamacpp', {
settings: updatedSettings
})
}
}
}
}, [isInitialized, gpuActivationStates, versionBackend, getActivatedDeviceString, updateProvider, getProviderByName, hardwareData.gpus.length])
const stopRunningModel = (modelId: string) => {
stopModel(modelId)
@ -61,6 +119,33 @@ function SystemMonitor() {
hardwareData.total_memory
) * 100
// Determine backend type and filter GPUs accordingly
const isCudaBackend = typeof versionBackend === 'string' && versionBackend.includes('cuda')
const isVulkanBackend = typeof versionBackend === 'string' && versionBackend.includes('vulkan')
// Check if GPU should be active based on backend compatibility
const isGPUCompatible = (gpu: any) => {
if (isCudaBackend) {
return gpu.nvidia_info !== null
} else if (isVulkanBackend) {
return gpu.vulkan_info !== null
} else {
// No valid backend - all GPUs are inactive
return false
}
}
// Check if GPU is actually activated
const isGPUActive = (gpu: any) => {
const compatible = isGPUCompatible(gpu)
const activated = gpu.activated ?? false
const result = compatible && activated
return result
}
// Filter to show only active GPUs
const activeGPUs = hardwareData.gpus.filter(gpu => isGPUActive(gpu))
return (
<div className="flex flex-col h-full bg-main-view overflow-y-auto p-6">
<div className="flex items-center mb-4 gap-2">
@ -220,11 +305,18 @@ function SystemMonitor() {
<h2 className="text-base font-semibold text-main-view-fg mb-4">
{t('system-monitor:activeGpus')}
</h2>
{hardwareData.gpus.length > 0 ? (
{!isInitialized ? (
<div className="text-center text-main-view-fg/50 py-4">
Initializing GPU states...
</div>
) : activeGPUs.length > 0 ? (
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{hardwareData.gpus
// .filter((gpu) => gpu.activated)
.map((gpu, index) => (
{activeGPUs.map((gpu, index) => {
// Find the corresponding system usage data for this GPU
const gpuUsage = systemUsage.gpus.find(usage => usage.uuid === gpu.uuid)
const gpuIndex = hardwareData.gpus.findIndex(hwGpu => hwGpu.uuid === gpu.uuid)
return (
<div
key={gpu.uuid || index}
className="bg-main-view-fg/3 rounded-lg p-4"
@ -243,11 +335,17 @@ function SystemMonitor() {
{t('system-monitor:vramUsage')}
</span>
<span className="text-main-view-fg">
{formatMegaBytes(
gpu.total_memory -
systemUsage.gpus[index]?.used_memory
)}{' '}
/ {formatMegaBytes(gpu.total_memory)}
{gpuUsage ? (
<>
{formatMegaBytes(gpuUsage.used_memory)}{' '}
/ {formatMegaBytes(gpu.total_memory)}
</>
) : (
<>
{formatMegaBytes(0)}{' '}
/ {formatMegaBytes(gpu.total_memory)}
</>
)}
</span>
</div>
<div className="flex justify-between items-center">
@ -264,23 +362,22 @@ function SystemMonitor() {
</span>
<span className="text-main-view-fg">
{gpu.nvidia_info?.compute_capability ||
gpu.vulkan_info.api_version}
gpu.vulkan_info?.api_version || '-'}
</span>
</div>
<div className="mt-2">
<Progress
value={
((gpu.total_memory -
systemUsage.gpus[index]?.used_memory) /
gpu.total_memory) *
100
gpuUsage ?
((gpuUsage.used_memory / gpu.total_memory) * 100) : 0
}
className="h-2 w-full"
/>
</div>
</div>
</div>
))}
)
})}
</div>
) : (
<div className="text-center text-main-view-fg/50 py-4">
@ -288,6 +385,7 @@ function SystemMonitor() {
</div>
)}
</div>
</div>
)
}