codeSentry / codesentry-frontend /backend /agents /performance_agent.py
YashashviAlva's picture
Initial commit for HF Spaces deploy
7b4f5dd
"""
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",
}