/**
* Space Fetch - System Performance Dashboard
* Frontend Logic
*/
// Application State
const state = {
systemInfo: null,
benchmarks: {
cpu: null,
memory: null,
disk: null,
gpu: null
},
status: {
running: {},
gpu_available: false
}
};
// Initialization
document.addEventListener('DOMContentLoaded', async () => {
await fetchSystemInfo();
await checkBenchmarkStatus();
// Start polling for active benchmarks
setInterval(pollBenchmarkStatus, 2000);
// Start polling for memory status
setInterval(updateMemoryStatus, 1000);
});
async function fetchSystemInfo() {
try {
const response = await fetch('/api/system');
const data = await response.json();
state.systemInfo = data;
renderSystemInfo(data);
renderHardwareInfo(data);
} catch (error) {
console.error('Failed to fetch system info:', error);
}
}
async function checkBenchmarkStatus() {
try {
const response = await fetch('/api/benchmark/status');
const data = await response.json();
state.status = data;
// Update GPU card visibility
const gpuCard = document.getElementById('gpu-card');
const gpuBench = document.getElementById('bench-gpu');
if (!data.gpu_available) {
if (gpuCard) gpuCard.style.display = 'none';
if (gpuBench) gpuBench.style.display = 'none';
}
// Restore any running or cached benchmarks
for (const [type, isCached] of Object.entries(data.cached)) {
if (isCached && !document.getElementById(`${type}-bench-content`).querySelector('.bench-result-item')) {
await fetchBenchmarkResult(type);
}
}
} catch (error) {
console.error('Failed to check status:', error);
}
}
async function pollBenchmarkStatus() {
const response = await fetch('/api/benchmark/status');
const data = await response.json();
// Check for completed benchmarks
for (const [type, isRunning] of Object.entries(data.running)) {
if (state.status.running[type] && !isRunning) {
// Benchmark finished, fetch results
await fetchBenchmarkResult(type);
}
// Update button states
const btn = document.getElementById(`run-${type}-btn`);
if (btn) {
if (isRunning) {
btn.disabled = true;
btn.innerHTML = ' Running...';
} else {
btn.disabled = false;
btn.innerText = 'Run';
}
}
}
state.status = data;
}
async function updateMemoryStatus() {
try {
const response = await fetch('/api/monitor/memory');
if (response.ok) {
const data = await response.json();
document.getElementById('memory-total').innerText = data.total_formatted;
document.getElementById('memory-usage').style.width = `${data.percent}%`;
document.getElementById('memory-details').innerText = `${data.used_formatted} used / ${data.available_formatted} available`;
}
} catch (error) {
// Silent fail for polling to avoid console spam
}
}
// Rendering Functions
function renderSystemInfo(data) {
const container = document.getElementById('system-info');
container.innerHTML = `
Operating System
Distro
${data.os.distro}
Kernel
${data.os.kernel}
Hostname
${data.os.hostname}
Load Avg
${data.os.load_average.join(', ')}
Uptime
${Math.floor(data.os.uptime_seconds / 3600)}h ${Math.floor((data.os.uptime_seconds % 3600) / 60)}m
Python Environment
Version
Python ${data.os.system === 'Linux' ? '3.x' : 'Unknown'}
Architecture
${data.os.architecture}
`;
}
function renderHardwareInfo(data) {
// CPU
document.getElementById('cpu-name').innerText = data.cpu.brand;
const cpuDetails = `${data.cpu.cores_physical} Physical Cores / ${data.cpu.cores_logical} Logical Cores @ ${data.cpu.frequency.current_mhz || 'N/A'} MHz`;
document.getElementById('cpu-details').innerText = cpuDetails;
// Memory
document.getElementById('memory-total').innerText = data.memory.total_formatted;
document.getElementById('memory-usage').style.width = `${data.memory.percent}%`;
document.getElementById('memory-details').innerText = `${data.memory.used_formatted} used / ${data.memory.available_formatted} available`;
// Disk (First Partition)
if (data.disk.length > 0) {
const disk = data.disk[0];
document.getElementById('disk-total').innerText = disk.total_formatted;
document.getElementById('disk-usage').style.width = `${disk.percent}%`;
document.getElementById('disk-details').innerText = `${disk.used_formatted} used / ${disk.free_formatted} free (${disk.mountpoint})`;
}
// GPU
if (data.gpu && data.gpu.length > 0) {
const gpu = data.gpu[0];
document.getElementById('gpu-name').innerText = gpu.name;
const memoryUsedPercent = (gpu.memory_used_mb / gpu.memory_total_mb) * 100;
document.getElementById('gpu-usage').style.width = `${memoryUsedPercent}%`;
document.getElementById('gpu-details').innerText = `${gpu.memory_used_mb}MB / ${gpu.memory_total_mb}MB VRAM | Driver: ${gpu.driver_version}`;
} else {
const gpuCard = document.getElementById('gpu-card');
if (gpuCard) gpuCard.style.display = 'none';
}
}
// Benchmark Actions
async function runBenchmark(type) {
const container = document.getElementById(`${type}-bench-content`);
container.innerHTML = `
Running benchmark... This may take a moment.
`;
try {
await fetch(`/api/benchmark/${type}`, { method: 'POST' });
// Polling will handle the update
} catch (error) {
container.innerHTML = `Error starting benchmark
`;
}
}
async function runAllBenchmarks() {
const types = ['cpu', 'memory', 'disk'];
if (state.status.gpu_available) types.push('gpu');
for (const type of types) {
runBenchmark(type);
}
}
async function fetchBenchmarkResult(type) {
try {
const response = await fetch(`/api/benchmark/${type}`);
const data = await response.json();
if (data.results) {
renderBenchmarkResult(type, data.results);
}
} catch (error) {
console.error(`Error details for ${type}:`, error);
}
}
function renderBenchmarkResult(type, results) {
const container = document.getElementById(`${type}-bench-content`);
let html = '';
if (type === 'cpu') {
html += createResultItem('Single Core Integer', `${results.single_core_integer.ops_per_second} ops/s`, results.single_core_integer.score);
html += createResultItem('Multi Core Integer', `${results.multi_core_integer.ops_per_second} ops/s`, results.multi_core_integer.score);
html += createResultItem('Single Core Float', `${results.single_core_float.gflops} GFLOPS`, results.single_core_float.score);
html += createResultItem('Multi Core Float', `${results.multi_core_float.gflops} GFLOPS`, results.multi_core_float.score);
html += createResultItem('SHA256 Hash', `${results.crypto.throughput_mb_per_sec} MB/s`, results.crypto.score);
html += createResultItem('Zlib Compression', `${results.compression.throughput_mb_per_sec} MB/s`, results.compression.score);
html += createResultItem('Context Switches', `${results.stress.wakeups_per_second} /s`, results.stress.score);
} else if (type === 'memory') {
html += createResultItem('Read Bandwidth', `${results.bandwidth.read_bandwidth_gb_s} GB/s`);
html += createResultItem('Write Bandwidth', `${results.bandwidth.write_bandwidth_gb_s} GB/s`);
// New Metric structure
if (results.latency_random) {
html += createResultItem('Random Latency', `${results.latency_random.average_latency_ns} ns`);
}
if (results.latency_sequential) {
html += createResultItem('Seq Latency', `${results.latency_sequential.average_latency_ns} ns`);
}
if (results.alloc_rate) {
html += createResultItem('Alloc Rate', `${(results.alloc_rate.ops_per_sec / 1e6).toFixed(1)} M/s`);
}
if (results.cache_latency && results.cache_latency.levels) {
const l1 = results.cache_latency.levels.L1;
const l2 = results.cache_latency.levels.L2;
const l3 = results.cache_latency.levels.L3;
html += createResultItem('L1 Latency', `${l1.latency_ns} ns`);
html += createResultItem('L2 Latency', `${l2.latency_ns} ns`);
html += createResultItem('L3 Latency', `${l3.latency_ns} ns`);
}
} else if (type === 'disk') {
html += createResultItem('Seq Read', `${results.sequential_read.throughput_mb_s} MB/s`, results.sequential_read.score);
html += createResultItem('Seq Write', `${results.sequential_write.throughput_mb_s} MB/s`, results.sequential_write.score);
html += createResultItem('Random Read', `${results.random_read_iops.iops} IOPS`, results.random_read_iops.score);
html += createResultItem('Random Write', `${results.random_write_iops.iops} IOPS`, results.random_write_iops.score);
} else if (type === 'gpu') {
if (results.memory_bandwidth) html += createResultItem('Memory Bandwidth', `${results.memory_bandwidth.bandwidth_gb_s} GB/s`, results.memory_bandwidth.score);
if (results.fp32) html += createResultItem('FP32 Compute', `${results.fp32.tflops} TFLOPS`, results.fp32.score);
if (results.fp16) html += createResultItem('FP16 Compute', `${results.fp16.tflops} TFLOPS`, results.fp16.score);
if (results.tensor_cores) html += createResultItem('Tensor Cores', `${results.tensor_cores.tflops} TFLOPS`, results.tensor_cores.score);
}
container.innerHTML = html;
}
function createResultItem(label, value, score) {
return `
`;
}
async function exportResults() {
try {
const response = await fetch('/api/export');
const data = await response.json();
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `space-fetch-results-${new Date().toISOString().slice(0, 10)}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
} catch (error) {
alert('Failed to export results');
}
}