/* === MeshCore Analyzer — perf.js === */ 'use strict'; (function () { let interval = null; async function render(app) { app.innerHTML = '

⚡ Performance Dashboard

Loading...
'; await refresh(); } async function refresh() { const el = document.getElementById('perfContent'); if (!el) return; try { const [server, client] = await Promise.all([ fetch('/api/perf').then(r => r.json()), Promise.resolve(window.apiPerf ? window.apiPerf() : null) ]); // Also fetch health telemetry const health = await fetch('/api/health').then(r => r.json()).catch(() => null); let html = ''; // Server overview html += `
${server.totalRequests}
Total Requests
${server.avgMs}ms
Avg Response
${health ? health.uptimeHuman : Math.round(server.uptime / 60) + 'm'}
Uptime
${server.slowQueries.length}
Slow (>100ms)
`; // System health (memory, event loop / go runtime, WS) if (health) { const isGo = health.engine === 'go'; if (isGo && server.goRuntime) { const gr = server.goRuntime; const gcColor = gr.lastPauseMs > 5 ? 'var(--status-red)' : gr.lastPauseMs > 1 ? 'var(--status-yellow)' : 'var(--status-green)'; html += `

🔧 Go Runtime

${gr.goroutines}
Goroutines
${gr.numGC}
GC Collections
${gr.pauseTotalMs}ms
GC Pause Total
${gr.lastPauseMs}ms
Last GC Pause
${gr.heapAllocMB}MB
Heap Alloc
${gr.heapSysMB}MB
Heap Sys
${gr.heapInuseMB}MB
Heap Inuse
${gr.heapIdleMB}MB
Heap Idle
${gr.numCPU}
CPUs
${health.websocket.clients}
WS Clients
`; } else { const m = health.memory, el = health.eventLoop; const elColor = el.p95Ms > 500 ? 'var(--status-red)' : el.p95Ms > 100 ? 'var(--status-yellow)' : 'var(--status-green)'; const memColor = m.heapUsed > m.heapTotal * 0.85 ? 'var(--status-red)' : m.heapUsed > m.heapTotal * 0.7 ? 'var(--status-yellow)' : 'var(--status-green)'; html += `

System Health

${m.heapUsed}MB
Heap Used / ${m.heapTotal}MB
${m.rss}MB
RSS
${el.p95Ms}ms
Event Loop p95
${el.maxLagMs}ms
EL Max Lag
${el.currentLagMs}ms
EL Current
${health.websocket.clients}
WS Clients
`; } } // Cache stats if (server.cache) { const c = server.cache; const clientCache = _apiCache ? _apiCache.size : 0; html += `

Cache

${c.size}
Server Entries
${c.hits}
Server Hits
${c.misses}
Server Misses
${c.hitRate}%
Server Hit Rate
${c.staleHits || 0}
Stale Hits (SWR)
${c.recomputes || 0}
Recomputes
${clientCache}
Client Entries
`; if (client) { html += `
${client.cacheHits || 0}
Client Hits
${client.cacheMisses || 0}
Client Misses
${client.cacheHitRate || 0}%
Client Hit Rate
`; } } // Packet Store stats if (server.packetStore) { const ps = server.packetStore; html += `

In-Memory Packet Store

${ps.inMemory.toLocaleString()}
Packets in RAM
${ps.estimatedMB}MB
Memory Used
${ps.maxMB}MB
Memory Limit
${ps.queries.toLocaleString()}
Queries Served
${ps.inserts.toLocaleString()}
Live Inserts
${ps.evicted.toLocaleString()}
Evicted
${ps.indexes.byHash.toLocaleString()}
Unique Hashes
${ps.indexes.byObserver}
Observers
${ps.indexes.byNode.toLocaleString()}
Indexed Nodes
`; } // SQLite stats if (server.sqlite && !server.sqlite.error) { const sq = server.sqlite; const walColor = sq.walSizeMB > 50 ? 'var(--status-red)' : sq.walSizeMB > 10 ? 'var(--status-yellow)' : 'var(--status-green)'; const freelistColor = sq.freelistMB > 10 ? 'var(--status-yellow)' : 'var(--status-green)'; html += `

SQLite

${sq.dbSizeMB}MB
DB Size
${sq.walSizeMB}MB
WAL Size
${sq.freelistMB}MB
Freelist
${(sq.rows.transmissions || 0).toLocaleString()}
Transmissions
${(sq.rows.observations || 0).toLocaleString()}
Observations
${sq.rows.nodes || 0}
Nodes
${sq.rows.observers || 0}
Observers
`; if (sq.walPages) { html += `
${sq.walPages.busy}
WAL Busy Pages
`; } html += `
`; } // Server endpoints table const eps = Object.entries(server.endpoints); if (eps.length) { html += '

Server Endpoints (sorted by total time)

'; html += '
'; for (const [path, s] of eps) { const total = Math.round(s.count * s.avgMs); const cls = s.p95Ms > 200 ? ' class="perf-slow"' : s.p95Ms > 50 ? ' class="perf-warn"' : ''; html += ``; } html += '
EndpointCountAvgP50P95MaxTotal
${path}${s.count}${s.avgMs}ms${s.p50Ms}ms${s.p95Ms}ms${s.maxMs}ms${total}ms
'; } // Client API calls if (client && client.endpoints.length) { html += '

Client API Calls (this session)

'; html += '
'; for (const s of client.endpoints) { const cls = s.maxMs > 500 ? ' class="perf-slow"' : s.avgMs > 200 ? ' class="perf-warn"' : ''; html += ``; } html += '
EndpointCountAvgMaxTotal
${s.path}${s.count}${s.avgMs}ms${s.maxMs}ms${s.totalMs}ms
'; } // Slow queries if (server.slowQueries.length) { html += '

Recent Slow Queries (>100ms)

'; html += '
'; for (const q of server.slowQueries.slice().reverse()) { html += ``; } html += '
TimePathDurationStatus
${new Date(q.time).toLocaleTimeString()}${q.path}${q.ms}ms${q.status}
'; } html += `
`; el.innerHTML = html; document.getElementById('perfReset')?.addEventListener('click', async () => { await fetch('/api/perf/reset', { method: 'POST' }); if (window._apiPerf) { window._apiPerf = { calls: 0, totalMs: 0, log: [] }; } refresh(); }); document.getElementById('perfRefresh')?.addEventListener('click', refresh); } catch (err) { el.innerHTML = `

Error: ${err.message}

`; } } registerPage('perf', { init(app) { render(app); interval = setInterval(refresh, 5000); }, destroy() { if (interval) { clearInterval(interval); interval = null; } } }); })();