S3 / src /lib /cpu.ts
GUI-STUDIO
Extract ff-dl package and refactor rendering app to use it
bf677e9
Raw History Blame Contribute Delete
2.96 kB
import { cpus } from "node:os";
import { NS_runtime } from "@x/types/env.runtime";
import { NS_websockets } from "@x/ff-dl/ws";
const DEBUG_MEM = () =>
(NS_runtime.ENV_VAR_DB?.DEBUG_MEM || process.env.DEBUG_MEM) === "1";
const STATS_CHANNEL = "server-stats";
const STATS_INTERVAL_MS = 2000;
let cpu_timer: ReturnType<typeof setInterval> | undefined;
let previous_cpu = process.cpuUsage();
let previous_time = process.hrtime.bigint();
const OS = () => process.platform;
const mb = (n: number) => Number((n / 1024 / 1024).toFixed(2));
function get_server_stats() {
const now = process.hrtime.bigint();
const elapsed_us = Number(now - previous_time) / 1000;
const cpu = process.cpuUsage(previous_cpu);
const cpu_time_us = cpu.user + cpu.system;
// Percentage of one CPU core used by this process.
const process_cpu_percent =
elapsed_us > 0 ? (cpu_time_us / elapsed_us) * 100 : 0;
// Percentage of total machine CPU capacity.
const core_count = cpus().length;
previous_cpu = process.cpuUsage();
previous_time = now;
const memory = process.memoryUsage();
return {
timestamp: Date.now(),
OS: OS(),
cpu: {
process_percent: Number(process_cpu_percent.toFixed(2)),
machine_percent: Number((process_cpu_percent / core_count).toFixed(2)),
cores: core_count
},
memory: {
rss_mb: mb(memory.rss),
heap_used_mb: mb(memory.heapUsed),
heap_total_mb: mb(memory.heapTotal),
external_mb: mb(memory.external),
array_buffers_mb: mb(memory.arrayBuffers)
},
process: {
uptime_seconds: Math.floor(process.uptime()),
pid: process.pid
}
};
}
function broadcast_server_stats() {
const stats = get_server_stats();
const payload = JSON.stringify({
type: "SERVER-STATS",
data: stats
});
for (const client of NS_websockets.ws_clients.values()) {
if (!client.channels.has(STATS_CHANNEL)) continue;
try {
client.socket.send(payload);
} catch (error) {
if (!NS_runtime.IS_PROD()) {
console.error("WS STATS SEND ERROR:", error);
}
}
}
}
function start_cpu_timer() {
if (cpu_timer) return;
// Establish a fresh baseline before the first sample.
previous_cpu = process.cpuUsage();
previous_time = process.hrtime.bigint();
if (DEBUG_MEM()) {
cpu_timer = setInterval(broadcast_server_stats, STATS_INTERVAL_MS);
}
}
function stop_cpu_timer() {
if (!cpu_timer) return;
clearInterval(cpu_timer);
cpu_timer = undefined;
}
function has_stats_subscribers() {
for (const client of NS_websockets.ws_clients.values()) {
if (client.channels.has(STATS_CHANNEL)) {
return true;
}
}
return false;
}
function sync_cpu_timer() {
if (has_stats_subscribers()) {
start_cpu_timer();
} else {
stop_cpu_timer();
}
}
export const NS_server_stats = {
get: get_server_stats,
start: start_cpu_timer,
stop: stop_cpu_timer,
sync: sync_cpu_timer
};