Self-check. Fan control failed for an entire session -- recoverably, and completely invisibly. It appeared once, inside one field of one log line, and nothing ever asked whether fan control worked. health.py now checks everything this service depends on (NVML, passwordless sudo for nvidia-smi, fan control via the headless X server, overclock drift, the telemetry store, residency measurement capability, model directories, the ComfyUI websocket, and both upstream HTTP services) and reports for each one what is broken, what that breaks, and how to fix it. Exposed at GET /api/health, as an MCP tool, and as a dashboard panel that collapses to a badge when healthy and expands to impact-and-fix when not. Current state: 9 ok, 1 degraded (the known cachestat permission limit on Ollama's blobs). A self-check that returns ok while a dependency is broken is worse than none, so the tests drive each check to its failure state -- including the exact "Error resolving target specification 'gpu:0'" string from the original incident -- and assert that a check which raises surfaces as failed rather than taking down the endpoint. SSE payload. The installed-model catalog was 10.6 KB of a 13.1 KB frame, 81% of the stream, re-sent to every subscriber every second despite changing only when a model is pulled or removed: 135 MB/hour across three tabs. It is now sent on a subscriber's first frame and whenever the set changes; the client keeps the last known list. Steady-state frames dropped from 14041 to 3664 bytes, a 74% reduction, and /api/stats still returns the complete snapshot for API consumers. Tests: 182 (was 169). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
884 lines
53 KiB
HTML
884 lines
53 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en" class="dark">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>HYPERSWAP // Dual-Engine Model Orchestrator & Live Telemetry</title>
|
||
<script src="https://cdn.tailwindcss.com"></script>
|
||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
|
||
<link rel="stylesheet" href="/static/styles.css">
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||
</head>
|
||
<body class="bg-slate-950 text-slate-100 min-h-screen font-sans antialiased selection:bg-cyan-500 selection:text-white">
|
||
|
||
<!-- TOP HEADER -->
|
||
<header class="border-b border-slate-800 bg-slate-900/80 backdrop-blur sticky top-0 z-50">
|
||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-3 flex flex-wrap items-center justify-between gap-4">
|
||
<div class="flex items-center space-x-3">
|
||
<div class="w-10 h-10 rounded-xl bg-gradient-to-tr from-cyan-500 via-indigo-500 to-purple-500 flex items-center justify-center shadow-lg shadow-cyan-500/20">
|
||
<i class="fa-solid fa-bolt-lightning text-white text-lg"></i>
|
||
</div>
|
||
<div>
|
||
<div class="flex items-center space-x-2">
|
||
<h1 class="text-xl font-bold tracking-tight bg-clip-text text-transparent bg-gradient-to-r from-cyan-400 via-sky-300 to-indigo-400">
|
||
HYPERSWAP
|
||
</h1>
|
||
<span class="text-xs uppercase tracking-widest px-2 py-0.5 rounded bg-cyan-950/80 text-cyan-400 border border-cyan-800 font-mono">
|
||
v1.0-DEPLOY
|
||
</span>
|
||
</div>
|
||
<p class="text-xs text-slate-400 font-mono">NVIDIA RTX 4080 SUPER 16GB // 64GB DDR5 RAM // Ubuntu Linux</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="flex items-center space-x-3">
|
||
<!-- Service Status Indicators -->
|
||
<div class="flex items-center space-x-2 px-3 py-1.5 rounded-lg bg-slate-800/80 border border-slate-700/60 text-xs">
|
||
<span class="relative flex h-2.5 w-2.5">
|
||
<span id="ollama-pulse" class="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
|
||
<span id="ollama-dot" class="relative inline-flex rounded-full h-2.5 w-2.5 bg-emerald-500"></span>
|
||
</span>
|
||
<span class="font-medium text-slate-300">Ollama LLM:</span>
|
||
<span id="ollama-status-text" class="text-emerald-400 font-mono font-bold">ONLINE</span>
|
||
</div>
|
||
|
||
<div class="flex items-center space-x-2 px-3 py-1.5 rounded-lg bg-slate-800/80 border border-slate-700/60 text-xs">
|
||
<span class="relative flex h-2.5 w-2.5">
|
||
<span id="comfy-pulse" class="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
|
||
<span id="comfy-dot" class="relative inline-flex rounded-full h-2.5 w-2.5 bg-emerald-500"></span>
|
||
</span>
|
||
<span class="font-medium text-slate-300">ComfyUI:</span>
|
||
<span id="comfy-status-text" class="text-emerald-400 font-mono font-bold">ONLINE</span>
|
||
</div>
|
||
|
||
<div class="flex items-center space-x-1.5 px-3 py-1.5 rounded-lg bg-slate-800/80 border border-slate-700/60 text-xs text-slate-400 font-mono">
|
||
<i class="fa-solid fa-satellite-dish text-cyan-400 text-xs animate-pulse"></i>
|
||
<span id="sse-badge">SSE 1Hz</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- MAIN CONTAINER -->
|
||
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6 space-y-6">
|
||
|
||
<!-- HERO MEMORY GAUGES -->
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||
<!-- GPU VRAM ALLOCATION GAUGE -->
|
||
<div class="bg-slate-900/70 border border-slate-800 rounded-2xl p-5 relative overflow-hidden backdrop-blur">
|
||
<div class="flex justify-between items-start mb-3">
|
||
<div>
|
||
<div class="flex items-center space-x-2">
|
||
<i class="fa-solid fa-microchip text-cyan-400"></i>
|
||
<h2 class="text-sm font-semibold text-slate-200 tracking-wide uppercase">GPU VRAM (16 GB Dedicated)</h2>
|
||
</div>
|
||
<p class="text-xs text-slate-400 mt-0.5">Real-time allocation breakdown on RTX 4080 SUPER</p>
|
||
</div>
|
||
<div class="text-right font-mono">
|
||
<span id="vram-total-used" class="text-2xl font-bold text-slate-100">0.0</span>
|
||
<span class="text-xs text-slate-400">/ 16.0 GB</span>
|
||
<div id="vram-used-pct" class="text-xs text-cyan-400 font-bold">0% USED</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Segmented Bar -->
|
||
<div class="h-6 w-full bg-slate-950 rounded-lg overflow-hidden flex border border-slate-800 p-0.5">
|
||
<div id="bar-ollama" class="bg-gradient-to-r from-purple-600 to-indigo-500 h-full rounded-l transition-all duration-500 relative group" style="width: 0%">
|
||
<div class="opacity-0 group-hover:opacity-100 absolute -top-8 left-1/2 -translate-x-1/2 bg-slate-800 text-[10px] text-white px-2 py-0.5 rounded border border-slate-700 whitespace-nowrap z-20">
|
||
Ollama: <span id="tooltip-ollama">0 GB</span>
|
||
</div>
|
||
</div>
|
||
<div id="bar-comfy" class="bg-gradient-to-r from-cyan-500 to-sky-400 h-full transition-all duration-500 relative group" style="width: 0%">
|
||
<div class="opacity-0 group-hover:opacity-100 absolute -top-8 left-1/2 -translate-x-1/2 bg-slate-800 text-[10px] text-white px-2 py-0.5 rounded border border-slate-700 whitespace-nowrap z-20">
|
||
ComfyUI: <span id="tooltip-comfy">0 GB</span>
|
||
</div>
|
||
</div>
|
||
<div id="bar-system" class="bg-slate-600 h-full transition-all duration-500 relative group" style="width: 0%">
|
||
<div class="opacity-0 group-hover:opacity-100 absolute -top-8 left-1/2 -translate-x-1/2 bg-slate-800 text-[10px] text-white px-2 py-0.5 rounded border border-slate-700 whitespace-nowrap z-20">
|
||
System: <span id="tooltip-system">0 GB</span>
|
||
</div>
|
||
</div>
|
||
<div id="bar-free" class="bg-slate-900 h-full rounded-r transition-all duration-500" style="width: 100%"></div>
|
||
</div>
|
||
|
||
<!-- Legend -->
|
||
<div class="grid grid-cols-4 gap-2 mt-3 text-xs font-mono">
|
||
<div class="flex items-center space-x-1.5">
|
||
<span class="w-2.5 h-2.5 rounded-full bg-purple-500"></span>
|
||
<span class="text-slate-400">Ollama:</span>
|
||
<span id="legend-ollama" class="text-slate-200 font-bold">0 GB</span>
|
||
</div>
|
||
<div class="flex items-center space-x-1.5">
|
||
<span class="w-2.5 h-2.5 rounded-full bg-cyan-400"></span>
|
||
<span class="text-slate-400">Comfy:</span>
|
||
<span id="legend-comfy" class="text-slate-200 font-bold">0 GB</span>
|
||
</div>
|
||
<div class="flex items-center space-x-1.5">
|
||
<span class="w-2.5 h-2.5 rounded-full bg-slate-500"></span>
|
||
<span class="text-slate-400">System:</span>
|
||
<span id="legend-system" class="text-slate-200 font-bold">0 GB</span>
|
||
</div>
|
||
<div class="flex items-center space-x-1.5">
|
||
<span class="w-2.5 h-2.5 rounded-full bg-slate-800 border border-slate-700"></span>
|
||
<span class="text-slate-400">Free:</span>
|
||
<span id="legend-free" class="text-emerald-400 font-bold">0 GB</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- SYSTEM RAM & PAGE CACHE GAUGE -->
|
||
<div class="bg-slate-900/70 border border-slate-800 rounded-2xl p-5 relative overflow-hidden backdrop-blur">
|
||
<div class="flex justify-between items-start mb-3">
|
||
<div>
|
||
<div class="flex items-center space-x-2">
|
||
<i class="fa-solid fa-memory text-amber-400"></i>
|
||
<h2 class="text-sm font-semibold text-slate-200 tracking-wide uppercase">Host RAM & Model Page Cache (64 GB)</h2>
|
||
</div>
|
||
<p class="text-xs text-slate-400 mt-0.5">Models stay resident in RAM for instant PCIe hot-swaps</p>
|
||
</div>
|
||
<div class="text-right font-mono">
|
||
<span id="ram-cached-gb" class="text-2xl font-bold text-amber-400">0.0</span>
|
||
<span class="text-xs text-slate-400">GB CACHED</span>
|
||
<div id="ram-total-text" class="text-xs text-slate-400">60.3 GB Total</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Segmented Bar -->
|
||
<div class="h-6 w-full bg-slate-950 rounded-lg overflow-hidden flex border border-slate-800 p-0.5">
|
||
<div id="bar-ram-used" class="bg-gradient-to-r from-rose-600 to-orange-500 h-full rounded-l transition-all duration-500" style="width: 10%"></div>
|
||
<div id="bar-ram-cache" class="bg-gradient-to-r from-amber-500 to-yellow-400 h-full transition-all duration-500" style="width: 50%"></div>
|
||
<div id="bar-ram-free" class="bg-slate-900 h-full rounded-r transition-all duration-500" style="width: 40%"></div>
|
||
</div>
|
||
|
||
<!-- Legend -->
|
||
<div class="grid grid-cols-3 gap-2 mt-3 text-xs font-mono">
|
||
<div class="flex items-center space-x-1.5">
|
||
<span class="w-2.5 h-2.5 rounded-full bg-rose-500"></span>
|
||
<span class="text-slate-400">Apps Used:</span>
|
||
<span id="legend-ram-used" class="text-slate-200 font-bold">0 GB</span>
|
||
</div>
|
||
<div class="flex items-center space-x-1.5">
|
||
<span class="w-2.5 h-2.5 rounded-full bg-amber-400"></span>
|
||
<span class="text-slate-400">Models in RAM:</span>
|
||
<span id="legend-ram-cached" class="text-amber-400 font-bold">0 GB</span>
|
||
</div>
|
||
<div class="flex items-center space-x-1.5">
|
||
<span class="w-2.5 h-2.5 rounded-full bg-slate-800 border border-slate-700"></span>
|
||
<span class="text-slate-400">Free RAM:</span>
|
||
<span id="legend-ram-free" class="text-emerald-400 font-bold">0 GB</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 4-CARD CONTROL & TELEMETRY GRID -->
|
||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||
|
||
<!-- CARD 1: OLLAMA LLM ENGINE -->
|
||
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-5 flex flex-col justify-between space-y-4">
|
||
<div>
|
||
<div class="flex items-center justify-between pb-3 border-b border-slate-800">
|
||
<div class="flex items-center space-x-2">
|
||
<div class="p-2 rounded-lg bg-purple-950/80 border border-purple-800 text-purple-400">
|
||
<i class="fa-solid fa-brain text-sm"></i>
|
||
</div>
|
||
<div>
|
||
<h3 class="font-bold text-slate-100 text-sm">Ollama LLM Engine</h3>
|
||
<p class="text-xs text-slate-400">Port :11434 // FlashAttention + Q4 KV Cache</p>
|
||
</div>
|
||
</div>
|
||
<button onclick="freeOllamaVRAM()" class="px-2.5 py-1 text-xs font-semibold rounded-lg bg-rose-950/70 border border-rose-800 text-rose-300 hover:bg-rose-900 transition flex items-center space-x-1">
|
||
<i class="fa-solid fa-arrow-down-to-bracket"></i>
|
||
<span>Soft-Yield VRAM</span>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Active Model Box -->
|
||
<div class="mt-4 p-4 rounded-xl bg-slate-950 border border-slate-800/80 space-y-3">
|
||
<div class="flex justify-between items-center">
|
||
<span class="text-xs text-slate-400 uppercase font-mono">Active Model in VRAM</span>
|
||
<span id="ollama-vram-badge" class="px-2 py-0.5 text-[10px] font-mono rounded bg-purple-900/60 text-purple-300 border border-purple-700">
|
||
0.0 GB VRAM
|
||
</span>
|
||
</div>
|
||
<div class="flex items-center justify-between">
|
||
<div class="flex items-center space-x-2 overflow-hidden">
|
||
<i class="fa-solid fa-cube text-purple-400"></i>
|
||
<span id="ollama-active-model" class="text-base font-bold font-mono text-slate-100 truncate">None Loaded</span>
|
||
</div>
|
||
<span id="ollama-context" class="text-xs font-mono text-slate-400">0 ctx</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Quick Hot-Swap Control -->
|
||
<div class="mt-4 space-y-2">
|
||
<label class="text-xs font-semibold text-slate-300 flex items-center justify-between">
|
||
<span>Instant Model Hot-Swap:</span>
|
||
<span class="text-[10px] text-cyan-400 font-mono">RAM Cache Optimized</span>
|
||
</label>
|
||
<div class="flex space-x-2">
|
||
<select id="ollama-model-select" class="flex-1 bg-slate-950 border border-slate-700 rounded-lg px-3 py-2 text-xs font-mono text-slate-200 focus:outline-none focus:border-purple-500">
|
||
<option value="">Loading installed models...</option>
|
||
</select>
|
||
<button id="btn-switch-model" onclick="triggerModelSwitch()" class="px-4 py-2 bg-gradient-to-r from-purple-600 to-indigo-600 hover:from-purple-500 hover:to-indigo-500 text-white text-xs font-bold rounded-lg shadow-md transition flex items-center space-x-1.5">
|
||
<i class="fa-solid fa-shuffle"></i>
|
||
<span>Hot Swap</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Ollama Stats Footer -->
|
||
<div class="pt-3 border-t border-slate-800 grid grid-cols-3 gap-2 text-center font-mono text-xs">
|
||
<div class="p-2 rounded bg-slate-950 border border-slate-800">
|
||
<span class="text-[10px] text-slate-500 block">LAST SWAP TIME</span>
|
||
<span id="ollama-last-swap" class="text-cyan-400 font-bold">-- ms</span>
|
||
</div>
|
||
<div class="p-2 rounded bg-slate-950 border border-slate-800">
|
||
<span class="text-[10px] text-slate-500 block">RAM HIT STATUS</span>
|
||
<span id="ollama-cache-hit" class="text-emerald-400 font-bold">--</span>
|
||
</div>
|
||
<div class="p-2 rounded bg-slate-950 border border-slate-800">
|
||
<span class="text-[10px] text-slate-500 block">TOTAL MODELS</span>
|
||
<span id="ollama-total-models" class="text-slate-300 font-bold">0</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- CARD 2: COMFYUI DIFFUSION PIPELINE -->
|
||
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-5 flex flex-col justify-between space-y-4">
|
||
<div>
|
||
<div class="flex items-center justify-between pb-3 border-b border-slate-800">
|
||
<div class="flex items-center space-x-2">
|
||
<div class="p-2 rounded-lg bg-cyan-950/80 border border-cyan-800 text-cyan-400">
|
||
<i class="fa-solid fa-palette text-sm"></i>
|
||
</div>
|
||
<div>
|
||
<h3 class="font-bold text-slate-100 text-sm">ComfyUI Diffusion Engine</h3>
|
||
<p class="text-xs text-slate-400">Port :8188 // DynamicVRAM + Pinned Async Offload</p>
|
||
</div>
|
||
</div>
|
||
<button onclick="freeComfyVRAM()" class="px-2.5 py-1 text-xs font-semibold rounded-lg bg-rose-950/70 border border-rose-800 text-rose-300 hover:bg-rose-900 transition flex items-center space-x-1">
|
||
<i class="fa-solid fa-broom"></i>
|
||
<span>Purge VRAM</span>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Comfy Execution Box -->
|
||
<div class="mt-4 p-4 rounded-xl bg-slate-950 border border-slate-800/80 space-y-3">
|
||
<div class="flex justify-between items-center">
|
||
<span class="text-xs text-slate-400 uppercase font-mono">Pipeline Status</span>
|
||
<span id="comfy-exec-badge" class="px-2 py-0.5 text-[10px] font-mono rounded bg-emerald-950 text-emerald-300 border border-emerald-800">
|
||
IDLE / READY
|
||
</span>
|
||
</div>
|
||
<div class="flex items-center justify-between">
|
||
<div class="flex items-center space-x-2">
|
||
<i class="fa-solid fa-layer-group text-cyan-400"></i>
|
||
<span id="comfy-model-info" class="text-sm font-mono text-slate-200">Dynamic Model Offloader</span>
|
||
</div>
|
||
<div class="text-xs font-mono text-slate-400">
|
||
Queue: <span id="comfy-queue-count" class="text-cyan-400 font-bold">0</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Comfy Feature Checklist -->
|
||
<div class="mt-4 space-y-2 text-xs">
|
||
<div class="p-2.5 rounded-lg bg-slate-950 border border-slate-800 space-y-1.5">
|
||
<div class="flex items-center justify-between text-slate-300">
|
||
<span class="flex items-center space-x-1.5">
|
||
<i class="fa-solid fa-check text-emerald-400 text-xs"></i>
|
||
<span>Host Pinned Memory:</span>
|
||
</span>
|
||
<span class="font-mono font-bold text-emerald-400">53.6 GB Staging Buffer</span>
|
||
</div>
|
||
<div class="flex items-center justify-between text-slate-300">
|
||
<span class="flex items-center space-x-1.5">
|
||
<i class="fa-solid fa-check text-emerald-400 text-xs"></i>
|
||
<span>Async PCIe Offloading:</span>
|
||
</span>
|
||
<span class="font-mono font-bold text-cyan-400">Enabled (2 Streams)</span>
|
||
</div>
|
||
<div class="flex items-center justify-between text-slate-300">
|
||
<span class="flex items-center space-x-1.5">
|
||
<i class="fa-solid fa-check text-emerald-400 text-xs"></i>
|
||
<span>Fast Disk RAM Mmap:</span>
|
||
</span>
|
||
<span class="font-mono font-bold text-amber-400">Active</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Comfy Stats Footer -->
|
||
<div class="pt-3 border-t border-slate-800 grid grid-cols-2 gap-2 text-center font-mono text-xs">
|
||
<div class="p-2 rounded bg-slate-950 border border-slate-800">
|
||
<span class="text-[10px] text-slate-500 block">DISCOVERED MODELS</span>
|
||
<span id="comfy-discovered-count" class="text-cyan-400 font-bold">0 Files</span>
|
||
</div>
|
||
<div class="p-2 rounded bg-slate-950 border border-slate-800">
|
||
<span class="text-[10px] text-slate-500 block">VRAM AVAILABLE</span>
|
||
<span id="comfy-vram-avail" class="text-emerald-400 font-bold">15.9 GB</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- CARD 3: GPU HARDWARE TELEMETRY -->
|
||
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-5 space-y-4">
|
||
<div class="flex items-center justify-between pb-3 border-b border-slate-800">
|
||
<div class="flex items-center space-x-2">
|
||
<div class="p-2 rounded-lg bg-emerald-950/80 border border-emerald-800 text-emerald-400">
|
||
<i class="fa-solid fa-gauge-high text-sm"></i>
|
||
</div>
|
||
<div>
|
||
<h3 class="font-bold text-slate-100 text-sm">GPU Live Telemetry (NVML)</h3>
|
||
<p class="text-xs text-slate-400" id="gpu-chip-name">NVIDIA GeForce RTX 4080 SUPER</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Quick Gauges Grid -->
|
||
<div class="grid grid-cols-2 sm:grid-cols-4 gap-3 font-mono">
|
||
<div class="p-3 rounded-xl bg-slate-950 border border-slate-800 text-center">
|
||
<span class="text-[10px] text-slate-400 uppercase block">GPU Util</span>
|
||
<span id="gpu-util-val" class="text-xl font-bold text-cyan-400">0%</span>
|
||
</div>
|
||
<div class="p-3 rounded-xl bg-slate-950 border border-slate-800 text-center">
|
||
<span class="text-[10px] text-slate-400 uppercase block">Temperature</span>
|
||
<span id="gpu-temp-val" class="text-xl font-bold text-emerald-400">0°C</span>
|
||
</div>
|
||
<div class="p-3 rounded-xl bg-slate-950 border border-slate-800 text-center">
|
||
<span class="text-[10px] text-slate-400 uppercase block">Power Draw</span>
|
||
<span id="gpu-power-val" class="text-xl font-bold text-amber-400">0 W</span>
|
||
</div>
|
||
<div class="p-3 rounded-xl bg-slate-950 border border-slate-800 text-center relative overflow-hidden">
|
||
<span class="text-[10px] text-slate-400 uppercase block">Fan Speed</span>
|
||
<div class="flex items-center justify-center space-x-1.5">
|
||
<i id="gpu-fan-icon" class="fa-solid fa-fan text-emerald-400 text-sm"></i>
|
||
<span id="gpu-fan-val" class="text-xl font-bold text-emerald-400">0%</span>
|
||
</div>
|
||
<span id="gpu-fan-sub" class="text-[9px] font-mono text-slate-500 block truncate">Fan 0: --% | Fan 1: --%</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Process Table -->
|
||
<div class="space-y-2">
|
||
<span class="text-xs font-semibold text-slate-400 uppercase font-mono">Active Compute Processes</span>
|
||
<div class="rounded-xl bg-slate-950 border border-slate-800 p-2 max-h-36 overflow-y-auto font-mono text-xs">
|
||
<table class="w-full text-left">
|
||
<thead>
|
||
<tr class="text-slate-500 border-b border-slate-800/80 text-[10px]">
|
||
<th class="pb-1">PID</th>
|
||
<th class="pb-1">Process</th>
|
||
<th class="pb-1 text-right">VRAM</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="gpu-proc-table" class="divide-y divide-slate-900">
|
||
<tr><td colspan="3" class="py-2 text-center text-slate-500">Scanning GPU processes...</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- CARD 4: REAL-TIME SWITCH TIMELINE & OPTIMIZER -->
|
||
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-5 flex flex-col justify-between space-y-4">
|
||
<div>
|
||
<div class="flex items-center justify-between pb-3 border-b border-slate-800">
|
||
<div class="flex items-center space-x-2">
|
||
<div class="p-2 rounded-lg bg-indigo-950/80 border border-indigo-800 text-indigo-400">
|
||
<i class="fa-solid fa-clock-rotate-left text-sm"></i>
|
||
</div>
|
||
<div>
|
||
<h3 class="font-bold text-slate-100 text-sm">Model Switch Timeline & Optimizer</h3>
|
||
<p class="text-xs text-slate-400">Real-time latency logger and memory warmer</p>
|
||
</div>
|
||
</div>
|
||
<button onclick="warmAllModels()" class="px-2.5 py-1 text-xs font-semibold rounded-lg bg-amber-950/70 border border-amber-800 text-amber-300 hover:bg-amber-900 transition flex items-center space-x-1">
|
||
<i class="fa-solid fa-fire text-amber-400"></i>
|
||
<span>Warm All to RAM</span>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Switch Events Log -->
|
||
<div class="mt-4 space-y-2">
|
||
<span class="text-xs font-semibold text-slate-400 uppercase font-mono">Recent Model Swaps</span>
|
||
<div id="switch-log-container" class="space-y-2 max-h-48 overflow-y-auto pr-1">
|
||
<div class="p-3 rounded-xl bg-slate-950 border border-slate-800 text-xs text-slate-400 text-center font-mono">
|
||
No recent model swaps recorded yet.
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Optimizer Banner -->
|
||
<div class="p-3 rounded-xl bg-gradient-to-r from-cyan-950/50 via-slate-950 to-purple-950/50 border border-slate-800 text-xs flex items-center justify-between">
|
||
<div class="flex items-center space-x-2">
|
||
<i class="fa-solid fa-wand-magic-sparkles text-cyan-400"></i>
|
||
<span class="text-slate-300">64GB RAM Cache holds all models in memory</span>
|
||
</div>
|
||
<span class="font-mono text-cyan-400 font-bold">PCIe x16 (~31.5 GB/s)</span>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- OVERCLOCK CONTROL PANEL -->
|
||
<div class="bg-slate-900/80 border border-fuchsia-900/50 rounded-2xl p-5 space-y-4 shadow-lg shadow-fuchsia-950/30">
|
||
<div class="flex flex-wrap items-center justify-between gap-3 pb-3 border-b border-slate-800">
|
||
<div class="flex items-center space-x-2">
|
||
<div class="p-2 rounded-lg bg-fuchsia-950/80 border border-fuchsia-800 text-fuchsia-400">
|
||
<i class="fa-solid fa-rocket text-sm"></i>
|
||
</div>
|
||
<div>
|
||
<h3 class="font-bold text-slate-100 text-sm">GPU Overclock Control</h3>
|
||
<p class="text-xs text-slate-400">Per-app profiles auto-switch with the VRAM arbitrator</p>
|
||
</div>
|
||
</div>
|
||
<div class="flex items-center space-x-2">
|
||
<span id="oc-active-badge" class="px-2.5 py-1 text-xs font-mono rounded-lg bg-slate-800 border border-slate-700 text-slate-300">Active: --</span>
|
||
<span id="oc-x-badge" class="px-2.5 py-1 text-xs font-mono rounded-lg bg-slate-800 border border-slate-700 text-slate-400">X: --</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Profile quick-select -->
|
||
<div class="grid grid-cols-3 gap-3">
|
||
<button id="oc-btn-ollama" onclick="applyOverclock('ollama')" class="py-2.5 rounded-xl border text-xs font-bold transition flex items-center justify-center space-x-2 bg-purple-950/60 border-purple-800 text-purple-300 hover:bg-purple-900/60">
|
||
<i class="fa-solid fa-brain"></i><span>Ollama</span>
|
||
</button>
|
||
<button id="oc-btn-comfy" onclick="applyOverclock('comfy')" class="py-2.5 rounded-xl border text-xs font-bold transition flex items-center justify-center space-x-2 bg-cyan-950/60 border-cyan-800 text-cyan-300 hover:bg-cyan-900/60">
|
||
<i class="fa-solid fa-palette"></i><span>ComfyUI</span>
|
||
</button>
|
||
<button id="oc-btn-balanced" onclick="applyOverclock('balanced')" class="py-2.5 rounded-xl border text-xs font-bold transition flex items-center justify-center space-x-2 bg-slate-800/60 border-slate-700 text-slate-300 hover:bg-slate-700/60">
|
||
<i class="fa-solid fa-scale-balanced"></i><span>Balanced</span>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Live status readback -->
|
||
<div class="grid grid-cols-2 sm:grid-cols-4 gap-3 font-mono text-center">
|
||
<div class="p-3 rounded-xl bg-slate-950 border border-slate-800">
|
||
<span class="text-[10px] text-slate-400 uppercase block">Power Limit</span>
|
||
<span id="oc-power-limit" class="text-lg font-bold text-amber-400">-- W</span>
|
||
</div>
|
||
<div class="p-3 rounded-xl bg-slate-950 border border-slate-800">
|
||
<span class="text-[10px] text-slate-400 uppercase block">Core Clock</span>
|
||
<span id="oc-core" class="text-lg font-bold text-cyan-400">--</span>
|
||
</div>
|
||
<div class="p-3 rounded-xl bg-slate-950 border border-slate-800">
|
||
<span class="text-[10px] text-slate-400 uppercase block">Mem Clock</span>
|
||
<span id="oc-mem" class="text-lg font-bold text-purple-400">--</span>
|
||
</div>
|
||
<div class="p-3 rounded-xl bg-slate-950 border border-slate-800">
|
||
<span class="text-[10px] text-slate-400 uppercase block">Temp / Draw</span>
|
||
<span id="oc-temp-draw" class="text-lg font-bold text-emerald-400">--</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- GPU FAN COOLING CONTROL -->
|
||
<div class="p-4 rounded-xl bg-slate-950 border border-slate-800 space-y-4">
|
||
<div class="flex flex-wrap items-center justify-between gap-2">
|
||
<div class="flex items-center space-x-2">
|
||
<i id="oc-fan-card-icon" class="fa-solid fa-fan text-emerald-400 text-sm fan-spinning"></i>
|
||
<div>
|
||
<span class="text-xs font-semibold text-slate-200 uppercase font-mono block">GPU Fan Cooling Control</span>
|
||
<span class="text-[10px] text-slate-400 font-mono">Dual-fan PWM active speed regulation</span>
|
||
</div>
|
||
</div>
|
||
<span id="oc-fan-badge" class="px-2.5 py-1 text-xs font-mono rounded-lg bg-emerald-950/80 border border-emerald-700 text-emerald-300 font-bold">
|
||
AUTO (VBIOS)
|
||
</span>
|
||
</div>
|
||
|
||
<!-- Fan Presets -->
|
||
<div class="grid grid-cols-2 sm:grid-cols-5 gap-2">
|
||
<button onclick="setFanAuto()" class="py-1.5 px-2 rounded-lg bg-slate-900 hover:bg-slate-800 border border-slate-700 text-slate-300 text-xs font-mono font-semibold transition text-center flex items-center justify-center space-x-1">
|
||
<i class="fa-solid fa-wand-magic-sparkles text-cyan-400 text-[10px]"></i>
|
||
<span>Auto (VBIOS)</span>
|
||
</button>
|
||
<button onclick="setFanManual(50)" class="py-1.5 px-2 rounded-lg bg-slate-900 hover:bg-slate-800 border border-slate-700 text-slate-300 text-xs font-mono font-semibold transition text-center">
|
||
50% Quiet
|
||
</button>
|
||
<button onclick="setFanManual(65)" class="py-1.5 px-2 rounded-lg bg-slate-900 hover:bg-slate-800 border border-slate-700 text-slate-300 text-xs font-mono font-semibold transition text-center">
|
||
65% Balanced
|
||
</button>
|
||
<button onclick="setFanManual(80)" class="py-1.5 px-2 rounded-lg bg-slate-900 hover:bg-slate-800 border border-slate-700 text-slate-300 text-xs font-mono font-semibold transition text-center">
|
||
80% Heavy
|
||
</button>
|
||
<button onclick="setFanManual(100)" class="py-1.5 px-2 rounded-lg bg-rose-950/60 hover:bg-rose-900/80 border border-rose-800 text-rose-300 text-xs font-mono font-bold transition text-center flex items-center justify-center space-x-1">
|
||
<i class="fa-solid fa-gauge-max text-rose-400 text-[10px]"></i>
|
||
<span>100% Turbo</span>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Live Dual-Fan Meters -->
|
||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3 p-3 rounded-lg bg-slate-900/60 border border-slate-800/80 text-xs font-mono">
|
||
<div class="space-y-1">
|
||
<div class="flex justify-between text-slate-400">
|
||
<span class="flex items-center space-x-1"><i class="fa-solid fa-fan text-[10px] text-cyan-400"></i><span>Fan 0 (Intake/Core):</span></span>
|
||
<span id="oc-fan0-val" class="font-bold text-slate-100">--%</span>
|
||
</div>
|
||
<div class="w-full bg-slate-950 rounded-full h-2 overflow-hidden border border-slate-800">
|
||
<div id="oc-fan0-bar" class="bg-gradient-to-r from-cyan-500 to-emerald-400 h-full rounded-full transition-all duration-300" style="width: 0%"></div>
|
||
</div>
|
||
</div>
|
||
<div class="space-y-1">
|
||
<div class="flex justify-between text-slate-400">
|
||
<span class="flex items-center space-x-1"><i class="fa-solid fa-fan text-[10px] text-purple-400"></i><span>Fan 1 (Exhaust/VRM):</span></span>
|
||
<span id="oc-fan1-val" class="font-bold text-slate-100">--%</span>
|
||
</div>
|
||
<div class="w-full bg-slate-950 rounded-full h-2 overflow-hidden border border-slate-800">
|
||
<div id="oc-fan1-bar" class="bg-gradient-to-r from-purple-500 to-emerald-400 h-full rounded-full transition-all duration-300" style="width: 0%"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Custom Manual Slider -->
|
||
<div class="space-y-2">
|
||
<div class="flex justify-between items-center text-xs">
|
||
<span class="text-slate-400">Custom Manual Target:</span>
|
||
<span id="oc-fan-slider-label" class="font-mono text-emerald-400 font-bold">65%</span>
|
||
</div>
|
||
<div class="flex items-center space-x-3">
|
||
<input id="oc-fan-slider" type="range" min="30" max="100" step="1" value="65" oninput="document.getElementById('oc-fan-slider-label').textContent=this.value+'%'" class="flex-1 accent-emerald-500">
|
||
<button onclick="setFanManual(parseInt(document.getElementById('oc-fan-slider').value))" class="px-3.5 py-1.5 rounded-lg bg-gradient-to-r from-emerald-600 to-teal-600 hover:from-emerald-500 hover:to-teal-500 text-white text-xs font-bold font-mono shadow transition flex items-center space-x-1">
|
||
<i class="fa-solid fa-check"></i>
|
||
<span>Apply</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- GPU SPECS STRIP -->
|
||
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-2 font-mono text-center">
|
||
<div class="p-2 rounded-lg bg-slate-950 border border-slate-800">
|
||
<span class="text-[9px] text-slate-500 uppercase block">GPU</span>
|
||
<span id="oc-spec-gpu" class="text-[11px] font-bold text-slate-200 block truncate">--</span>
|
||
</div>
|
||
<div class="p-2 rounded-lg bg-slate-950 border border-slate-800">
|
||
<span class="text-[9px] text-slate-500 uppercase block">Driver</span>
|
||
<span id="oc-spec-driver" class="text-[11px] font-bold text-cyan-400 block">--</span>
|
||
</div>
|
||
<div class="p-2 rounded-lg bg-slate-950 border border-slate-800">
|
||
<span class="text-[9px] text-slate-500 uppercase block">VRAM</span>
|
||
<span id="oc-spec-vram" class="text-[11px] font-bold text-purple-400 block">--</span>
|
||
</div>
|
||
<div class="p-2 rounded-lg bg-slate-950 border border-slate-800">
|
||
<span class="text-[9px] text-slate-500 uppercase block">Max Core</span>
|
||
<span id="oc-spec-maxcore" class="text-[11px] font-bold text-cyan-400 block">--</span>
|
||
</div>
|
||
<div class="p-2 rounded-lg bg-slate-950 border border-slate-800">
|
||
<span class="text-[9px] text-slate-500 uppercase block">Max Mem</span>
|
||
<span id="oc-spec-maxmem" class="text-[11px] font-bold text-purple-400 block">--</span>
|
||
</div>
|
||
<div class="p-2 rounded-lg bg-slate-950 border border-slate-800">
|
||
<span class="text-[9px] text-slate-500 uppercase block">Power</span>
|
||
<span id="oc-spec-power" class="text-[11px] font-bold text-amber-400 block">--</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- LIVE TIME-SERIES GRAPH (clocks + temp + fan) -->
|
||
<div class="rounded-xl bg-slate-950 border border-slate-800 p-3">
|
||
<div class="flex items-center justify-between mb-2">
|
||
<span class="text-xs font-semibold text-slate-300 uppercase font-mono">
|
||
<i class="fa-solid fa-chart-line text-fuchsia-400 mr-1"></i>Live Tuning Graph
|
||
</span>
|
||
<div class="flex flex-wrap items-center gap-x-3 gap-y-1 text-[10px] font-mono">
|
||
<span class="flex items-center space-x-1"><span class="w-2 h-2 rounded-full bg-cyan-400 inline-block"></span>Core MHz</span>
|
||
<span class="flex items-center space-x-1"><span class="w-2 h-2 rounded-full bg-purple-400 inline-block"></span>Mem MHz</span>
|
||
<span class="flex items-center space-x-1"><span class="w-2 h-2 rounded-full bg-rose-400 inline-block"></span>Temp °C</span>
|
||
<span class="flex items-center space-x-1"><span class="w-2 h-2 rounded-full bg-amber-400 inline-block"></span>Power W</span>
|
||
<span class="flex items-center space-x-1"><span class="w-2 h-2 rounded-full bg-emerald-400 inline-block"></span>Fan %</span>
|
||
<span class="flex items-center space-x-1"><span class="w-2 h-2 rounded-full bg-indigo-400 inline-block"></span>VRAM GB</span>
|
||
<span class="flex items-center space-x-1"><span class="w-2 h-2 rounded-full bg-fuchsia-400 inline-block"></span>RAM Cache GB</span>
|
||
</div>
|
||
</div>
|
||
<div class="relative h-64">
|
||
<canvas id="oc-chart"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Fine-tune sliders for the selected profile -->
|
||
<div class="p-4 rounded-xl bg-slate-950 border border-slate-800 space-y-4">
|
||
<div class="flex items-center justify-between">
|
||
<span class="text-xs font-semibold text-slate-300 uppercase font-mono">Fine-tune profile</span>
|
||
<select id="oc-edit-profile" onchange="loadOverclockForProfile(this.value)" class="bg-slate-900 border border-slate-700 rounded-lg px-2 py-1 text-xs font-mono text-slate-200 focus:outline-none focus:border-fuchsia-500">
|
||
<option value="ollama">ollama</option>
|
||
<option value="comfy">comfy</option>
|
||
<option value="balanced">balanced</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="grid grid-cols-1 md:grid-cols-3 gap-5">
|
||
<div>
|
||
<label class="text-xs text-slate-400 flex justify-between"><span>Power Limit</span><span id="oc-val-power" class="font-mono text-amber-400">370 W</span></label>
|
||
<input id="oc-slider-power" type="range" min="150" max="370" step="5" value="370" oninput="document.getElementById('oc-val-power').textContent=this.value+' W'" class="w-full accent-amber-500">
|
||
</div>
|
||
<div>
|
||
<label class="text-xs text-slate-400 flex justify-between"><span>Core Offset</span><span id="oc-val-core" class="font-mono text-cyan-400">+100 MHz</span></label>
|
||
<input id="oc-slider-core" type="range" min="0" max="200" step="5" value="100" oninput="document.getElementById('oc-val-core').textContent='+'+this.value+' MHz'" class="w-full accent-cyan-500">
|
||
</div>
|
||
<div>
|
||
<label class="text-xs text-slate-400 flex justify-between"><span>Memory Offset</span><span id="oc-val-mem" class="font-mono text-purple-400">+500 MHz</span></label>
|
||
<input id="oc-slider-mem" type="range" min="0" max="1000" step="25" value="500" oninput="document.getElementById('oc-val-mem').textContent='+'+this.value+' MHz'" class="w-full accent-purple-500">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||
<div>
|
||
<label class="text-xs text-slate-400 flex justify-between"><span>Core Clock Lock</span><span id="oc-val-lockcore" class="font-mono text-slate-400">Off</span></label>
|
||
<div class="flex items-center space-x-2">
|
||
<input id="oc-lockcore-toggle" type="checkbox" onchange="toggleCoreLock()" class="w-4 h-4 accent-cyan-500">
|
||
<span class="text-xs text-slate-500">Lock core to max boost (2900–3105 MHz)</span>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<label class="text-xs text-slate-400 flex justify-between"><span>Memory Clock Lock</span><span id="oc-val-lockmem" class="font-mono text-slate-400">Off</span></label>
|
||
<div class="flex items-center space-x-2">
|
||
<input id="oc-lockmem-toggle" type="checkbox" onchange="toggleMemLock()" class="w-4 h-4 accent-purple-500">
|
||
<span class="text-xs text-slate-500">Lock mem to max (11501 MHz)</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Per-Profile Fan Settings -->
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-5 pt-3 border-t border-slate-900">
|
||
<div>
|
||
<label class="text-xs text-slate-400 flex justify-between"><span>Profile Fan Mode</span><span id="oc-val-prof-fanmode" class="font-mono text-emerald-400">Auto</span></label>
|
||
<select id="oc-prof-fanmode" onchange="toggleProfileFanMode()" class="w-full bg-slate-900 border border-slate-700 rounded-lg px-3 py-2 text-xs font-mono text-slate-200 mt-1 focus:outline-none focus:border-emerald-500">
|
||
<option value="auto">Auto (VBIOS Dynamic Curve)</option>
|
||
<option value="manual">Manual (Locked Target %)</option>
|
||
</select>
|
||
</div>
|
||
<div id="oc-prof-fanspeed-container" class="opacity-50 pointer-events-none transition">
|
||
<label class="text-xs text-slate-400 flex justify-between"><span>Profile Fan Target</span><span id="oc-val-prof-fanspeed" class="font-mono text-emerald-400">70%</span></label>
|
||
<input id="oc-slider-prof-fanspeed" type="range" min="30" max="100" step="5" value="70" oninput="document.getElementById('oc-val-prof-fanspeed').textContent=this.value+'%'" class="w-full accent-emerald-500 mt-2">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="flex items-center justify-between pt-2">
|
||
<span id="oc-offset-note" class="text-[11px] font-mono text-slate-500"></span>
|
||
<button onclick="saveOverclockProfile()" class="px-4 py-2 bg-gradient-to-r from-fuchsia-600 to-purple-600 hover:from-fuchsia-500 hover:to-purple-500 text-white text-xs font-bold rounded-lg shadow-md transition flex items-center space-x-1.5">
|
||
<i class="fa-solid fa-floppy-disk"></i><span>Save Profile</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ============ NEXT-LEVEL PANELS: governor / residency / analytics / autotune ============ -->
|
||
<div class="grid grid-cols-1 xl:grid-cols-2 gap-5 mt-5">
|
||
|
||
|
||
<!-- System health: makes a silently-broken dependency loud -->
|
||
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-5 xl:col-span-2">
|
||
<div class="flex items-center justify-between pb-3 border-b border-slate-800">
|
||
<div class="flex items-center space-x-2">
|
||
<div class="p-2 rounded-lg bg-sky-950/80 border border-sky-800 text-sky-400">
|
||
<i class="fa-solid fa-stethoscope text-sm"></i>
|
||
</div>
|
||
<div>
|
||
<h3 class="font-bold text-slate-100 text-sm">System Health</h3>
|
||
<p class="text-xs text-slate-400">Every dependency, with impact and how to fix it</p>
|
||
</div>
|
||
</div>
|
||
<div class="flex items-center space-x-2">
|
||
<span id="health-badge" class="px-2 py-1 text-xs font-bold rounded-lg bg-slate-800 text-slate-400">checking…</span>
|
||
<button onclick="fetchHealth(true)" class="px-2.5 py-1 text-xs font-semibold rounded-lg bg-slate-800 border border-slate-700 text-slate-300 hover:bg-slate-700 transition">Recheck</button>
|
||
</div>
|
||
</div>
|
||
<div id="health-body" class="mt-4 space-y-1.5 text-[11px] font-mono"></div>
|
||
</div>
|
||
|
||
<!-- VRAM Arbitration — the core handoff, previously invisible -->
|
||
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-5 xl:col-span-2">
|
||
<div class="flex items-center justify-between pb-3 border-b border-slate-800">
|
||
<div class="flex items-center space-x-2">
|
||
<div class="p-2 rounded-lg bg-emerald-950/80 border border-emerald-800 text-emerald-400">
|
||
<i class="fa-solid fa-right-left text-sm"></i>
|
||
</div>
|
||
<div>
|
||
<h3 class="font-bold text-slate-100 text-sm">VRAM Arbitration</h3>
|
||
<p class="text-xs text-slate-400">Who holds the GPU, and how handoffs are going</p>
|
||
</div>
|
||
</div>
|
||
<span id="arb-ws" class="text-xs font-mono text-slate-500">—</span>
|
||
</div>
|
||
<div class="mt-4">
|
||
<div id="arb-action" class="text-sm text-slate-200 bg-slate-950/60 border border-slate-800 rounded-lg px-3 py-2 mb-3 font-mono">Idle</div>
|
||
<div id="arb-backoff" class="text-[11px] font-mono text-amber-400 mb-3"></div>
|
||
<div id="arb-unmanaged" class="text-[11px] font-mono text-slate-400 mb-3"></div>
|
||
<div class="grid grid-cols-3 sm:grid-cols-6 gap-2 text-center">
|
||
<div class="bg-slate-950/60 rounded-lg p-2 border border-slate-800">
|
||
<div id="arb-yields" class="text-lg font-bold text-emerald-400">0</div>
|
||
<div class="text-[10px] text-slate-500 uppercase leading-tight">Released</div>
|
||
</div>
|
||
<div class="bg-slate-950/60 rounded-lg p-2 border border-slate-800">
|
||
<div id="arb-busy" class="text-lg font-bold text-cyan-400">0</div>
|
||
<div class="text-[10px] text-slate-500 uppercase leading-tight">Deferred<br>(busy)</div>
|
||
</div>
|
||
<div class="bg-slate-950/60 rounded-lg p-2 border border-slate-800">
|
||
<div id="arb-later" class="text-lg font-bold text-cyan-400">0</div>
|
||
<div class="text-[10px] text-slate-500 uppercase leading-tight">Landed<br>later</div>
|
||
</div>
|
||
<div class="bg-slate-950/60 rounded-lg p-2 border border-slate-800">
|
||
<div id="arb-stalled" class="text-lg font-bold text-rose-400">0</div>
|
||
<div class="text-[10px] text-slate-500 uppercase leading-tight">Stalled</div>
|
||
</div>
|
||
<div class="bg-slate-950/60 rounded-lg p-2 border border-slate-800">
|
||
<div id="arb-purges" class="text-lg font-bold text-fuchsia-400">0</div>
|
||
<div class="text-[10px] text-slate-500 uppercase leading-tight">Comfy<br>purges</div>
|
||
</div>
|
||
<div class="bg-slate-950/60 rounded-lg p-2 border border-slate-800">
|
||
<div id="arb-defpurge" class="text-lg font-bold text-slate-300">0</div>
|
||
<div class="text-[10px] text-slate-500 uppercase leading-tight">Purges<br>deferred</div>
|
||
</div>
|
||
</div>
|
||
<p class="text-[11px] text-slate-500 mt-3">
|
||
<span class="text-cyan-400">Deferred</span> is healthy — an LLM mid-generation cannot unload, so the
|
||
request queues and applies the moment it finishes. Only <span class="text-rose-400">stalled</span>
|
||
(VRAM held while the GPU sits idle) indicates a real problem.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Thermal Governor -->
|
||
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-5">
|
||
<div class="flex items-center justify-between pb-3 border-b border-slate-800">
|
||
<div class="flex items-center space-x-2">
|
||
<div class="p-2 rounded-lg bg-rose-950/80 border border-rose-800 text-rose-400">
|
||
<i class="fa-solid fa-temperature-arrow-down text-sm"></i>
|
||
</div>
|
||
<div>
|
||
<h3 class="font-bold text-slate-100 text-sm">Thermal Governor</h3>
|
||
<p class="text-xs text-slate-400">Walks the overclock back when the card complains</p>
|
||
</div>
|
||
</div>
|
||
<div class="flex items-center space-x-2">
|
||
<button onclick="toggleGovernor()" id="gov-toggle" class="px-2.5 py-1 text-xs font-semibold rounded-lg bg-slate-800 border border-slate-700 text-slate-300 hover:bg-slate-700 transition">Enabled</button>
|
||
<button onclick="resetGovernor()" class="px-2.5 py-1 text-xs font-semibold rounded-lg bg-slate-800 border border-slate-700 text-slate-300 hover:bg-slate-700 transition">Reset</button>
|
||
</div>
|
||
</div>
|
||
<div class="mt-4 space-y-3">
|
||
<div class="flex items-baseline justify-between">
|
||
<span id="gov-label" class="text-2xl font-bold text-emerald-400">full</span>
|
||
<span id="gov-level" class="text-xs font-mono text-slate-500">level 0 / 3</span>
|
||
</div>
|
||
<div class="w-full bg-slate-950 rounded-full h-2 overflow-hidden border border-slate-800">
|
||
<div id="gov-bar" class="h-full bg-gradient-to-r from-emerald-500 to-rose-500 transition-all duration-500" style="width:0%"></div>
|
||
</div>
|
||
<div class="grid grid-cols-3 gap-2 text-center pt-1">
|
||
<div class="bg-slate-950/60 rounded-lg p-2 border border-slate-800">
|
||
<div class="text-[10px] text-slate-500 uppercase">Escalate</div>
|
||
<div id="gov-esc" class="text-sm font-mono text-rose-400">83°C</div>
|
||
</div>
|
||
<div class="bg-slate-950/60 rounded-lg p-2 border border-slate-800">
|
||
<div class="text-[10px] text-slate-500 uppercase">Recover</div>
|
||
<div id="gov-rec" class="text-sm font-mono text-cyan-400">72°C</div>
|
||
</div>
|
||
<div class="bg-slate-950/60 rounded-lg p-2 border border-slate-800">
|
||
<div class="text-[10px] text-slate-500 uppercase">Offset Scale</div>
|
||
<div id="gov-scale" class="text-sm font-mono text-slate-300">100%</div>
|
||
</div>
|
||
</div>
|
||
<p class="text-xs text-slate-400"><span class="text-slate-500">Last action:</span> <span id="gov-reason" class="font-mono">cold start</span></p>
|
||
<div id="gov-history" class="space-y-1 max-h-24 overflow-y-auto text-[11px] font-mono"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Measured page-cache residency -->
|
||
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-5">
|
||
<div class="flex items-center justify-between pb-3 border-b border-slate-800">
|
||
<div class="flex items-center space-x-2">
|
||
<div class="p-2 rounded-lg bg-amber-950/80 border border-amber-800 text-amber-400">
|
||
<i class="fa-solid fa-memory text-sm"></i>
|
||
</div>
|
||
<div>
|
||
<h3 class="font-bold text-slate-100 text-sm">Measured Page-Cache Residency</h3>
|
||
<p class="text-xs text-slate-400">What is genuinely in RAM, not what we hope is</p>
|
||
</div>
|
||
</div>
|
||
<div class="flex items-center space-x-2">
|
||
<button onclick="fetchWarmPlan()" class="px-2.5 py-1 text-xs font-semibold rounded-lg bg-slate-800 border border-slate-700 text-slate-300 hover:bg-slate-700 transition">Plan</button>
|
||
<button onclick="fetchCacheReport(true)" class="px-2.5 py-1 text-xs font-semibold rounded-lg bg-amber-950/70 border border-amber-800 text-amber-300 hover:bg-amber-900 transition">Rescan</button>
|
||
</div>
|
||
</div>
|
||
<div class="mt-4">
|
||
<div class="flex items-baseline justify-between mb-2">
|
||
<span id="cache-total" class="text-2xl font-bold text-amber-400">— GB</span>
|
||
<span id="cache-meta" class="text-xs font-mono text-slate-500">—</span>
|
||
</div>
|
||
<div id="cache-capability" class="text-[11px] text-slate-500 mb-3"></div>
|
||
<div id="cache-files" class="space-y-1.5 max-h-56 overflow-y-auto pr-1"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Profile analytics -->
|
||
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-5">
|
||
<div class="flex items-center justify-between pb-3 border-b border-slate-800">
|
||
<div class="flex items-center space-x-2">
|
||
<div class="p-2 rounded-lg bg-cyan-950/80 border border-cyan-800 text-cyan-400">
|
||
<i class="fa-solid fa-chart-column text-sm"></i>
|
||
</div>
|
||
<div>
|
||
<h3 class="font-bold text-slate-100 text-sm">Is the Overclock Actually Working?</h3>
|
||
<p class="text-xs text-slate-400">Decode throughput per profile, from persisted history</p>
|
||
</div>
|
||
</div>
|
||
<select id="analytics-days" onchange="fetchAnalytics()" class="bg-slate-950 border border-slate-700 text-xs text-slate-300 rounded-lg px-2 py-1">
|
||
<option value="1">24h</option><option value="7" selected>7d</option><option value="30">30d</option>
|
||
</select>
|
||
</div>
|
||
<div id="analytics-body" class="mt-4 text-xs text-slate-400">Collecting data…</div>
|
||
</div>
|
||
|
||
<!-- Autotune -->
|
||
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-5">
|
||
<div class="flex items-center justify-between pb-3 border-b border-slate-800">
|
||
<div class="flex items-center space-x-2">
|
||
<div class="p-2 rounded-lg bg-fuchsia-950/80 border border-fuchsia-800 text-fuchsia-400">
|
||
<i class="fa-solid fa-wave-square text-sm"></i>
|
||
</div>
|
||
<div>
|
||
<h3 class="font-bold text-slate-100 text-sm">Overclock Autotune</h3>
|
||
<p class="text-xs text-slate-400">Sweep a clock offset, measure tok/s, stop at instability</p>
|
||
</div>
|
||
</div>
|
||
<span id="autotune-state" class="text-xs font-mono text-slate-500">idle</span>
|
||
</div>
|
||
<div class="mt-4 grid grid-cols-2 gap-3">
|
||
<label class="text-xs text-slate-400">Knob
|
||
<select id="at-knob" class="w-full mt-1 bg-slate-950 border border-slate-700 text-slate-300 rounded-lg px-2 py-1.5">
|
||
<option value="mem_offset_mhz">Memory offset</option>
|
||
<option value="core_offset_mhz">Core offset</option>
|
||
</select>
|
||
</label>
|
||
<label class="text-xs text-slate-400">Profile
|
||
<select id="at-profile" class="w-full mt-1 bg-slate-950 border border-slate-700 text-slate-300 rounded-lg px-2 py-1.5">
|
||
<option value="ollama">ollama</option><option value="comfy">comfy</option><option value="balanced">balanced</option>
|
||
</select>
|
||
</label>
|
||
<label class="text-xs text-slate-400">Start<input id="at-start" type="number" value="0" class="w-full mt-1 bg-slate-950 border border-slate-700 text-slate-300 rounded-lg px-2 py-1.5 font-mono"></label>
|
||
<label class="text-xs text-slate-400">Stop<input id="at-stop" type="number" value="600" class="w-full mt-1 bg-slate-950 border border-slate-700 text-slate-300 rounded-lg px-2 py-1.5 font-mono"></label>
|
||
<label class="text-xs text-slate-400">Step<input id="at-step" type="number" value="150" class="w-full mt-1 bg-slate-950 border border-slate-700 text-slate-300 rounded-lg px-2 py-1.5 font-mono"></label>
|
||
<label class="text-xs text-slate-400 flex items-end space-x-2 pb-1">
|
||
<input id="at-apply" type="checkbox" class="accent-fuchsia-500"><span>Save winner to profile</span>
|
||
</label>
|
||
</div>
|
||
<div class="flex items-center space-x-2 mt-3">
|
||
<button onclick="runSweep()" id="at-run" class="px-4 py-2 bg-gradient-to-r from-fuchsia-600 to-purple-600 hover:from-fuchsia-500 hover:to-purple-500 text-white text-xs font-bold rounded-lg shadow-md transition">
|
||
<i class="fa-solid fa-play mr-1"></i>Run Sweep
|
||
</button>
|
||
<button onclick="cancelSweep()" class="px-3 py-2 bg-slate-800 border border-slate-700 text-slate-300 text-xs font-semibold rounded-lg hover:bg-slate-700 transition">Cancel</button>
|
||
<span class="text-[11px] text-slate-500">Restores the profile when done, even on error.</span>
|
||
</div>
|
||
<div id="autotune-body" class="mt-3 text-xs"></div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</main>
|
||
|
||
<script src="/static/app.js"></script>
|
||
</body>
|
||
</html>
|