claude-flow
Version:
Enterprise-grade AI agent orchestration with ruv-swarm integration (Alpha Release)
337 lines (275 loc) ⢠9.69 kB
JavaScript
// performance-monitor.js - Performance monitoring for batch operations
import { printInfo } from '../../utils.js';
export class PerformanceMonitor {
constructor(options = {}) {
this.enabled = options.enabled !== false;
this.logLevel = options.logLevel || 'info';
this.memoryCheckInterval = options.memoryCheckInterval || 5000; // 5 seconds
this.maxMemoryMB = options.maxMemoryMB || 1024; // 1GB default limit
this.metrics = {
startTime: null,
endTime: null,
peakMemoryMB: 0,
averageMemoryMB: 0,
operationCount: 0,
memoryReadings: [],
errors: [],
warnings: []
};
this.memoryMonitor = null;
}
start() {
if (!this.enabled) return;
this.metrics.startTime = Date.now();
this.startMemoryMonitoring();
if (this.logLevel === 'debug') {
console.log('š Performance monitoring started');
}
}
stop() {
if (!this.enabled) return;
this.metrics.endTime = Date.now();
this.stopMemoryMonitoring();
this.calculateAverages();
if (this.logLevel === 'debug') {
console.log('š Performance monitoring stopped');
}
}
startMemoryMonitoring() {
if (typeof Deno !== 'undefined' && Deno.memoryUsage) {
this.memoryMonitor = setInterval(() => {
const memUsage = Deno.memoryUsage();
const memoryMB = memUsage.rss / 1024 / 1024;
this.metrics.memoryReadings.push({
timestamp: Date.now(),
memoryMB: memoryMB
});
if (memoryMB > this.metrics.peakMemoryMB) {
this.metrics.peakMemoryMB = memoryMB;
}
// Check memory limit
if (memoryMB > this.maxMemoryMB) {
this.metrics.warnings.push({
timestamp: Date.now(),
type: 'memory',
message: `Memory usage ${memoryMB.toFixed(1)}MB exceeds limit ${this.maxMemoryMB}MB`
});
}
}, this.memoryCheckInterval);
}
}
stopMemoryMonitoring() {
if (this.memoryMonitor) {
clearInterval(this.memoryMonitor);
this.memoryMonitor = null;
}
}
calculateAverages() {
if (this.metrics.memoryReadings.length > 0) {
const totalMemory = this.metrics.memoryReadings.reduce((sum, reading) => sum + reading.memoryMB, 0);
this.metrics.averageMemoryMB = totalMemory / this.metrics.memoryReadings.length;
}
}
recordOperation(operationType, details = {}) {
if (!this.enabled) return;
this.metrics.operationCount++;
if (this.logLevel === 'debug') {
console.log(`š Operation: ${operationType}`, details);
}
}
recordError(error, context = {}) {
if (!this.enabled) return;
this.metrics.errors.push({
timestamp: Date.now(),
error: error.message || error,
context
});
if (this.logLevel === 'debug') {
console.log('ā Error recorded:', error.message || error);
}
}
recordWarning(message, context = {}) {
if (!this.enabled) return;
this.metrics.warnings.push({
timestamp: Date.now(),
type: 'warning',
message,
context
});
if (this.logLevel === 'debug') {
console.log('ā ļø Warning recorded:', message);
}
}
getMetrics() {
const duration = this.metrics.endTime - this.metrics.startTime;
return {
...this.metrics,
duration,
operationsPerSecond: this.metrics.operationCount / (duration / 1000),
memoryEfficiency: this.metrics.peakMemoryMB < (this.maxMemoryMB * 0.8) ? 'good' : 'warning'
};
}
generateReport() {
if (!this.enabled) return 'Performance monitoring disabled';
const metrics = this.getMetrics();
let report = '\nš Performance Report\n';
report += '====================\n';
report += `Duration: ${(metrics.duration / 1000).toFixed(2)}s\n`;
report += `Operations: ${metrics.operationCount}\n`;
report += `Operations/sec: ${metrics.operationsPerSecond.toFixed(2)}\n`;
report += `Peak Memory: ${metrics.peakMemoryMB.toFixed(1)}MB\n`;
report += `Average Memory: ${metrics.averageMemoryMB.toFixed(1)}MB\n`;
report += `Memory Efficiency: ${metrics.memoryEfficiency}\n`;
if (metrics.errors.length > 0) {
report += `\nā Errors: ${metrics.errors.length}\n`;
metrics.errors.slice(-3).forEach(error => {
report += ` - ${error.error}\n`;
});
}
if (metrics.warnings.length > 0) {
report += `\nā ļø Warnings: ${metrics.warnings.length}\n`;
metrics.warnings.slice(-3).forEach(warning => {
report += ` - ${warning.message}\n`;
});
}
return report;
}
// Real-time monitoring display
displayRealTimeStats() {
if (!this.enabled) return;
const currentTime = Date.now();
const elapsed = this.metrics.startTime ? (currentTime - this.metrics.startTime) / 1000 : 0;
let currentMemory = 'ā';
if (typeof Deno !== 'undefined' && Deno.memoryUsage) {
const memUsage = Deno.memoryUsage();
currentMemory = `${(memUsage.rss / 1024 / 1024).toFixed(1)}MB`;
}
console.log(`ā±ļø ${elapsed.toFixed(1)}s | š¾ ${currentMemory} | š ${this.metrics.operationCount} ops`);
}
}
// Resource threshold monitor
export class ResourceThresholdMonitor {
constructor(options = {}) {
this.maxMemoryMB = options.maxMemoryMB || 1024;
this.maxCPUPercent = options.maxCPUPercent || 80;
this.checkInterval = options.checkInterval || 2000;
this.isMonitoring = false;
this.monitorInterval = null;
this.callbacks = {
memoryWarning: options.onMemoryWarning || (() => {}),
memoryError: options.onMemoryError || (() => {}),
cpuWarning: options.onCPUWarning || (() => {})
};
}
start() {
if (this.isMonitoring) return;
this.isMonitoring = true;
this.monitorInterval = setInterval(() => {
this.checkResources();
}, this.checkInterval);
}
stop() {
if (!this.isMonitoring) return;
this.isMonitoring = false;
if (this.monitorInterval) {
clearInterval(this.monitorInterval);
this.monitorInterval = null;
}
}
checkResources() {
if (typeof Deno !== 'undefined' && Deno.memoryUsage) {
const memUsage = Deno.memoryUsage();
const memoryMB = memUsage.rss / 1024 / 1024;
const warningThreshold = this.maxMemoryMB * 0.8;
const errorThreshold = this.maxMemoryMB * 0.95;
if (memoryMB > errorThreshold) {
this.callbacks.memoryError(memoryMB, this.maxMemoryMB);
} else if (memoryMB > warningThreshold) {
this.callbacks.memoryWarning(memoryMB, this.maxMemoryMB);
}
}
}
static createDefaultCallbacks() {
return {
onMemoryWarning: (current, max) => {
printInfo(`ā ļø Memory usage high: ${current.toFixed(1)}MB / ${max}MB`);
},
onMemoryError: (current, max) => {
console.error(`ā Memory usage critical: ${current.toFixed(1)}MB / ${max}MB`);
console.error('Consider reducing batch size or max concurrency');
},
onCPUWarning: (percent) => {
printInfo(`ā ļø CPU usage high: ${percent}%`);
}
};
}
}
// Batch operation optimizer
export class BatchOptimizer {
static calculateOptimalConcurrency(projectCount, systemSpecs = {}) {
const {
cpuCores = 4,
memoryGB = 8,
diskSpeed = 'ssd' // 'ssd' or 'hdd'
} = systemSpecs;
let optimal = Math.min(
cpuCores * 2, // 2x CPU cores
Math.floor(memoryGB / 0.5), // 500MB per project
projectCount, // Can't exceed project count
20 // Hard limit
);
// Adjust for disk speed
if (diskSpeed === 'hdd') {
optimal = Math.ceil(optimal * 0.7); // Reduce for HDD
}
return Math.max(1, optimal);
}
static estimateCompletionTime(projectCount, options = {}) {
const {
concurrency = 5,
template = 'basic',
sparc = false,
averageTimePerProject = 15 // seconds
} = options;
let timeMultiplier = 1;
// Adjust for template complexity
const templateMultipliers = {
'basic': 1,
'web-api': 1.2,
'react-app': 1.5,
'microservice': 1.8,
'cli-tool': 1.1
};
timeMultiplier *= templateMultipliers[template] || 1;
// Adjust for SPARC
if (sparc) {
timeMultiplier *= 1.3;
}
const adjustedTime = averageTimePerProject * timeMultiplier;
const totalSequentialTime = projectCount * adjustedTime;
const parallelTime = Math.ceil(projectCount / concurrency) * adjustedTime;
return {
sequential: totalSequentialTime,
parallel: parallelTime,
savings: totalSequentialTime - parallelTime,
savingsPercent: ((totalSequentialTime - parallelTime) / totalSequentialTime * 100).toFixed(1)
};
}
static generateRecommendations(projectCount, options = {}) {
const recommendations = [];
if (projectCount > 10) {
recommendations.push('Consider using parallel processing for better performance');
}
if (projectCount > 20) {
recommendations.push('Use configuration files for better organization');
recommendations.push('Consider breaking into smaller batches');
}
if (options.sparc && projectCount > 5) {
recommendations.push('SPARC initialization adds overhead - monitor memory usage');
}
if (options.template === 'microservice' && projectCount > 3) {
recommendations.push('Microservice template is complex - consider lower concurrency');
}
return recommendations;
}
}