Spaces:
Running
Running
File size: 3,314 Bytes
7b4f5dd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | """
Performance Agent — detects N+1 queries, memory leaks,
unoptimized tensor ops, and redundant re-renders.
"""
import asyncio
import re
from typing import AsyncGenerator
PERF_PATTERNS = [
{
"id": "PERF-001",
"name": "N+1 Query Pattern",
"pattern": r'for.*(await|async).*query|forEach.*db\.|for.*execute\(',
"severity": "high",
"suggestion": "Use a single JOIN or batch query to eliminate N+1.",
"description": "Database queries inside loops cause N+1 performance degradation.",
},
{
"id": "PERF-002",
"name": "Memory Leak (Missing Cleanup)",
"pattern": r'addEventListener|setInterval|setTimeout(?!.*clearTimeout)',
"severity": "medium",
"suggestion": "Add cleanup functions to remove event listeners and clear timers.",
"description": "Event listeners or timers without cleanup cause memory leaks over time.",
},
{
"id": "PERF-003",
"name": "CPU Tensor Operation (use GPU)",
"pattern": r"\.to\(['\"]cpu['\"]\)|\.cpu\(\)|device=['\"]cpu['\"]",
"severity": "high",
"suggestion": "Move tensor operations to GPU with .to('cuda') and use torch.no_grad() for inference.",
"description": "Tensor ops on CPU when GPU is available slows inference significantly.",
},
{
"id": "PERF-004",
"name": "Missing React Memoization",
"pattern": r'const \w+ = \(\{.*\}\) =>|function \w+\(\{.*\}\)',
"severity": "low",
"suggestion": "Wrap expensive components with React.memo() and use useCallback/useMemo.",
"description": "Missing memoization causes unnecessary re-renders on every parent update.",
},
]
class PerformanceAgent:
async def analyze(self, code: str, language: str) -> AsyncGenerator[tuple[str, dict], None]:
lines = code.split("\n")
found = 0
for i, pattern_def in enumerate(PERF_PATTERNS):
await asyncio.sleep(0.6)
pct = int((i / len(PERF_PATTERNS)) * 100)
yield "progress", {
"agent": "performance",
"percent": pct,
"filesScanned": i + 1,
"message": f"Checking for {pattern_def['name']}...",
}
for line_num, line in enumerate(lines, 1):
if re.search(pattern_def["pattern"], line, re.IGNORECASE):
found += 1
yield "finding", {
"agent": "performance",
"id": pattern_def["id"],
"title": pattern_def["name"],
"severity": pattern_def["severity"],
"cwe": None,
"description": pattern_def["description"],
"file": "uploaded_code.py",
"line": line_num,
"code": line.strip(),
"suggestion": pattern_def["suggestion"],
"fixAvailable": False,
}
break
yield "progress", {
"agent": "performance",
"percent": 100,
"filesScanned": len(PERF_PATTERNS),
"message": f"Performance analysis complete — {found} issues found",
}
|