Performance Audit
Decision Tree
code
Performance issue → Where is it slow?
├─ API response time → Check DB queries, N+1, missing indexes
├─ Page load → Check bundle size, images, network waterfall
├─ Memory growing → Check for leaks (event listeners, closures, unclosed resources)
├─ Build/CI slow → Check caching, parallelization, unnecessary steps
└─ Unknown → Profile first, then follow the data
Phases
code
Phase 1: Measure (baseline) → Phase 2: Identify (profile) → Phase 3: Fix → Phase 4: Verify (compare to baseline)
Key Metrics
| Metric | Target | Tool |
|---|---|---|
| API response time (p95) | <200ms | Load test, APM |
| Time to First Byte | <100ms | curl -w, Lighthouse |
| First Contentful Paint | <1.5s | Lighthouse, WebPageTest |
| Memory usage | Stable over time | top, htop, profiler |
| DB query time | <50ms per query | Query logs, EXPLAIN |
| Bundle size (JS) | <200KB gzipped | npx bundlesize, webpack-bundle-analyzer |
Profiling Commands
bash
# Node.js node --prof app.js # V8 profiler clinic doctor -- node app.js # Auto-diagnose (npm i -g clinic) # Python python -m cProfile -s cumtime app.py py-spy record -o profile.svg -- python app.py # Database EXPLAIN ANALYZE SELECT ...; # PostgreSQL
Common Bottlenecks
| Pattern | Symptom | Fix |
|---|---|---|
| N+1 queries | Slow list pages, many DB calls | Eager loading, JOIN, batch fetch |
| Missing index | Slow queries on large tables | Add index on WHERE/JOIN columns |
| Unbounded query | Memory spike, timeout | Add LIMIT, pagination |
| Synchronous I/O | Blocked event loop | async/await, worker threads |
| Large payload | Slow API, high bandwidth | Pagination, field selection, compression |
| No caching | Repeated expensive operations | Redis, in-memory cache, HTTP cache headers |
| Unoptimized images | Slow page load | WebP, lazy loading, srcset |
| Memory leak | Growing memory, eventual crash | Heap snapshots, check event listeners/closures |
Database Query Analysis
sql
-- PostgreSQL: Find slow queries SELECT query, mean_exec_time, calls FROM pg_stat_statements ORDER BY mean_exec_time DESC LIMIT 10; -- Find missing indexes SELECT relname, seq_scan, idx_scan FROM pg_stat_user_tables WHERE seq_scan > idx_scan ORDER BY seq_scan DESC;
Output Format
code
[IMPACT: HIGH|MEDIUM|LOW] Category - Finding Measured: Current value Target: Expected value Fix: Specific optimization