UNPKG

aios-core

Version:

Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework

758 lines (657 loc) 23.4 kB
const fs = require('fs').promises; const path = require('path'); const chalk = require('chalk'); /** * Performance bottleneck analyzer for Synkra AIOS framework * Identifies performance issues and optimization opportunities */ class PerformanceAnalyzer { constructor(options = {}) { this.rootPath = options.rootPath || process.cwd(); this.thresholds = { fileSize: 50 * 1024, // 50KB functionLength: 50, // lines cyclomaticComplexity: 10, nestingDepth: 5, importCount: 20, unusedCode: 0.1, // 10% unused code ratio }; this.performancePatterns = { // Sync operations that should be async syncOperations: [ /fs\.readFileSync/g, /fs\.writeFileSync/g, /fs\.existsSync/g, /JSON\.parse\(\s*fs\.readFileSync/g, ], // Memory-intensive patterns memoryIssues: [ /\.map\(\s*.*\.map\(/g, // Nested maps /new Array\(\d{4,}\)/g, // Large arrays /JSON\.stringify.*JSON\.parse/g, // Unnecessary serialization /require\(\s*['"`][^'"`]+\.json['"`]\s*\)/g, // Large JSON imports ], // Performance anti-patterns antiPatterns: [ /console\.log/g, // Console logs in production /debugger/g, // Debugger statements /setTimeout\(\s*.*,\s*0\s*\)/g, // Unnecessary setTimeout /setInterval\(\s*.*,\s*[0-9]{1,2}\s*\)/g, // High-frequency intervals ], // Inefficient loops inefficientLoops: [ /for\s*\(\s*.*\.length\s*;/g, // Length calculated in loop condition /while\s*\(\s*true\s*\)/g, // Infinite loops /forEach.*forEach/g, // Nested forEach ], }; } /** * Analyze performance across all components */ async analyzePerformance(components) { const analysis = { timestamp: new Date().toISOString(), overall_score: 0, bottlenecks: [], optimization_opportunities: [], memory_issues: [], async_opportunities: [], code_quality_issues: [], file_size_issues: [], complexity_issues: [], recommendations: [], metrics: { total_files_analyzed: 0, total_issues_found: 0, critical_issues: 0, high_priority_issues: 0, medium_priority_issues: 0, low_priority_issues: 0, }, }; try { console.log(chalk.blue('🔍 Analyzing performance bottlenecks...')); // Analyze each component for (const component of components) { const componentAnalysis = await this.analyzeComponentPerformance(component); // Aggregate results analysis.bottlenecks.push(...componentAnalysis.bottlenecks); analysis.optimization_opportunities.push(...componentAnalysis.optimizations); analysis.memory_issues.push(...componentAnalysis.memory_issues); analysis.async_opportunities.push(...componentAnalysis.async_opportunities); analysis.code_quality_issues.push(...componentAnalysis.quality_issues); analysis.file_size_issues.push(...componentAnalysis.file_size_issues); analysis.complexity_issues.push(...componentAnalysis.complexity_issues); analysis.metrics.total_files_analyzed++; } // Calculate overall metrics analysis.overall_score = this.calculateOverallScore(analysis); analysis.metrics.total_issues_found = this.countTotalIssues(analysis); analysis.metrics = this.calculateIssuePriorities(analysis); analysis.recommendations = this.generatePerformanceRecommendations(analysis); console.log(chalk.green('✅ Performance analysis completed')); console.log(chalk.gray(` Files analyzed: ${analysis.metrics.total_files_analyzed}`)); console.log(chalk.gray(` Issues found: ${analysis.metrics.total_issues_found}`)); console.log(chalk.gray(` Overall score: ${analysis.overall_score}/10`)); return analysis; } catch (error) { console.error(chalk.red(`Performance analysis failed: ${error.message}`)); throw error; } } /** * Analyze performance for a single component */ async analyzeComponentPerformance(component) { const analysis = { component_id: component.id, component_type: component.type, bottlenecks: [], optimizations: [], memory_issues: [], async_opportunities: [], quality_issues: [], file_size_issues: [], complexity_issues: [], }; try { // Only analyze JavaScript files and executable components if (!this.shouldAnalyzeComponent(component)) { return analysis; } const filePath = path.join(this.rootPath, component.file_path); const content = await fs.readFile(filePath, 'utf-8'); const stats = await fs.stat(filePath); // File size analysis if (stats.size > this.thresholds.fileSize) { analysis.file_size_issues.push({ component: component.id, issue: `Large file size: ${this.formatBytes(stats.size)}`, severity: stats.size > this.thresholds.fileSize * 2 ? 'high' : 'medium', recommendation: 'Consider breaking down into smaller modules', impact: 'high', effort: 'medium', }); } // Synchronous operations analysis const syncIssues = this.findSyncOperations(content, component); analysis.async_opportunities.push(...syncIssues); // Memory usage analysis const memoryIssues = this.findMemoryIssues(content, component); analysis.memory_issues.push(...memoryIssues); // Performance anti-patterns const antiPatterns = this.findAntiPatterns(content, component); analysis.quality_issues.push(...antiPatterns); // Loop efficiency analysis const loopIssues = this.findLoopIssues(content, component); analysis.bottlenecks.push(...loopIssues); // Function complexity analysis const complexityIssues = this.analyzeComplexity(content, component); analysis.complexity_issues.push(...complexityIssues); // Import/require analysis const importIssues = this.analyzeImports(content, component); analysis.optimizations.push(...importIssues); // Dead code analysis const deadCodeIssues = await this.findDeadCode(content, component); analysis.optimizations.push(...deadCodeIssues); } catch (error) { console.warn(chalk.yellow(`Failed to analyze performance for ${component.id}: ${error.message}`)); } return analysis; } /** * Find synchronous operations that should be async */ findSyncOperations(content, component) { const issues = []; const lines = content.split('\n'); this.performancePatterns.syncOperations.forEach(pattern => { lines.forEach((line, index) => { const matches = line.match(pattern); if (matches) { matches.forEach(match => { issues.push({ component: component.id, issue: `Synchronous operation: ${match}`, line: index + 1, context: line.trim(), severity: 'high', recommendation: 'Convert to async equivalent', impact: 'high', effort: 'low', }); }); } }); }); return issues; } /** * Find memory-intensive patterns */ findMemoryIssues(content, component) { const issues = []; const lines = content.split('\n'); this.performancePatterns.memoryIssues.forEach(pattern => { lines.forEach((line, index) => { const matches = line.match(pattern); if (matches) { matches.forEach(match => { let severity = 'medium'; let recommendation = 'Optimize memory usage'; if (match.includes('new Array')) { severity = 'high'; recommendation = 'Use array literals or streaming for large datasets'; } else if (match.includes('JSON.stringify.*JSON.parse')) { recommendation = 'Use direct object assignment or deep clone utilities'; } else if (match.includes('.map(.*map(')) { recommendation = 'Combine operations or use more efficient iteration'; } issues.push({ component: component.id, issue: `Memory-intensive pattern: ${match}`, line: index + 1, context: line.trim(), severity, recommendation, impact: 'medium', effort: 'medium', }); }); } }); }); return issues; } /** * Find performance anti-patterns */ findAntiPatterns(content, component) { const issues = []; const lines = content.split('\n'); this.performancePatterns.antiPatterns.forEach(pattern => { lines.forEach((line, index) => { const matches = line.match(pattern); if (matches) { matches.forEach(match => { let severity = 'low'; let recommendation = 'Remove or optimize'; if (match.includes('console.log')) { recommendation = 'Remove console.log statements from production code'; } else if (match.includes('debugger')) { severity = 'medium'; recommendation = 'Remove debugger statements'; } else if (match.includes('setTimeout')) { recommendation = 'Use proper async/await or promises instead'; } issues.push({ component: component.id, issue: `Performance anti-pattern: ${match}`, line: index + 1, context: line.trim(), severity, recommendation, impact: 'low', effort: 'low', }); }); } }); }); return issues; } /** * Find inefficient loop patterns */ findLoopIssues(content, component) { const issues = []; const lines = content.split('\n'); this.performancePatterns.inefficientLoops.forEach(pattern => { lines.forEach((line, index) => { const matches = line.match(pattern); if (matches) { matches.forEach(match => { let severity = 'medium'; let recommendation = 'Optimize loop structure'; if (match.includes('.length')) { recommendation = 'Cache array length in variable before loop'; } else if (match.includes('while(true)')) { severity = 'high'; recommendation = 'Add proper exit condition to prevent infinite loops'; } else if (match.includes('forEach.*forEach')) { recommendation = 'Consider using nested for loops or array methods like flatMap'; } issues.push({ component: component.id, issue: `Inefficient loop: ${match}`, line: index + 1, context: line.trim(), severity, recommendation, impact: 'medium', effort: 'low', }); }); } }); }); return issues; } /** * Analyze function complexity */ analyzeComplexity(content, component) { const issues = []; const functions = this.extractFunctions(content); functions.forEach(func => { // Check function length if (func.lines > this.thresholds.functionLength) { issues.push({ component: component.id, issue: `Long function: ${func.name} (${func.lines} lines)`, line: func.startLine, severity: func.lines > this.thresholds.functionLength * 2 ? 'high' : 'medium', recommendation: 'Break down into smaller functions', impact: 'medium', effort: 'medium', }); } // Check cyclomatic complexity if (func.complexity > this.thresholds.cyclomaticComplexity) { issues.push({ component: component.id, issue: `High complexity: ${func.name} (complexity: ${func.complexity})`, line: func.startLine, severity: func.complexity > this.thresholds.cyclomaticComplexity * 1.5 ? 'high' : 'medium', recommendation: 'Reduce conditional complexity', impact: 'high', effort: 'high', }); } // Check nesting depth if (func.nestingDepth > this.thresholds.nestingDepth) { issues.push({ component: component.id, issue: `Deep nesting: ${func.name} (depth: ${func.nestingDepth})`, line: func.startLine, severity: 'medium', recommendation: 'Reduce nesting depth using early returns or guard clauses', impact: 'medium', effort: 'medium', }); } }); return issues; } /** * Analyze imports and requires */ analyzeImports(content, component) { const issues = []; const imports = this.extractImports(content); if (imports.length > this.thresholds.importCount) { issues.push({ component: component.id, issue: `Too many imports: ${imports.length}`, severity: 'medium', recommendation: 'Consider breaking down module or using dynamic imports', impact: 'low', effort: 'medium', }); } // Find unused imports (basic heuristic) const unusedImports = imports.filter(imp => { const usage = content.split(imp.name).length - 1; return usage <= 1; // Only appears in import statement }); if (unusedImports.length > 0) { issues.push({ component: component.id, issue: `Unused imports: ${unusedImports.map(i => i.name).join(', ')}`, severity: 'low', recommendation: 'Remove unused imports', impact: 'low', effort: 'low', }); } return issues; } /** * Find dead code (unused functions, variables) */ async findDeadCode(content, component) { const issues = []; // This is a simplified implementation // A full implementation would analyze the entire codebase for usage const functions = this.extractFunctions(content); const exports = this.extractExports(content); // Check for functions that are defined but never called within the file functions.forEach(func => { if (!func.name.startsWith('_') && !exports.includes(func.name)) { const usage = content.split(func.name).length - 1; if (usage <= 1) { // Only appears in definition issues.push({ component: component.id, issue: `Potentially unused function: ${func.name}`, line: func.startLine, severity: 'low', recommendation: 'Remove if truly unused or export if needed elsewhere', impact: 'low', effort: 'low', }); } } }); return issues; } /** * Extract function information from code */ extractFunctions(content) { const functions = []; const lines = content.split('\n'); const functionRegex = /(?:function\s+(\w+)|(\w+)\s*[:=]\s*(?:async\s+)?function|(?:async\s+)?(\w+)\s*\([^)]*\)\s*(?:=>|{))/g; lines.forEach((line, index) => { const matches = [...line.matchAll(functionRegex)]; matches.forEach(match => { const name = match[1] || match[2] || match[3] || 'anonymous'; // Calculate function metrics (simplified) const funcInfo = { name, startLine: index + 1, lines: this.estimateFunctionLength(lines, index), complexity: this.estimateComplexity(lines, index), nestingDepth: this.estimateNestingDepth(lines, index), }; functions.push(funcInfo); }); }); return functions; } /** * Extract import information */ extractImports(content) { const imports = []; const importRegex = /(?:import\s+(?:(\w+)|\{([^}]+)\}|.*)\s+from\s+['"`]([^'"`]+)['"`]|const\s+(?:(\w+)|\{([^}]+)\})\s*=\s*require\(['"`]([^'"`]+)['"`]\))/g; const matches = [...content.matchAll(importRegex)]; matches.forEach(match => { const defaultImport = match[1] || match[4]; const namedImports = match[2] || match[5]; const source = match[3] || match[6]; if (defaultImport) { imports.push({ name: defaultImport, source, type: 'default' }); } if (namedImports) { namedImports.split(',').forEach(name => { imports.push({ name: name.trim(), source, type: 'named' }); }); } }); return imports; } /** * Extract export information */ extractExports(content) { const exports = []; const exportRegex = /(?:export\s+(?:default\s+)?(?:function\s+(\w+)|class\s+(\w+)|(?:const|let|var)\s+(\w+))|module\.exports\s*=\s*(\w+))/g; const matches = [...content.matchAll(exportRegex)]; matches.forEach(match => { const name = match[1] || match[2] || match[3] || match[4]; if (name) exports.push(name); }); return exports; } /** * Estimate function length (simplified) */ estimateFunctionLength(lines, startIndex) { let braceCount = 0; let lineCount = 0; let inFunction = false; for (let i = startIndex; i < lines.length; i++) { const line = lines[i]; lineCount++; // Count braces to find function end for (const char of line) { if (char === '{') { braceCount++; inFunction = true; } else if (char === '}') { braceCount--; if (inFunction && braceCount === 0) { return lineCount; } } } // Safety limit if (lineCount > 200) break; } return lineCount; } /** * Estimate cyclomatic complexity (simplified) */ estimateComplexity(lines, startIndex) { let complexity = 1; // Base complexity const complexityKeywords = ['if', 'else', 'while', 'for', 'switch', 'case', 'catch', '&&', '||', '?']; const functionLines = lines.slice(startIndex, startIndex + this.estimateFunctionLength(lines, startIndex)); functionLines.forEach(line => { complexityKeywords.forEach(keyword => { const matches = line.match(new RegExp(`\\b${keyword}\\b`, 'g')); if (matches) { complexity += matches.length; } }); }); return complexity; } /** * Estimate nesting depth (simplified) */ estimateNestingDepth(lines, startIndex) { let maxDepth = 0; let currentDepth = 0; const functionLines = lines.slice(startIndex, startIndex + this.estimateFunctionLength(lines, startIndex)); functionLines.forEach(line => { for (const char of line) { if (char === '{') { currentDepth++; maxDepth = Math.max(maxDepth, currentDepth); } else if (char === '}') { currentDepth--; } } }); return maxDepth; } /** * Calculate overall performance score */ calculateOverallScore(analysis) { let score = 10; const penalties = { critical: 2, high: 1, medium: 0.5, low: 0.1, }; // Apply penalties based on issue severity [...analysis.bottlenecks, ...analysis.memory_issues, ...analysis.async_opportunities, ...analysis.code_quality_issues, ...analysis.file_size_issues, ...analysis.complexity_issues] .forEach(issue => { score -= penalties[issue.severity] || 0.1; }); return Math.max(0, Math.round(score * 10) / 10); } /** * Count total issues */ countTotalIssues(analysis) { return analysis.bottlenecks.length + analysis.memory_issues.length + analysis.async_opportunities.length + analysis.code_quality_issues.length + analysis.file_size_issues.length + analysis.complexity_issues.length; } /** * Calculate issue priorities */ calculateIssuePriorities(analysis) { const metrics = analysis.metrics; const allIssues = [ ...analysis.bottlenecks, ...analysis.memory_issues, ...analysis.async_opportunities, ...analysis.code_quality_issues, ...analysis.file_size_issues, ...analysis.complexity_issues, ]; metrics.critical_issues = allIssues.filter(i => i.severity === 'critical').length; metrics.high_priority_issues = allIssues.filter(i => i.severity === 'high').length; metrics.medium_priority_issues = allIssues.filter(i => i.severity === 'medium').length; metrics.low_priority_issues = allIssues.filter(i => i.severity === 'low').length; return metrics; } /** * Generate performance recommendations */ generatePerformanceRecommendations(analysis) { const recommendations = []; // Critical issues if (analysis.metrics.critical_issues > 0) { recommendations.push({ priority: 'critical', category: 'immediate_action', message: `${analysis.metrics.critical_issues} critical performance issues require immediate attention`, action: 'Fix critical bottlenecks before deployment', }); } // High severity issues if (analysis.metrics.high_priority_issues > 5) { recommendations.push({ priority: 'high', category: 'performance', message: `${analysis.metrics.high_priority_issues} high-priority performance issues detected`, action: 'Address synchronous operations and complexity issues', }); } // Memory issues if (analysis.memory_issues.length > 0) { recommendations.push({ priority: 'medium', category: 'memory', message: `${analysis.memory_issues.length} memory optimization opportunities found`, action: 'Implement memory-efficient patterns and data structures', }); } // File size issues if (analysis.file_size_issues.length > 0) { recommendations.push({ priority: 'medium', category: 'modularity', message: `${analysis.file_size_issues.length} files are too large`, action: 'Break down large files into smaller, focused modules', }); } // Overall score if (analysis.overall_score < 7) { recommendations.push({ priority: 'high', category: 'general', message: `Overall performance score is ${analysis.overall_score}/10`, action: 'Comprehensive performance review and optimization needed', }); } return recommendations; } /** * Check if component should be analyzed */ shouldAnalyzeComponent(component) { const analyzableTypes = ['utility', 'task']; const analyzableExtensions = ['.js', '.mjs', '.ts']; if (!analyzableTypes.includes(component.type)) { return false; } if (component.file_path) { const ext = path.extname(component.file_path).toLowerCase(); return analyzableExtensions.includes(ext); } return false; } /** * Format bytes for display */ formatBytes(bytes) { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } } module.exports = PerformanceAnalyzer;