@casoon/auditmysite
Version:
Professional website analysis suite with robust accessibility testing, Core Web Vitals performance monitoring, SEO analysis, and content optimization insights. Features isolated browser contexts, retry mechanisms, and comprehensive API endpoints for profe
274 lines • 10.3 kB
JavaScript
;
/**
* Performance Monitoring and Benchmarking System
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.performanceMonitor = exports.PerformanceMonitor = void 0;
class PerformanceMonitor {
constructor() {
this.metrics = [];
this.activeOperations = new Map();
this.benchmarks = new Map();
}
/**
* Start monitoring an operation
*/
startOperation(operationId, operation, metadata) {
const memoryUsage = process.memoryUsage();
this.activeOperations.set(operationId, {
startTime: Date.now(),
startMemory: memoryUsage.heapUsed
});
console.log(`⏱️ Started monitoring: ${operation} (ID: ${operationId})`);
}
/**
* End monitoring an operation and record metrics
*/
endOperation(operationId, operation, metadata) {
const activeOp = this.activeOperations.get(operationId);
if (!activeOp) {
console.warn(`⚠️ No active operation found for ID: ${operationId}`);
return null;
}
const endTime = Date.now();
const duration = endTime - activeOp.startTime;
const memoryUsage = process.memoryUsage();
// Get CPU usage if available
let cpuUsage;
try {
cpuUsage = process.cpuUsage();
}
catch (error) {
// CPU usage not available on all platforms
}
const metric = {
timestamp: endTime,
operation,
duration,
memoryUsage: {
used: memoryUsage.rss,
total: memoryUsage.rss + memoryUsage.external,
external: memoryUsage.external,
heapUsed: memoryUsage.heapUsed,
heapTotal: memoryUsage.heapTotal
},
cpuUsage: cpuUsage ? {
user: cpuUsage.user / 1000, // Convert to milliseconds
system: cpuUsage.system / 1000
} : undefined,
metadata
};
this.metrics.push(metric);
this.activeOperations.delete(operationId);
const memoryDelta = memoryUsage.heapUsed - activeOp.startMemory;
console.log(`✅ Completed: ${operation} (${duration}ms, ${this.formatBytes(memoryDelta)} memory)`);
return metric;
}
/**
* Monitor a function execution
*/
async monitor(operation, fn, metadata) {
const operationId = `${operation}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
this.startOperation(operationId, operation, metadata);
try {
const result = await fn();
this.endOperation(operationId, operation, metadata);
return result;
}
catch (error) {
this.endOperation(operationId, operation, { ...metadata, error: error?.message || String(error) });
throw error;
}
}
/**
* Run benchmark tests
*/
async benchmark(name, fn, options = {}) {
const { iterations = 100, warmup = 10 } = options;
console.log(`🏁 Starting benchmark: ${name} (${iterations} iterations, ${warmup} warmup)`);
// Warmup runs
for (let i = 0; i < warmup; i++) {
await fn();
}
// Force garbage collection if available
if (global.gc) {
global.gc();
}
const times = [];
const initialMemory = process.memoryUsage().heapUsed;
let peakMemory = initialMemory;
// Benchmark runs
for (let i = 0; i < iterations; i++) {
const startTime = process.hrtime.bigint();
await fn();
const endTime = process.hrtime.bigint();
const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds
times.push(duration);
const currentMemory = process.memoryUsage().heapUsed;
peakMemory = Math.max(peakMemory, currentMemory);
}
const finalMemory = process.memoryUsage().heapUsed;
const totalTime = times.reduce((sum, time) => sum + time, 0);
const averageTime = totalTime / iterations;
const minTime = Math.min(...times);
const maxTime = Math.max(...times);
// Calculate standard deviation
const variance = times.reduce((sum, time) => sum + Math.pow(time - averageTime, 2), 0) / iterations;
const standardDeviation = Math.sqrt(variance);
const result = {
operation: name,
iterations,
totalTime,
averageTime,
minTime,
maxTime,
standardDeviation,
throughput: 1000 / averageTime, // ops per second
memoryProfile: {
initial: initialMemory,
peak: peakMemory,
final: finalMemory,
leaked: finalMemory - initialMemory
}
};
this.benchmarks.set(name, result);
console.log(`🏆 Benchmark completed: ${name}`);
console.log(` Average: ${averageTime.toFixed(2)}ms`);
console.log(` Throughput: ${result.throughput.toFixed(2)} ops/sec`);
console.log(` Memory leaked: ${this.formatBytes(result.memoryProfile.leaked)}`);
return result;
}
/**
* Get performance statistics
*/
getStats(operation) {
const filteredMetrics = operation
? this.metrics.filter(m => m.operation === operation)
: this.metrics;
if (filteredMetrics.length === 0) {
return {
count: 0,
averageDuration: 0,
totalDuration: 0,
minDuration: 0,
maxDuration: 0,
averageMemoryUsage: 0,
peakMemoryUsage: 0
};
}
const durations = filteredMetrics.map(m => m.duration);
const memoryUsages = filteredMetrics.map(m => m.memoryUsage.heapUsed);
return {
count: filteredMetrics.length,
averageDuration: durations.reduce((sum, d) => sum + d, 0) / durations.length,
totalDuration: durations.reduce((sum, d) => sum + d, 0),
minDuration: Math.min(...durations),
maxDuration: Math.max(...durations),
averageMemoryUsage: memoryUsages.reduce((sum, m) => sum + m, 0) / memoryUsages.length,
peakMemoryUsage: Math.max(...memoryUsages)
};
}
/**
* Get all metrics
*/
getMetrics(limit) {
const sorted = [...this.metrics].sort((a, b) => b.timestamp - a.timestamp);
return limit ? sorted.slice(0, limit) : sorted;
}
/**
* Get all benchmarks
*/
getBenchmarks() {
return new Map(this.benchmarks);
}
/**
* Generate performance report
*/
generateReport() {
const stats = this.getStats();
const operations = [...new Set(this.metrics.map(m => m.operation))];
let report = `\n📊 Performance Report\n`;
report += `=====================================\n`;
report += `Total Operations: ${stats.count}\n`;
report += `Average Duration: ${stats.averageDuration.toFixed(2)}ms\n`;
report += `Total Duration: ${stats.totalDuration.toFixed(2)}ms\n`;
report += `Peak Memory Usage: ${this.formatBytes(stats.peakMemoryUsage)}\n\n`;
if (operations.length > 0) {
report += `Operation Breakdown:\n`;
report += `--------------------\n`;
for (const operation of operations) {
const opStats = this.getStats(operation);
report += `${operation}:\n`;
report += ` Count: ${opStats.count}\n`;
report += ` Average: ${opStats.averageDuration.toFixed(2)}ms\n`;
report += ` Min/Max: ${opStats.minDuration.toFixed(2)}/${opStats.maxDuration.toFixed(2)}ms\n`;
report += ` Memory: ${this.formatBytes(opStats.averageMemoryUsage)}\n\n`;
}
}
if (this.benchmarks.size > 0) {
report += `Benchmarks:\n`;
report += `-----------\n`;
for (const [name, benchmark] of this.benchmarks) {
report += `${name}:\n`;
report += ` Iterations: ${benchmark.iterations}\n`;
report += ` Average: ${benchmark.averageTime.toFixed(2)}ms\n`;
report += ` Throughput: ${benchmark.throughput.toFixed(2)} ops/sec\n`;
report += ` Memory Leaked: ${this.formatBytes(benchmark.memoryProfile.leaked)}\n\n`;
}
}
return report;
}
/**
* Clear all metrics and benchmarks
*/
clear() {
this.metrics = [];
this.benchmarks.clear();
this.activeOperations.clear();
console.log('🧹 Performance monitor cleared');
}
/**
* Export metrics to JSON
*/
export() {
return {
metrics: this.metrics,
benchmarks: Object.fromEntries(this.benchmarks),
stats: this.getStats(),
timestamp: Date.now()
};
}
/**
* Format bytes to human readable format
*/
formatBytes(bytes) {
const sizes = ['B', 'KB', 'MB', 'GB'];
if (bytes === 0)
return '0 B';
const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(1024));
const size = bytes / Math.pow(1024, i);
return `${size.toFixed(2)} ${sizes[i]}`;
}
/**
* Memory leak detection
*/
detectMemoryLeaks(threshold = 50 * 1024 * 1024) {
const suspiciousOperations = [];
let totalLeak = 0;
for (const [name, benchmark] of this.benchmarks) {
if (benchmark.memoryProfile.leaked > threshold) {
suspiciousOperations.push(name);
totalLeak += benchmark.memoryProfile.leaked;
}
}
return {
hasLeak: suspiciousOperations.length > 0,
leakSize: totalLeak,
operations: suspiciousOperations
};
}
}
exports.PerformanceMonitor = PerformanceMonitor;
// Global performance monitor instance
exports.performanceMonitor = new PerformanceMonitor();
//# sourceMappingURL=performance-monitor.js.map