SuperAPI AI Directory

gravitas-perf

Testing & quality

View repository

Updated 10-25 03:13

About this skill

GRAVITAS — Performance Extension

Performance analysis mode. Load in addition to skills/gravitas/SKILL.md. All perf claims require measured before/after numbers. No guessing.


Core Rule: Measure Before Optimizing

Never optimize without a baseline measurement. "This is slow" is not a baseline.

Baseline required:
  - What is the current latency/throughput? (measured, not estimated)
  - What is the target? (user's goal or SLA)
  - What is the profiler saying is hot? (not intuition)

Performance Recon Additions

# Database — N+1 queries
grep -rn "\.find\|\.findOne\|\.select" src/ --include="*.ts" | grep -v "include\|join"

# Missing indexes
grep -rn "WHERE.*email\|WHERE.*username\|WHERE.*userId" src/ --include="*.ts"
# → check if these columns have DB indexes

# Unoptimized loops
grep -rn "for.*await\|forEach.*await" src/ --include="*.ts"
# → sequential async where parallel would work

# Missing memoization
grep -rn "\.map\|\.filter\|\.reduce" src/ --include="*.ts" -A 2 | grep "expensive\|compute\|calculate"

# Bundle size (frontend)
npx bundlesize 2>/dev/null || du -sh dist/ 2>/dev/null

# Memory leaks
grep -rn "setInterval\|addEventListener" src/ --include="*.ts" | grep -v "clearInterval\|removeEventListener"

Measurement Protocol

Before any optimization

# API latency (using autocannon, wrk, or k6)
autocannon -c 10 -d 10 http://localhost:3000/api/users
# Record: req/sec, latency p50/p95/p99

# Function benchmark (using vitest bench)
import { bench, describe } from 'vitest';
describe('processUsers', () => {
  bench('current', () => processUsers(testData));
});

# Memory
node --inspect src/server.js &
# heap snapshot before and after load

Report format (required)

## Performance Baseline
- Endpoint: GET /api/users
- Before: 127ms p50, 842ms p99, 78 req/sec
- After:  23ms p50, 95ms p99, 512 req/sec
- Improvement: 5.5x p50, 8.9x p99, 6.6x throughput

Common Performance Anti-Patterns

N+1 Query Problem

BAD:
const users = await db.query('SELECT * FROM users');
for (const user of users) {
  user.posts = await db.query('SELECT * FROM posts WHERE userId = $1', [user.id]);
  // N queries for N users → N+1 total
}

GOOD:
const users = await db.query(`
  SELECT u.*, json_agg(p.*) as posts
  FROM users u
  LEFT JOIN posts p ON p.userId = u.id
  GROUP BY u.id
`);
// 1 query total

Sequential Async Where Parallel Works

BAD:
const user = await fetchUser(id);
const posts = await fetchPosts(id);  // waits for user unnecessarily
const comments = await fetchComments(id);  // waits for posts

GOOD:
const [user, posts, comments] = await Promise.all([
  fetchUser(id),
  fetchPosts(id),
  fetchComments(id),  // all start simultaneously
]);

Missing Cache for Expensive Computation

BAD: function getPermissions(userId: string) {
  return db.query('SELECT * FROM permissions WHERE userId = $1', [userId]);
  // called on every request
}

GOOD: const cache = new Map<string, Permission[]>();
function getPermissions(userId: string) {
  if (cache.has(userId)) return cache.get(userId)!;
  const perms = await db.query(...);
  cache.set(userId, perms);
  setTimeout(() => cache.delete(userId), 60_000); // 1min TTL
  return perms;
}

Missing Database Indexes

-- Check slow queries
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'user@example.com';
-- If: Seq Scan → MISSING INDEX

-- Fix
CREATE INDEX idx_users_email ON users(email);
-- After: Index Scan → fast

Algorithmic Complexity Analysis

For any new algorithm, document complexity:

/**
 * Finds duplicate usernames in O(n) time.
 * @complexity O(n) time, O(n) space
 *
 * BAD alternative: O(n²) nested loops
 */
function findDuplicates(usernames: string[]): string[] {
  const seen = new Set<string>();
  return usernames.filter(name => {
    if (seen.has(name)) return true;
    seen.add(name);
    return false;
  });
}

Performance Verification

# Benchmark comparison
vitest bench --reporter=verbose

# Before/after latency comparison
autocannon -c 10 -d 30 http://localhost:3000/api/endpoint

# Bundle size change
du -sh dist/  # before and after

# Memory usage
node --max-old-space-size=512 -e "require('./dist/server')" &
sleep 5 && curl http://localhost:3000/api/heavy-endpoint

VERDICT for Performance Tasks

VERDICT: PASS (Performance)

Baseline:    p50=127ms, p99=842ms, 78 req/sec
After:       p50=23ms,  p99=95ms,  512 req/sec
Improvement: 5.5x p50, 8.9x p99, 6.6x throughput
Tests:       47/47 (behavior unchanged)
Memory:      no increase in heap usage

Never claim performance improvement without measured before/after numbers.