diff --git a/static/app.js b/static/app.js index 020eaa0..2ba0faf 100644 --- a/static/app.js +++ b/static/app.js @@ -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); +}); diff --git a/static/index.html b/static/index.html index e6b6409..97684a5 100644 --- a/static/index.html +++ b/static/index.html @@ -24,7 +24,7 @@ HYPERSWAP - v1.0-DEPLOY + v...

NVIDIA RTX 4080 SUPER 16GB // 64GB DDR5 RAM // Ubuntu Linux

@@ -115,9 +115,14 @@
- System: + Desktop: 0 GB
+
+ + Unmanaged: + 0 GB +
Free: @@ -159,7 +164,7 @@
- Models in RAM: + Page Cache (all files): 0 GB
@@ -167,6 +172,11 @@ Free RAM: 0 GB
+
+ + Models resident (measured): + — +
@@ -286,26 +296,22 @@
-
- - - Host Pinned Memory: - - 53.6 GB Staging Buffer +
+
+ VRAM held by ComfyUI: + —
-
- - - Async PCIe Offloading: - - Enabled (2 Streams) +
+ PCIe throughput (TX/RX): + —
-
- - - Fast Disk RAM Mmap: - - Active +
+ Checkpoints resident in RAM: + — +
+
+ Idle purge: + —