Stop the dashboard reporting things that are not true
A screenshot of the running dashboard showed four claims that the backend does not support. Each is the same failure the rest of this branch has been correcting: displaying a number without checking what it measures. "Models in RAM: 54.31 GB" was ram.cached_gb -- the entire Linux page cache, every file the kernel has cached, not models. Measured model residency at the same moment was 42.87 GB of a 331 GB catalogue. The two are different quantities that happened to look similar. The legend now says "Page Cache (all files)" for what that number is, and shows measured model residency separately beside it. "LAST SWAP TIME 1.65 ms" and "RAM HIT STATUS: Cleaned" were read from history[0], the most recent event of any type. Both tiles were describing a ComfyUI VRAM purge: its duration under a swap-time label, its status under a cache-hit label. They now select the most recent LLM Model Switch, and fall back to the persisted log when the in-memory ring is empty, so a restart no longer blanks them. "Host Pinned Memory: 53.6 GB Staging Buffer", "Async PCIe Offloading: Enabled (2 Streams)" and "Fast Disk RAM Mmap: Active" were hardcoded in the HTML and measured from nothing at all. Replaced with values the service actually has: VRAM currently held by ComfyUI, live PCIe throughput from NVML, measured checkpoint residency, and the real idle-purge countdown. Also: the VRAM legend's "System" bucket hid an 842 MB third-party process behind the same label as a 3.9 MB compositor, so it is now split into Desktop and Unmanaged; and the version badge read a hardcoded "v1.0-DEPLOY" while the API served 2.0.0, so it now reads the version from /openapi.json. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -154,6 +154,29 @@ function updateDashboard(data) {
|
||||
|
||||
document.getElementById('legend-ram-used').textContent = `${ram.used_gb || 0} GB`;
|
||||
document.getElementById('legend-ram-cached').textContent = `${ram.cached_gb || 0} GB`;
|
||||
|
||||
// Split the old catch-all: desktop compositor vs VRAM we cannot reclaim.
|
||||
const vbd = gpu.breakdown || {};
|
||||
const unmanagedEl = document.getElementById('legend-vram-unmanaged');
|
||||
if (unmanagedEl) unmanagedEl.textContent = `${vbd.unmanaged_gb ?? 0} GB`;
|
||||
const sysEl = document.getElementById('legend-system');
|
||||
if (sysEl) sysEl.textContent = `${vbd.desktop_gb ?? 0} GB`;
|
||||
|
||||
// Measured ComfyUI facts, replacing the panel's previously hardcoded ones.
|
||||
const held = document.getElementById('comfy-vram-held');
|
||||
if (held) held.textContent = `${vbd.comfyui_gb ?? 0} GB`;
|
||||
const pcie = document.getElementById('comfy-pcie');
|
||||
if (pcie) {
|
||||
const tx = (gpu.pcie_tx_kbps || 0) / 1024, rx = (gpu.pcie_rx_kbps || 0) / 1024;
|
||||
pcie.textContent = `${tx.toFixed(1)} / ${rx.toFixed(1)} MB/s`;
|
||||
}
|
||||
const purge = document.getElementById('comfy-purge-state');
|
||||
if (purge && data.arbitrator) {
|
||||
const a = data.arbitrator;
|
||||
purge.textContent = a.pending_purge && a.comfy_idle_s != null
|
||||
? `in ${Math.max((a.idle_purge_after_s || 0) - a.comfy_idle_s, 0).toFixed(0)}s`
|
||||
: (a.comfy_active ? 'generating' : 'idle');
|
||||
}
|
||||
document.getElementById('legend-ram-free').textContent = `${ram.free_gb || 0} GB`;
|
||||
}
|
||||
|
||||
@@ -225,9 +248,14 @@ function updateDashboard(data) {
|
||||
const history = data.history || [];
|
||||
const logContainer = document.getElementById('switch-log-container');
|
||||
if (history.length > 0) {
|
||||
const latest = history[0];
|
||||
document.getElementById('ollama-last-swap').textContent = `${latest.duration_ms} ms`;
|
||||
document.getElementById('ollama-cache-hit').textContent = latest.cache_status || 'OK';
|
||||
// These tiles are labelled "last swap time" and "RAM hit status", so they must come
|
||||
// from an actual model swap. Reading history[0] meant a ComfyUI purge showed its
|
||||
// 1.65 ms duration as the swap time and its "Cleaned" status as a cache result.
|
||||
const lastSwap = history.find(h => h.event_type === 'LLM Model Switch');
|
||||
document.getElementById('ollama-last-swap').textContent =
|
||||
lastSwap ? `${lastSwap.duration_ms} ms` : '\u2014';
|
||||
document.getElementById('ollama-cache-hit').textContent =
|
||||
lastSwap ? (lastSwap.cache_status || 'OK') : 'no swaps yet';
|
||||
|
||||
logContainer.innerHTML = history.slice(0, 10).map(item => {
|
||||
const isHit = (item.cache_status || '').includes('RAM Cache Hit') || (item.cache_status || '').includes('RAM-Cached');
|
||||
@@ -976,3 +1004,68 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
fetchHealth(false);
|
||||
setInterval(() => fetchHealth(false), 60000);
|
||||
});
|
||||
|
||||
|
||||
// ---------------------------------------------------------------- honest labels
|
||||
|
||||
async function fetchMeasuredResidency() {
|
||||
const el = document.getElementById('legend-models-resident');
|
||||
if (!el) return;
|
||||
try {
|
||||
const d = await (await fetch('/api/cache/report?files=false')).json();
|
||||
// Deliberately distinct from the page-cache figure beside it: that is every file
|
||||
// the kernel has cached; this is model weights, measured.
|
||||
el.textContent = `${d.resident_total_gb} GB of ${d.catalog_total_gb} GB`;
|
||||
const cr = document.getElementById('comfy-resident');
|
||||
if (cr) cr.textContent = `${d.residency_pct}%`;
|
||||
} catch (e) {
|
||||
el.textContent = 'unavailable';
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchVersion() {
|
||||
const el = document.getElementById('app-version');
|
||||
if (!el) return;
|
||||
try {
|
||||
const d = await (await fetch('/openapi.json')).json();
|
||||
el.textContent = `v${d.info.version}`;
|
||||
} catch (e) {
|
||||
el.textContent = 'v?';
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
fetchVersion();
|
||||
fetchMeasuredResidency();
|
||||
setInterval(fetchMeasuredResidency, 30000);
|
||||
});
|
||||
|
||||
|
||||
// ---------------------------------------------------------------- durable swap stats
|
||||
|
||||
let lastSwapFromStore = null;
|
||||
|
||||
async function fetchLastSwapFromStore() {
|
||||
// The in-memory ring empties on restart, which blanked the swap tiles even though
|
||||
// every swap is on disk. Fall back to the persisted log so a restart does not erase
|
||||
// what the dashboard knows.
|
||||
try {
|
||||
const rows = await (await fetch('/api/history?durable=true&limit=50')).json();
|
||||
const swap = (rows || []).find(r => r.event_type === 'LLM Model Switch');
|
||||
if (!swap) return;
|
||||
lastSwapFromStore = swap;
|
||||
const t = document.getElementById('ollama-last-swap');
|
||||
const c = document.getElementById('ollama-cache-hit');
|
||||
if (t && (!t.textContent || t.textContent.includes('\u2014') || t.textContent.includes('--'))) {
|
||||
t.textContent = `${Math.round(swap.duration_ms)} ms`;
|
||||
}
|
||||
if (c && (!c.textContent || c.textContent.includes('\u2014') || c.textContent.includes('--')
|
||||
|| c.textContent === 'no swaps yet')) {
|
||||
c.textContent = swap.cache_status || 'OK';
|
||||
}
|
||||
} catch (e) { /* the live stream is the primary source; this is only a fallback */ }
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
setTimeout(fetchLastSwapFromStore, 1500);
|
||||
});
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
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 id="app-version">v...</span>
|
||||
</span>
|
||||
</div>
|
||||
<p class="text-xs text-slate-400 font-mono">NVIDIA RTX 4080 SUPER 16GB // 64GB DDR5 RAM // Ubuntu Linux</p>
|
||||
@@ -115,9 +115,14 @@
|
||||
</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 class="text-slate-400" title="Desktop compositor and display server">Desktop:</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" title="Held by processes HyperSwap cannot reclaim">Unmanaged:</span>
|
||||
<span id="legend-vram-unmanaged" 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:</span>
|
||||
@@ -159,7 +164,7 @@
|
||||
</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 class="text-slate-400">Page Cache (all files):</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">
|
||||
@@ -167,6 +172,11 @@
|
||||
<span class="text-slate-400">Free RAM:</span>
|
||||
<span id="legend-ram-free" class="text-emerald-400 font-bold">0 GB</span>
|
||||
</div>
|
||||
<div class="flex items-center space-x-1.5" title="Measured with cachestat(2) where the kernel permits it, and a read-rate probe where it does not. This is model weights only, not the whole page cache.">
|
||||
<span class="w-2.5 h-2.5 rounded-full bg-emerald-500"></span>
|
||||
<span class="text-slate-400">Models resident (measured):</span>
|
||||
<span id="legend-models-resident" class="text-emerald-400 font-bold">—</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -286,26 +296,22 @@
|
||||
<!-- 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 class="space-y-2 text-xs">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-slate-400">VRAM held by ComfyUI:</span>
|
||||
<span id="comfy-vram-held" class="font-mono font-bold text-emerald-400">—</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 class="flex justify-between">
|
||||
<span class="text-slate-400">PCIe throughput (TX/RX):</span>
|
||||
<span id="comfy-pcie" class="font-mono font-bold text-cyan-400">—</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 class="flex justify-between">
|
||||
<span class="text-slate-400">Checkpoints resident in RAM:</span>
|
||||
<span id="comfy-resident" class="font-mono font-bold text-amber-400">—</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-slate-400">Idle purge:</span>
|
||||
<span id="comfy-purge-state" class="font-mono font-bold text-slate-300">—</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user