bodhi-node-profiler
Version:
A lightweight, zero-configuration performance profiler for Node.js applications with real-time dashboard
118 lines (101 loc) • 3.14 kB
text/typescript
import pidusage from 'pidusage';
import { performance } from 'perf_hooks';
import { SystemStats, CpuMetrics, MemoryMetrics } from './types';
import os from 'os';
export class Stats {
private latestStats: SystemStats;
private eventLoopLag: number;
private lastCpuUsage: { user: number; system: number };
private lastCpuCheck: number;
constructor() {
this.eventLoopLag = 0;
this.lastCpuCheck = Date.now();
this.lastCpuUsage = process.cpuUsage();
this.latestStats = {
timestamp: Date.now(),
cpu: {
percentage: '0',
system: 0,
user: 0
},
memory: {
heapUsed: 0,
heapTotal: 0,
rss: 0,
external: 0
},
eventLoopDelay: 0
};
this.startEventLoopMonitoring();
}
private startEventLoopMonitoring(): void {
let lastCheck = performance.now();
let minLag = Infinity;
let maxLag = 0;
let samples = 0;
let totalLag = 0;
setInterval(() => {
const now = performance.now();
const delta = now - lastCheck;
const lag = Math.max(0, delta - 1);
// Update stats
minLag = Math.min(minLag, lag);
maxLag = Math.max(maxLag, lag);
totalLag += lag;
samples++;
// Calculate average lag over the last interval
if (samples >= 10) { // Average over 10 samples
this.eventLoopLag = totalLag / samples;
minLag = Infinity;
maxLag = 0;
totalLag = 0;
samples = 0;
}
lastCheck = now;
}, 10); // Sample every 10ms for better accuracy
}
private calculateCpuUsage(): CpuMetrics {
const now = Date.now();
const currentCpuUsage = process.cpuUsage();
const userDiff = currentCpuUsage.user - this.lastCpuUsage.user;
const systemDiff = currentCpuUsage.system - this.lastCpuUsage.system;
const timeDiff = now - this.lastCpuCheck;
this.lastCpuUsage = currentCpuUsage;
this.lastCpuCheck = now;
// Convert microseconds to milliseconds
const totalUsage = (userDiff + systemDiff) / 1000;
// Calculate percentage based on elapsed time and number of cores
const numCores = os.cpus().length;
const maxTime = timeDiff * numCores * 1000; // Convert to microseconds
const percentage = ((totalUsage / maxTime) * 100).toFixed(1);
return {
percentage,
system: systemDiff / 1000000, // Convert to seconds
user: userDiff / 1000000
};
}
public async collect(): Promise<SystemStats> {
try {
const memoryUsage = process.memoryUsage();
const cpu = this.calculateCpuUsage();
this.latestStats = {
timestamp: Date.now(),
cpu,
memory: {
heapUsed: memoryUsage.heapUsed,
heapTotal: memoryUsage.heapTotal,
rss: memoryUsage.rss,
external: memoryUsage.external
},
eventLoopDelay: this.eventLoopLag
};
return this.latestStats;
} catch (error) {
console.error('Error collecting stats:', error);
throw error;
}
}
public getLatest(): SystemStats {
return this.latestStats;
}
}