Download scripts/analyze_performance.py from techprotrade/annator-full-system: direct link, hf CLI and curl.
- Browser
- Download file 7.98 kB
-
https://huggingface.co/spaces/techprotrade/annator-full-system/resolve/main/scripts/analyze_performance.py
- Command line
-
hf download hf://spaces/techprotrade/annator-full-system/scripts/analyze_performance.py
-
curl -L -o analyze_performance.py https://huggingface.co/spaces/techprotrade/annator-full-system/resolve/main/scripts/analyze_performance.py
7.98 kB
| #!/usr/bin/env python3 | |
| """ | |
| Performance Analysis Script for Atom Backend | |
| Analyzes the codebase for: | |
| 1. N+1 query problems | |
| 2. Missing database indexes | |
| 3. Caching opportunities | |
| 4. Slow endpoints | |
| Usage: | |
| python scripts/analyze_performance.py | |
| """ | |
| import os | |
| import sys | |
| import logging | |
| from pathlib import Path | |
| from typing import Dict, List, Set | |
| # Add backend to path | |
| sys.path.insert(0, str(Path(__file__).parent.parent)) | |
| logging.basicConfig(level=logging.INFO, format='%(message)s') | |
| logger = logging.getLogger(__name__) | |
| # Results storage | |
| results = { | |
| "n_plus_one_issues": [], | |
| "missing_indexes": [], | |
| "caching_opportunities": [], | |
| "slow_endpoints": [], | |
| } | |
| def analyze_n_plus_one_queries(): | |
| """Analyze code for potential N+1 query problems""" | |
| logger.info("Analyzing for N+1 query patterns...") | |
| issues_found = 0 | |
| # Check routes for loop queries | |
| for file in Path("backend/api").glob("*.py"): | |
| try: | |
| content = file.read_text() | |
| # Pattern: loops with db.query inside | |
| if "for " in content and ".query(" in content: | |
| lines = content.split('\n') | |
| for i, line in enumerate(lines): | |
| if "for " in line and ".query(" in content[i:i+5]: # Check nearby lines | |
| results["n_plus_one_issues"].append({ | |
| "file": str(file), | |
| "line": i + 1, | |
| "pattern": "Loop with query", | |
| "code": line.strip() | |
| }) | |
| issues_found += 1 | |
| except Exception as e: | |
| logger.warning(f"Could not analyze {file}: {e}") | |
| logger.info(f"Found {issues_found} potential N+1 query issues") | |
| def analyze_missing_indexes(): | |
| """Analyze models for missing database indexes""" | |
| logger.info("Analyzing for missing database indexes...") | |
| # Read models file | |
| models_file = Path(__file__).parent.parent / "backend" / "core" / "models.py" | |
| if not models_file.exists(): | |
| logger.warning(f"models.py not found at {models_file}") | |
| return | |
| content = models_file.read_text() | |
| lines = content.split('\n') | |
| # Find ForeignKey columns without index=True | |
| in_model = False | |
| current_model = None | |
| current_table = None | |
| for i, line in enumerate(lines): | |
| # Check if we're in a class definition | |
| if line.strip().startswith("class "): | |
| in_model = True | |
| parts = line.strip().split() | |
| if len(parts) >= 2: | |
| current_model = parts[1].strip("(") | |
| # Check for __tablename__ | |
| if '__tablename__' in line: | |
| parts = line.split('=') | |
| if len(parts) >= 2: | |
| current_table = parts[1].strip().strip('"') | |
| # Check for ForeignKey without index | |
| if 'ForeignKey(' in line and 'index=' not in line: | |
| # This is a foreign key without an index | |
| results["missing_indexes"].append({ | |
| "model": current_model, | |
| "table": current_table, | |
| "line": i + 1, | |
| "code": line.strip() | |
| }) | |
| logger.info(f"Found {len(results['missing_indexes'])} foreign keys without indexes") | |
| def analyze_caching_opportunities(): | |
| """Analyze code for caching opportunities""" | |
| logger.info("Analyzing for caching opportunities...") | |
| backend_path = Path(__file__).parent.parent / "backend" | |
| # Check for patterns | |
| for file in (backend_path / "core").glob("*.py"): | |
| try: | |
| content = file.read_text() | |
| if "AgentRegistry" in content and ".query(" in content: | |
| results["caching_opportunities"].append({ | |
| "type": "agent_registry", | |
| "file": str(file.relative_to(Path(__file__).parent.parent)), | |
| "recommendation": "Cache AgentRegistry queries by agent_id", | |
| "priority": "HIGH" | |
| }) | |
| if "User" in content and ".query(" in content: | |
| results["caching_opportunities"].append({ | |
| "type": "user_queries", | |
| "file": str(file.relative_to(Path(__file__).parent.parent)), | |
| "recommendation": "Cache User lookups by user_id", | |
| "priority": "MEDIUM" | |
| }) | |
| except Exception as e: | |
| logger.warning(f"Could not analyze {file}: {e}") | |
| logger.info(f"Found {len(results['caching_opportunities'])} caching opportunities") | |
| def generate_recommendations(): | |
| """Generate performance improvement recommendations""" | |
| logger.info("\n" + "="*80) | |
| logger.info("PERFORMANCE ANALYSIS RESULTS") | |
| logger.info("="*80 + "\n") | |
| # N+1 Queries | |
| logger.info("π N+1 QUERY ISSUES") | |
| if results["n_plus_one_issues"]: | |
| logger.info(f"Found {len(results['n_plus_one_issues'])} potential issues:") | |
| for issue in results["n_plus_one_issues"][:5]: # Show first 5 | |
| logger.info(f" - {issue['file']}:{issue['line']}: {issue['pattern']}") | |
| if len(results["n_plus_one_issues"]) > 5: | |
| logger.info(f" ... and {len(results['n_plus_one_issues']) - 5} more") | |
| else: | |
| logger.info(" No N+1 query issues found") | |
| # Missing Indexes | |
| logger.info("\nπ MISSING DATABASE INDEXES") | |
| if results["missing_indexes"]: | |
| logger.info(f"Found {len(results['missing_indexes'])} foreign keys without indexes:") | |
| for issue in results["missing_indexes"][:5]: | |
| logger.info(f" - {issue['model']}: {issue['code']}") | |
| if len(results["missing_indexes"]) > 5: | |
| logger.info(f" ... and {len(results['missing_indexes']) - 5} more") | |
| logger.info("\n π‘ Recommendation: Add index=True to ForeignKey columns") | |
| logger.info(" Example: user_id = Column(String(36), ForeignKey(\"users.id\"), index=True)") | |
| else: | |
| logger.info(" All foreign keys have indexes") | |
| # Caching Opportunities | |
| logger.info("\nπ CACHING OPPORTUNITIES") | |
| if results["caching_opportunities"]: | |
| logger.info(f"Found {len(results['caching_opportunities'])} caching opportunities:") | |
| for opp in results["caching_opportunities"]: | |
| logger.info(f" - [{opp['priority']}] {opp['type']}: {opp['recommendation']}") | |
| logger.info(f" File: {opp.get('file', 'N/A')}") | |
| logger.info("\n π‘ Recommended cache implementations:") | |
| logger.info(" - Use Redis from core/governance_cache.py for hot data") | |
| logger.info(" - Cache user sessions, agent registry, configuration") | |
| logger.info(" - Set appropriate TTL (5-60 minutes for most data)") | |
| else: | |
| logger.info(" No obvious caching opportunities found") | |
| logger.info("\n" + "="*80) | |
| logger.info("RECOMMENDATIONS") | |
| logger.info("="*80 + "\n") | |
| logger.info("1. Add indexes to foreign keys (see detailed list above)") | |
| logger.info("2. Implement caching for frequently accessed data") | |
| logger.info("3. Use SQLAlchemy's joinedload() for eager loading relationships") | |
| logger.info("4. Add pagination to endpoints that return lists") | |
| logger.info("5. Use selectin/prefetch for optimizing relationship loading") | |
| logger.info("\nSee docs/DATABASE_MODEL_BEST_PRACTICES.md for implementation patterns") | |
| if __name__ == "__main__": | |
| try: | |
| analyze_n_plus_one_queries() | |
| analyze_missing_indexes() | |
| analyze_caching_opportunities() | |
| generate_recommendations() | |
| # Save results to file | |
| import json | |
| with open("scripts/performance_analysis_results.json", "w") as f: | |
| json.dump(results, f, indent=2) | |
| logger.info("\nβ Analysis complete. Results saved to scripts/performance_analysis_results.json") | |
| except Exception as e: | |
| logger.error(f"Error during analysis: {e}") | |
| import traceback | |
| traceback.print_exc() | |
| sys.exit(1) | |