SuperAPI AI Directory

performance-audit

Office & productivity

View repository

Updated 10-16 07:26

About this skill

Performance Audit

The Law

A PERFORMANCE CLAIM WITHOUT NUMBERS IS AN OPINION.
"I think it's faster" is not a result.
"p95 latency dropped from 480ms to 42ms on a 1000-item dataset" is a result.

When to Use

  • Before any optimisation work (establish baseline first)
  • When a performance regression is reported
  • As a pre-release gate on performance-critical features
  • After an optimisation to validate the improvement

Audit Workflow

Step 1: Define the Performance Goal

Before measuring anything, define what "good" looks like:

Category Example target
API latency p95 < 200ms at 100 concurrent users
Page load First Contentful Paint < 1.5s on 4G
Mobile frame rate 60fps during scroll, 0 jank frames
Build time Full build < 3 minutes
Memory Peak heap < 512MB under load
Bundle size JS bundle < 250KB gzipped

If no target exists, the first audit establishes the baseline that becomes the target.

Step 2: Measure the Baseline

Run the benchmark before any changes. Record:

  • Tool used and exact command
  • Input size and conditions
  • Raw numbers (min, p50, p95, p99, max)
  • System state (CPU, memory, concurrent users)
## Baseline — YYYY-MM-DD

**Feature:** User search endpoint
**Tool:** k6
**Command:** `k6 run --vus 50 --duration 60s scripts/search-load-test.js`
**Input:** 1000-user dataset, query="test"

| Metric | Value |
|--------|-------|
| p50 | 45ms |
| p95 | 380ms |
| p99 | 720ms |
| Error rate | 0.2% |
| Throughput | 210 req/s |

Step 3: Profile — Find the Real Bottleneck

Use the appropriate tool for the stack. Read the output. Don't guess.

Web APIs

# Node.js — CPU profile
node --prof app.js
# Run load test, then:
node --prof-process isolate-*.log > profile.txt

# Python — flame graph
pip install py-spy
py-spy record -o profile.svg --pid $(pgrep -f "python app.py")

# Go — pprof
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30

# Database — slow query log
EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) SELECT ...;

Frontend

# Bundle analysis
npx webpack-bundle-analyzer stats.json
npx source-map-explorer dist/main.js

# Runtime: Chrome DevTools → Performance tab
# Record interaction → identify long tasks (>50ms)

# Lighthouse CI
npx lhci autorun

Mobile

  • Android: Android Studio → Profiler → CPU/Memory/Network
  • iOS: Xcode → Instruments → Time Profiler
  • Flutter: flutter run --profile → DevTools → Performance overlay

Step 4: Report the Finding

State the bottleneck with evidence, not assumption:

## Bottleneck Found

**Location:** `UserSearchService.search()` — lines 45-67
**Evidence:** pprof shows 78% of CPU time in this function
**Root cause:** For each of 50 search results, a separate `getUserById()` DB call is made (N+1 query)
**Impact:** 47 sequential DB calls per request × ~8ms each = ~376ms per request

Step 5: Apply One Change

Single change. Document hypothesis and expected impact before applying:

## Change Applied

**Hypothesis:** Replacing per-item DB lookups with a single JOIN will eliminate 46 of the 47 DB calls
**Change:** `UserSearchService.search()` — replace loop + `getUserById()` with `getUsersByIds(ids)` JOIN
**Files modified:** `src/services/UserSearchService.ts`
**Expected impact:** p95 latency from 380ms to < 50ms

Step 6: Re-Measure and Compare

Run the exact same benchmark from Step 2.

## After Optimisation — YYYY-MM-DD

**Change:** N+1 query replaced with single JOIN

| Metric | Before | After | Delta |
|--------|--------|-------|-------|
| p50 | 45ms | 12ms | -73% |
| p95 | 380ms | 38ms | -90% |
| p99 | 720ms | 65ms | -91% |
| Error rate | 0.2% | 0.1% | -50% |
| Throughput | 210 req/s | 890 req/s | +324% |

**Verdict:** IMPROVEMENT CONFIRMED
**Root cause validated:** DB calls per request: 47 → 1
**No regression:** error rate stable, memory unchanged

Step 7: Verdict

Verdict Criteria
IMPROVEMENT CONFIRMED Measurable improvement on target metric, no regression elsewhere
INCONCLUSIVE No measurable change — hypothesis was wrong; identify next bottleneck
REGRESSION Change made things worse — revert immediately, re-diagnose
GOAL MET Target from Step 1 achieved — further optimisation not required

Performance Budget (Pre-Release Gate)

For release-critical features, define performance budgets in docs/performance-budgets.md:

api_latency:
  endpoint: POST /api/search
  p95_ms: 200
  measured_with: k6
  load: 100 concurrent users

bundle_size:
  entry: main.js
  max_gzip_kb: 250
  measured_with: webpack-bundle-analyzer

mobile_fps:
  screen: SearchScreen
  min_fps: 60
  tool: Android Profiler

CI fails if any budget is exceeded. Performance is a feature — it regresses like any other feature.