UNPKG

sead-method-core

Version:

Specification Enforced Agentic Agile Development - A hybrid methodology preventing AI agent drift through catalog-based constraints with comprehensive external asset integration

226 lines (191 loc) 5.96 kB
/** * Memory Profiler - Track memory usage during installation * Helps identify memory leaks and optimize resource usage */ const v8 = require('node:v8'); class MemoryProfiler { constructor() { this.checkpoints = []; this.startTime = Date.now(); this.peakMemory = 0; } /** * Create a memory checkpoint * @param {string} label - Label for this checkpoint */ checkpoint(label) { const memUsage = process.memoryUsage(); const heapStats = v8.getHeapStatistics(); const checkpoint = { label, timestamp: Date.now() - this.startTime, memory: { rss: this.formatBytes(memUsage.rss), heapTotal: this.formatBytes(memUsage.heapTotal), heapUsed: this.formatBytes(memUsage.heapUsed), external: this.formatBytes(memUsage.external), arrayBuffers: this.formatBytes(memUsage.arrayBuffers || 0), }, heap: { totalHeapSize: this.formatBytes(heapStats.total_heap_size), usedHeapSize: this.formatBytes(heapStats.used_heap_size), heapSizeLimit: this.formatBytes(heapStats.heap_size_limit), mallocedMemory: this.formatBytes(heapStats.malloced_memory), externalMemory: this.formatBytes(heapStats.external_memory), }, raw: { heapUsed: memUsage.heapUsed, }, }; // Track peak memory if (memUsage.heapUsed > this.peakMemory) { this.peakMemory = memUsage.heapUsed; } this.checkpoints.push(checkpoint); return checkpoint; } /** * Force garbage collection (requires --expose-gc flag) */ forceGC() { if (globalThis.gc) { globalThis.gc(); return true; } return false; } /** * Get memory usage summary */ getSummary() { const currentMemory = process.memoryUsage(); return { currentUsage: { rss: this.formatBytes(currentMemory.rss), heapTotal: this.formatBytes(currentMemory.heapTotal), heapUsed: this.formatBytes(currentMemory.heapUsed), }, peakMemory: this.formatBytes(this.peakMemory), totalCheckpoints: this.checkpoints.length, runTime: `${((Date.now() - this.startTime) / 1000).toFixed(2)}s`, }; } /** * Get detailed report of memory usage */ getDetailedReport() { const summary = this.getSummary(); const memoryGrowth = this.calculateMemoryGrowth(); return { summary, memoryGrowth, checkpoints: this.checkpoints, recommendations: this.getRecommendations(memoryGrowth), }; } /** * Calculate memory growth between checkpoints */ calculateMemoryGrowth() { if (this.checkpoints.length < 2) return []; const growth = []; for (let index = 1; index < this.checkpoints.length; index++) { const previous = this.checkpoints[index - 1]; const current = this.checkpoints[index]; const heapDiff = current.raw.heapUsed - previous.raw.heapUsed; growth.push({ from: previous.label, to: current.label, heapGrowth: this.formatBytes(Math.abs(heapDiff)), isIncrease: heapDiff > 0, timeDiff: `${((current.timestamp - previous.timestamp) / 1000).toFixed(2)}s`, }); } return growth; } /** * Get recommendations based on memory usage */ getRecommendations(memoryGrowth) { const recommendations = []; // Check for large memory growth const largeGrowths = memoryGrowth.filter((g) => { const bytes = this.parseBytes(g.heapGrowth); return bytes > 50 * 1024 * 1024; // 50MB }); if (largeGrowths.length > 0) { recommendations.push({ type: 'warning', message: `Large memory growth detected in ${largeGrowths.length} operations`, details: largeGrowths.map((g) => `${g.from} → ${g.to}: ${g.heapGrowth}`), }); } // Check peak memory if (this.peakMemory > 500 * 1024 * 1024) { // 500MB recommendations.push({ type: 'warning', message: `High peak memory usage: ${this.formatBytes(this.peakMemory)}`, suggestion: 'Consider processing files in smaller batches', }); } // Check for potential memory leaks const continuousGrowth = this.checkContinuousGrowth(); if (continuousGrowth) { recommendations.push({ type: 'error', message: 'Potential memory leak detected', details: 'Memory usage continuously increases without significant decreases', }); } return recommendations; } /** * Check for continuous memory growth (potential leak) */ checkContinuousGrowth() { if (this.checkpoints.length < 5) return false; let increasingCount = 0; for (let index = 1; index < this.checkpoints.length; index++) { if (this.checkpoints[index].raw.heapUsed > this.checkpoints[index - 1].raw.heapUsed) { increasingCount++; } } // If memory increases in more than 80% of checkpoints, might be a leak return increasingCount / (this.checkpoints.length - 1) > 0.8; } /** * Format bytes to human-readable string */ formatBytes(bytes) { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const index = Math.floor(Math.log(bytes) / Math.log(k)); return Number.parseFloat((bytes / Math.pow(k, index)).toFixed(2)) + ' ' + sizes[index]; } /** * Parse human-readable bytes back to number */ parseBytes(string_) { const match = string_.match(/^([\d.]+)\s*([KMGT]?B?)$/i); if (!match) return 0; const value = Number.parseFloat(match[1]); const unit = match[2].toUpperCase(); const multipliers = { B: 1, KB: 1024, MB: 1024 * 1024, GB: 1024 * 1024 * 1024, }; return value * (multipliers[unit] || 1); } /** * Clear checkpoints to free memory */ clear() { this.checkpoints = []; } } // Export singleton instance module.exports = new MemoryProfiler();