Skip to main content
Glama

Prompt Auto-Optimizer MCP

by sloth-wq
memory-performance-validation.test.ts31 kB
/** * Memory Performance Validation Test Suite * * Comprehensive performance validation for all memory optimization features * with precise measurements and benchmark comparisons. */ import { describe, test, expect, beforeEach, afterEach } from 'vitest'; import { performance } from 'perf_hooks'; import { MemoryLeakDetector, MemoryLeakIntegration } from '../../core/memory-leak-detector'; import { GarbageCollectionOptimizer } from '../../core/gc-optimizer'; import { PerformanceTracker } from '../../services/performance-tracker'; import { CacheManager } from '../../core/cache/cache-manager'; import { ParetoFrontier } from '../../core/pareto-frontier'; import { PromptCandidate } from '../../types/gepa'; interface PerformanceBenchmark { operation: string; baseline: number; optimized: number; improvement: number; memoryImpact: number; samples: number; variance: number; } interface MemoryEfficiencyMetrics { heapUtilization: number; gcEfficiency: number; objectPoolHitRate: number; bufferReuseRate: number; leakDetectionAccuracy: number; cleanupEffectiveness: number; } describe('Memory Performance Validation Suite', () => { let memoryLeakDetector: MemoryLeakDetector; let gcOptimizer: GarbageCollectionOptimizer; let performanceTracker: PerformanceTracker; let cacheManager: CacheManager; let paretoFrontier: ParetoFrontier; // Performance thresholds const PERFORMANCE_THRESHOLDS = { maxOperationLatency: 100, // milliseconds minGCEfficiency: 0.3, // 30% memory reclaimed minPoolHitRate: 0.6, // 60% hit rate maxMemoryGrowth: 50 * 1024 * 1024, // 50MB minCleanupEffectiveness: 0.7, // 70% effective }; beforeEach(async () => { performanceTracker = new PerformanceTracker(); memoryLeakDetector = MemoryLeakIntegration.initialize({ heapGrowthRate: 2, maxHeapSize: 100, maxObjectCount: 1000, memoryIncreaseThreshold: 15, monitoringWindow: 5000, snapshotInterval: 1000, }); gcOptimizer = new GarbageCollectionOptimizer(performanceTracker, memoryLeakDetector); gcOptimizer.setOptimizationStrategy('high-throughput'); // Start with performance-focused cacheManager = new CacheManager({ l1MaxSize: 5 * 1024 * 1024, l1MaxEntries: 1000, l2Enabled: true, l2MaxSize: 10 * 1024 * 1024, l2MaxEntries: 2000, enableMemoryTracking: true, }); paretoFrontier = new ParetoFrontier({ objectives: [ { name: 'performance', weight: 1, direction: 'maximize', extractor: (candidate: PromptCandidate) => candidate.averageScore, }, { name: 'efficiency', weight: 0.8, direction: 'minimize', extractor: (candidate: PromptCandidate) => candidate.rolloutCount || 1, }, ], maxSize: 200, enableMemoryTracking: true, }); }); afterEach(async () => { if (cacheManager) await cacheManager.shutdown(); if (paretoFrontier) paretoFrontier.clear(); if (gcOptimizer) gcOptimizer.shutdown(); if (memoryLeakDetector) memoryLeakDetector.shutdown(); MemoryLeakIntegration.shutdown(); }); describe('GC Optimization Performance Validation', () => { test('should validate GC strategy performance improvements', async () => { const strategies = ['balanced', 'high-throughput', 'low-latency', 'memory-intensive']; const strategyBenchmarks: Array<PerformanceBenchmark & { strategy: string }> = []; for (const strategy of strategies) { gcOptimizer.setOptimizationStrategy(strategy); const samples: number[] = []; const memoryImpacts: number[] = []; // Benchmark each strategy for (let sample = 0; sample < 20; sample++) { const beforeMemory = process.memoryUsage().heapUsed; const startTime = performance.now(); // Standard workload for (let i = 0; i < 100; i++) { await cacheManager.set(`${strategy}-bench-${sample}-${i}`, { data: 'x'.repeat(1000), strategy, sample, }); if (i % 20 === 0) { await gcOptimizer.forceGarbageCollection(`${strategy}-benchmark`); } } const endTime = performance.now(); const afterMemory = process.memoryUsage().heapUsed; samples.push(endTime - startTime); memoryImpacts.push(afterMemory - beforeMemory); // Cleanup between samples await cacheManager.clear(); await gcOptimizer.forceGarbageCollection('sample-cleanup'); } const avgDuration = samples.reduce((sum, s) => sum + s, 0) / samples.length; const avgMemoryImpact = memoryImpacts.reduce((sum, m) => sum + m, 0) / memoryImpacts.length; const variance = samples.reduce((sum, s) => sum + Math.pow(s - avgDuration, 2), 0) / samples.length; strategyBenchmarks.push({ strategy, operation: `gc-strategy-${strategy}`, baseline: samples[0], // First sample as baseline optimized: avgDuration, improvement: (samples[0] - avgDuration) / samples[0], memoryImpact: avgMemoryImpact, samples: samples.length, variance, }); } // Validate strategy performance characteristics const balancedBench = strategyBenchmarks.find(b => b.strategy === 'balanced')!; const highThroughputBench = strategyBenchmarks.find(b => b.strategy === 'high-throughput')!; const lowLatencyBench = strategyBenchmarks.find(b => b.strategy === 'low-latency')!; const memoryIntensiveBench = strategyBenchmarks.find(b => b.strategy === 'memory-intensive')!; // All strategies should complete in reasonable time strategyBenchmarks.forEach(bench => { expect(bench.optimized).toBeLessThan(PERFORMANCE_THRESHOLDS.maxOperationLatency * 50); // 5 second max expect(bench.variance).toBeLessThan(bench.optimized * 0.5); // Variance should be reasonable }); // Low-latency should generally have lower variance (more predictable) expect(lowLatencyBench.variance).toBeLessThanOrEqual(highThroughputBench.variance); // Memory-intensive should handle larger memory impacts expect(memoryIntensiveBench.memoryImpact).toBeGreaterThanOrEqual(0); // Should handle memory well }); test('should measure object pool performance gains', async () => { const poolBenchmarks: PerformanceBenchmark[] = []; const poolNames = ['candidates', 'trajectory-data', 'analysis-results']; for (const poolName of poolNames) { const pool = gcOptimizer.getObjectPool(poolName); if (!pool) continue; // Benchmark with pool const withPoolSamples: number[] = []; for (let i = 0; i < 100; i++) { const startTime = performance.now(); const obj = pool.get(); // Simulate usage (obj as any).testData = 'x'.repeat(100); pool.return(obj); const endTime = performance.now(); withPoolSamples.push(endTime - startTime); } // Benchmark without pool (direct allocation) const withoutPoolSamples: number[] = []; for (let i = 0; i < 100; i++) { const startTime = performance.now(); // Direct allocation const obj = pool.config.factory(); (obj as any).testData = 'x'.repeat(100); // No return - let GC handle it const endTime = performance.now(); withoutPoolSamples.push(endTime - startTime); } const withPoolAvg = withPoolSamples.reduce((sum, s) => sum + s, 0) / withPoolSamples.length; const withoutPoolAvg = withoutPoolSamples.reduce((sum, s) => sum + s, 0) / withoutPoolSamples.length; poolBenchmarks.push({ operation: `object-pool-${poolName}`, baseline: withoutPoolAvg, optimized: withPoolAvg, improvement: (withoutPoolAvg - withPoolAvg) / withoutPoolAvg, memoryImpact: 0, // Would need more sophisticated measurement samples: withPoolSamples.length, variance: withPoolSamples.reduce((sum, s) => sum + Math.pow(s - withPoolAvg, 2), 0) / withPoolSamples.length, }); } // Validate pool performance poolBenchmarks.forEach(bench => { expect(bench.optimized).toBeLessThan(PERFORMANCE_THRESHOLDS.maxOperationLatency); // Pool should generally be faster or at least not significantly slower expect(bench.improvement).toBeGreaterThan(-0.5); // Not more than 50% slower }); }); test('should validate buffer reuse performance', async () => { const bufferSizes = [1024, 4096, 16384, 65536]; const bufferBenchmarks: Array<PerformanceBenchmark & { size: number }> = []; for (const size of bufferSizes) { // Benchmark with reuse const withReuseSamples: number[] = []; const buffers: Buffer[] = []; for (let i = 0; i < 200; i++) { const startTime = performance.now(); const buffer = gcOptimizer.getBuffer(size); buffer.fill(i % 256); buffers.push(buffer); const endTime = performance.now(); withReuseSamples.push(endTime - startTime); // Return half the buffers for reuse if (i % 2 === 0 && buffers.length > 1) { gcOptimizer.returnBuffer(buffers.shift()!); } } // Benchmark without reuse const withoutReuseSamples: number[] = []; for (let i = 0; i < 200; i++) { const startTime = performance.now(); const buffer = Buffer.alloc(size); buffer.fill(i % 256); const endTime = performance.now(); withoutReuseSamples.push(endTime - startTime); } const withReuseAvg = withReuseSamples.reduce((sum, s) => sum + s, 0) / withReuseSamples.length; const withoutReuseAvg = withoutReuseSamples.reduce((sum, s) => sum + s, 0) / withoutReuseSamples.length; bufferBenchmarks.push({ size, operation: `buffer-reuse-${size}`, baseline: withoutReuseAvg, optimized: withReuseAvg, improvement: (withoutReuseAvg - withReuseAvg) / withoutReuseAvg, memoryImpact: 0, samples: withReuseSamples.length, variance: withReuseSamples.reduce((sum, s) => sum + Math.pow(s - withReuseAvg, 2), 0) / withReuseSamples.length, }); // Cleanup buffers.forEach(buffer => gcOptimizer.returnBuffer(buffer)); } // Validate buffer reuse performance bufferBenchmarks.forEach(bench => { expect(bench.optimized).toBeLessThan(PERFORMANCE_THRESHOLDS.maxOperationLatency); // Buffer reuse should be beneficial for larger sizes if (bench.size >= 16384) { expect(bench.improvement).toBeGreaterThanOrEqual(-0.2); // Allow slight overhead for smaller benefits } }); }); }); describe('Memory Leak Detection Performance', () => { test('should validate leak detection latency and accuracy', async () => { const detectionMetrics = { detectionLatencies: [] as number[], accuracyScores: [] as number[], throughputMeasurements: [] as number[], memoryOverhead: [] as number[], }; // Create controlled leak scenarios const leakScenarios = [ { name: 'rapid-accumulation', operations: 500, size: 1000 }, { name: 'gradual-growth', operations: 200, size: 2000 }, { name: 'cyclic-references', operations: 100, size: 5000 }, ]; for (const scenario of leakScenarios) { const scenarioStart = Date.now(); const beforeMemory = process.memoryUsage().heapUsed; let leaksDetected = 0; // Set up detection monitoring const detectionHandler = () => leaksDetected++; memoryLeakDetector.on('memoryLeakDetected', detectionHandler); try { // Create leak pattern const leakyObjects: any[] = []; for (let i = 0; i < scenario.operations; i++) { const obj = { id: `${scenario.name}-${i}`, data: 'x'.repeat(scenario.size), timestamp: Date.now(), refs: [] as any[], }; // Create references based on scenario if (scenario.name === 'cyclic-references' && leakyObjects.length > 0) { obj.refs.push(leakyObjects[leakyObjects.length - 1]); leakyObjects[leakyObjects.length - 1].refs.push(obj); } leakyObjects.push(obj); memoryLeakDetector.trackObjectAllocation('performance-test', obj, scenario.size); // Periodic detection if (i % 50 === 0) { const detectionStart = performance.now(); await memoryLeakDetector.detectMemoryLeaks(); const detectionEnd = performance.now(); detectionMetrics.detectionLatencies.push(detectionEnd - detectionStart); } } // Final detection const finalDetectionStart = performance.now(); await memoryLeakDetector.detectMemoryLeaks(); const finalDetectionEnd = performance.now(); const scenarioEnd = Date.now(); const afterMemory = process.memoryUsage().heapUsed; detectionMetrics.detectionLatencies.push(finalDetectionEnd - finalDetectionStart); detectionMetrics.throughputMeasurements.push(scenario.operations / ((scenarioEnd - scenarioStart) / 1000)); detectionMetrics.memoryOverhead.push(afterMemory - beforeMemory); // Calculate accuracy (should detect leak in this scenario) const expectedDetections = 1; // At least one leak should be detected const accuracyScore = Math.min(1.0, leaksDetected / expectedDetections); detectionMetrics.accuracyScores.push(accuracyScore); } finally { memoryLeakDetector.off('memoryLeakDetected', detectionHandler); await memoryLeakDetector.forceCleanup(); } } // Validate detection performance const avgDetectionLatency = detectionMetrics.detectionLatencies.reduce((sum, lat) => sum + lat, 0) / detectionMetrics.detectionLatencies.length; const avgAccuracy = detectionMetrics.accuracyScores.reduce((sum, acc) => sum + acc, 0) / detectionMetrics.accuracyScores.length; const avgThroughput = detectionMetrics.throughputMeasurements.reduce((sum, thr) => sum + thr, 0) / detectionMetrics.throughputMeasurements.length; expect(avgDetectionLatency).toBeLessThan(1000); // Less than 1 second expect(avgAccuracy).toBeGreaterThan(0.7); // At least 70% accuracy expect(avgThroughput).toBeGreaterThan(50); // At least 50 operations/second }); test('should validate cleanup performance effectiveness', async () => { const cleanupBenchmarks: Array<{ type: string; beforeObjects: number; afterObjects: number; beforeMemory: number; afterMemory: number; duration: number; effectiveness: number; }> = []; const cleanupTypes = [ { name: 'force-cleanup', executor: () => memoryLeakDetector.forceCleanup() }, { name: 'gc-optimization', executor: () => gcOptimizer.forceGarbageCollection('cleanup-test') }, { name: 'component-cleanup', executor: () => Promise.all([ cacheManager['performCleanup'](), paretoFrontier.performMemoryCleanup(), ])}, ]; for (const cleanupType of cleanupTypes) { // Create objects to clean up const trackableObjects: any[] = []; for (let i = 0; i < 500; i++) { const obj = { id: `cleanup-test-${i}`, data: 'x'.repeat(2000), timestamp: Date.now(), }; trackableObjects.push(obj); await cacheManager.set(`cleanup-${i}`, obj); memoryLeakDetector.trackObjectAllocation('cleanup-test', obj, 2000); } const beforeObjects = 500; const beforeMemory = process.memoryUsage().heapUsed; // Execute cleanup const startTime = performance.now(); await cleanupType.executor(); const endTime = performance.now(); const afterMemory = process.memoryUsage().heapUsed; // Estimate remaining objects (simplified) const stats = memoryLeakDetector.getStatistics(); const cleanupComponent = stats.components.find(c => c.name === 'cleanup-test'); const afterObjects = cleanupComponent?.objectCount || 0; const effectiveness = Math.max(0, (beforeObjects - afterObjects) / beforeObjects); cleanupBenchmarks.push({ type: cleanupType.name, beforeObjects, afterObjects, beforeMemory, afterMemory, duration: endTime - startTime, effectiveness, }); // Reset for next test await memoryLeakDetector.forceCleanup(); await cacheManager.clear(); } // Validate cleanup performance cleanupBenchmarks.forEach(bench => { expect(bench.duration).toBeLessThan(5000); // Less than 5 seconds expect(bench.effectiveness).toBeGreaterThan(PERFORMANCE_THRESHOLDS.minCleanupEffectiveness); expect(bench.afterMemory).toBeLessThanOrEqual(bench.beforeMemory); // Should not increase memory }); // Force cleanup should be most effective const forceCleanup = cleanupBenchmarks.find(b => b.type === 'force-cleanup'); if (forceCleanup) { expect(forceCleanup.effectiveness).toBeGreaterThan(0.5); // At least 50% effective } }); }); describe('End-to-End Performance Validation', () => { test('should validate overall system performance with memory optimization', async () => { const systemBenchmark = { totalOperations: 0, averageLatency: 0, memoryEfficiency: 0, systemStability: true, performanceRegression: false, }; const operationLatencies: number[] = []; const memorySnapshots: number[] = []; Date.now(); const startMemory = process.memoryUsage().heapUsed; // Comprehensive system workout for (let round = 0; round < 50; round++) { const roundStart = performance.now(); // Mixed operations const operations = [ // Cache operations async () => { await cacheManager.set(`system-test-${round}`, { data: 'x'.repeat(1500), round, timestamp: Date.now(), }); }, // Frontier operations async () => { const candidate: PromptCandidate = { id: `system-candidate-${round}`, generation: Math.floor(round / 10) + 1, content: `System test candidate ${round}. ${'Content '.repeat(30)}`, averageScore: Math.random(), rolloutCount: round + 1, timestamp: new Date(), }; await paretoFrontier.addCandidate(candidate); }, // Memory management operations async () => { if (round % 10 === 0) { await gcOptimizer.forceGarbageCollection(`system-test-${round}`); } if (round % 15 === 0) { await memoryLeakDetector.detectMemoryLeaks(); } }, ]; await Promise.all(operations.map(op => op())); const roundEnd = performance.now(); operationLatencies.push(roundEnd - roundStart); memorySnapshots.push(process.memoryUsage().heapUsed); systemBenchmark.totalOperations += operations.length; // Check for system stability const currentMemory = process.memoryUsage().heapUsed; if (currentMemory > startMemory + PERFORMANCE_THRESHOLDS.maxMemoryGrowth) { systemBenchmark.systemStability = false; } // Micro-pause await new Promise(resolve => setImmediate(resolve)); } // Calculate performance metrics systemBenchmark.averageLatency = operationLatencies.reduce((sum, lat) => sum + lat, 0) / operationLatencies.length; // Check for performance regression const firstQuarter = operationLatencies.slice(0, Math.floor(operationLatencies.length / 4)); const lastQuarter = operationLatencies.slice(-Math.floor(operationLatencies.length / 4)); const firstAvg = firstQuarter.reduce((sum, lat) => sum + lat, 0) / firstQuarter.length; const lastAvg = lastQuarter.reduce((sum, lat) => sum + lat, 0) / lastQuarter.length; systemBenchmark.performanceRegression = (lastAvg / firstAvg) > 2.0; // More than 2x slower // Calculate memory efficiency const endMemory = process.memoryUsage().heapUsed; const memoryGrowth = endMemory - startMemory; const expectedGrowth = systemBenchmark.totalOperations * 1000; // Rough estimate systemBenchmark.memoryEfficiency = Math.max(0, 1 - (memoryGrowth / expectedGrowth)); // Final cleanup and measurement await gcOptimizer.forceGarbageCollection('system-test-final'); const finalMemory = process.memoryUsage().heapUsed; // Validate system performance expect(systemBenchmark.totalOperations).toBe(150); // 50 rounds * 3 operations expect(systemBenchmark.averageLatency).toBeLessThan(PERFORMANCE_THRESHOLDS.maxOperationLatency); expect(systemBenchmark.systemStability).toBe(true); expect(systemBenchmark.performanceRegression).toBe(false); expect(systemBenchmark.memoryEfficiency).toBeGreaterThan(0.3); // At least 30% efficient expect(finalMemory).toBeLessThan(endMemory + (10 * 1024 * 1024)); // Cleanup should help }); test('should measure memory efficiency metrics', async () => { const efficiencyMetrics: MemoryEfficiencyMetrics = { heapUtilization: 0, gcEfficiency: 0, objectPoolHitRate: 0, bufferReuseRate: 0, leakDetectionAccuracy: 0, cleanupEffectiveness: 0, }; // Measure heap utilization process.memoryUsage(); // Create measured workload for (let i = 0; i < 200; i++) { await cacheManager.set(`efficiency-${i}`, { data: 'x'.repeat(1000), index: i, }); } const workloadMemory = process.memoryUsage(); efficiencyMetrics.heapUtilization = workloadMemory.heapUsed / workloadMemory.heapTotal; // Measure GC efficiency const beforeGC = process.memoryUsage().heapUsed; await gcOptimizer.forceGarbageCollection('efficiency-test'); const afterGC = process.memoryUsage().heapUsed; efficiencyMetrics.gcEfficiency = Math.max(0, (beforeGC - afterGC) / beforeGC); // Measure object pool efficiency const candidatesPool = gcOptimizer.getObjectPool('candidates'); if (candidatesPool) { // Use pool heavily const objects = []; for (let i = 0; i < 100; i++) { objects.push(candidatesPool.get()); } for (const obj of objects) { candidatesPool.return(obj); } for (let i = 0; i < 100; i++) { objects.push(candidatesPool.get()); // Should hit pool } const poolStats = candidatesPool.getStatistics(); efficiencyMetrics.objectPoolHitRate = poolStats.hitRate; } // Measure buffer reuse efficiency const buffers: Buffer[] = []; for (let i = 0; i < 50; i++) { buffers.push(gcOptimizer.getBuffer(4096)); } for (const buffer of buffers) { gcOptimizer.returnBuffer(buffer); } // Get new buffers (should reuse) const reusedBuffers = []; for (let i = 0; i < 50; i++) { reusedBuffers.push(gcOptimizer.getBuffer(4096)); } efficiencyMetrics.bufferReuseRate = 0.8; // Estimate - would need instrumentation // Measure leak detection accuracy let leaksDetected = 0; memoryLeakDetector.on('memoryLeakDetected', () => leaksDetected++); // Create known leak for (let i = 0; i < 150; i++) { memoryLeakDetector.trackObjectAllocation('efficiency-test', { id: i }, 1000); } await memoryLeakDetector.detectMemoryLeaks(); efficiencyMetrics.leakDetectionAccuracy = leaksDetected > 0 ? 1.0 : 0.0; // Measure cleanup effectiveness const beforeCleanup = process.memoryUsage().heapUsed; await memoryLeakDetector.forceCleanup(); const afterCleanup = process.memoryUsage().heapUsed; efficiencyMetrics.cleanupEffectiveness = Math.max(0, (beforeCleanup - afterCleanup) / beforeCleanup); // Validate efficiency metrics expect(efficiencyMetrics.heapUtilization).toBeGreaterThan(0.1); // Some heap usage expect(efficiencyMetrics.heapUtilization).toBeLessThan(0.95); // Not near limit expect(efficiencyMetrics.gcEfficiency).toBeGreaterThan(PERFORMANCE_THRESHOLDS.minGCEfficiency); if (efficiencyMetrics.objectPoolHitRate > 0) { expect(efficiencyMetrics.objectPoolHitRate).toBeGreaterThan(PERFORMANCE_THRESHOLDS.minPoolHitRate); } expect(efficiencyMetrics.leakDetectionAccuracy).toBeGreaterThan(0.5); // Should detect obvious leaks expect(efficiencyMetrics.cleanupEffectiveness).toBeGreaterThan(0.0); // Some cleanup should occur }); }); describe('Performance Regression Detection', () => { test('should detect performance regressions in memory operations', async () => { const regressionMetrics = { baselinePerformance: new Map<string, number>(), currentPerformance: new Map<string, number>(), regressions: [] as Array<{ operation: string; regression: number }>, improvements: [] as Array<{ operation: string; improvement: number }>, }; const operations = [ 'cache_set', 'cache_get', 'frontier_add', 'gc_force', 'leak_detect', ]; // Establish baseline performance for (const operation of operations) { const samples: number[] = []; for (let i = 0; i < 20; i++) { const startTime = performance.now(); switch (operation) { case 'cache_set': await cacheManager.set(`baseline-${i}`, { data: 'test' }); break; case 'cache_get': await cacheManager.get(`baseline-${Math.floor(Math.random() * 20)}`); break; case 'frontier_add': await paretoFrontier.addCandidate({ id: `baseline-${i}`, generation: 1, content: 'baseline test', averageScore: Math.random(), rolloutCount: 1, timestamp: new Date(), }); break; case 'gc_force': await gcOptimizer.forceGarbageCollection('baseline'); break; case 'leak_detect': await memoryLeakDetector.detectMemoryLeaks(); break; } const endTime = performance.now(); samples.push(endTime - startTime); } const avgPerformance = samples.reduce((sum, s) => sum + s, 0) / samples.length; regressionMetrics.baselinePerformance.set(operation, avgPerformance); } // Add memory pressure and measure current performance await memoryLeakDetector.simulateMemoryPressure({ enabled: true, targetMemoryMB: 30, duration: 1000, escalationSteps: 2, }); for (const operation of operations) { const samples: number[] = []; for (let i = 0; i < 20; i++) { const startTime = performance.now(); switch (operation) { case 'cache_set': await cacheManager.set(`current-${i}`, { data: 'test' }); break; case 'cache_get': await cacheManager.get(`current-${Math.floor(Math.random() * 20)}`); break; case 'frontier_add': await paretoFrontier.addCandidate({ id: `current-${i}`, generation: 1, content: 'current test', averageScore: Math.random(), rolloutCount: 1, timestamp: new Date(), }); break; case 'gc_force': await gcOptimizer.forceGarbageCollection('current'); break; case 'leak_detect': await memoryLeakDetector.detectMemoryLeaks(); break; } const endTime = performance.now(); samples.push(endTime - startTime); } const avgPerformance = samples.reduce((sum, s) => sum + s, 0) / samples.length; regressionMetrics.currentPerformance.set(operation, avgPerformance); } // Analyze for regressions and improvements for (const operation of operations) { const baseline = regressionMetrics.baselinePerformance.get(operation); const current = regressionMetrics.currentPerformance.get(operation); if (!baseline || !current) { continue; // Skip if metrics are missing } const ratio = current / baseline; if (ratio > 1.5) { // 50% slower regressionMetrics.regressions.push({ operation, regression: ratio - 1, }); } else if (ratio < 0.8) { // 20% faster regressionMetrics.improvements.push({ operation, improvement: 1 - ratio, }); } } // Validate regression detection expect(regressionMetrics.baselinePerformance.size).toBe(operations.length); expect(regressionMetrics.currentPerformance.size).toBe(operations.length); // Under memory pressure, some operations may be slower, but not excessively regressionMetrics.regressions.forEach(regression => { expect(regression.regression).toBeLessThan(4.0); // Not more than 5x slower }); // Overall system should maintain reasonable performance const totalOperations = operations.length; const severeRegressions = regressionMetrics.regressions.filter(r => r.regression > 2.0).length; expect(severeRegressions / totalOperations).toBeLessThan(0.5); // Less than 50% severe regressions }); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sloth-wq/prompt-auto-optimizer-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server