review-perf

Performance analysis for common bottlenecks and inefficiencies.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "review-perf" with this command: npx skills add nielsmadan/agentic-coding/nielsmadan-agentic-coding-review-perf

Review Performance

Performance analysis for common bottlenecks and inefficiencies.

Usage

/review-perf # Review context-related code /review-perf --staged # Review staged changes /review-perf --all # Full codebase audit (parallel agents)

Scope

Flag Scope Method

(none) Context-related code Files from the current conversation context: any files the user has discussed, opened, or that you have read/edited in this session. If no conversation context exists, ask the user to specify files or use --staged /--all .

--staged

Staged changes git diff --cached --name-only

--all

Full codebase Glob source files, parallel agents

Workflow

  • Determine scope based on flags (see Scope table above)

  • Review each file against all 5 categories in the Performance Checklist below: Algorithmic Complexity, Database/Query Patterns, Memory Management, UI/Render Performance, Network/IO

  • Parallelize if scope has >5 files: spawn one sub-agent per category, each scanning all files for that category. Merge results and deduplicate.

  • Classify severity for each finding:

  • Critical: User-facing slowdown, data loss risk, or resource exhaustion (e.g., memory leak, N+1 on hot path)

  • High: Measurable inefficiency on a common code path but not immediately user-visible (e.g., O(n²) on lists typically < 100 items but growing)

  • Medium: Suboptimal pattern that could become a problem at scale (e.g., missing pagination, sequential requests that could be parallel)

  • Suggestion: Optimization opportunity with marginal current impact

  • Report findings grouped by severity using the Output Format below

Performance Checklist

Algorithmic Complexity

O(n²) or Worse:

// BAD: O(n²) nested loops for (const item of items) { for (const other of items) { if (item.id === other.parentId) { ... } } }

// GOOD: O(n) with lookup map const parentMap = new Map(items.map(i => [i.id, i])); for (const item of items) { const parent = parentMap.get(item.parentId); }

Repeated Calculations:

// BAD: Recalculating in loop items.forEach(item => { const config = expensiveConfigLookup(); // Called n times process(item, config); });

// GOOD: Calculate once const config = expensiveConfigLookup(); items.forEach(item => process(item, config));

Missing Early Exit:

// BAD: Always iterates entire array function findUser(users, id) { let result = null; users.forEach(u => { if (u.id === id) result = u; }); return result; }

// GOOD: Exit when found function findUser(users, id) { return users.find(u => u.id === id); }

Database/Query Patterns

N+1 Queries:

// BAD: Query per item const users = await db.users.findAll(); for (const user of users) { user.posts = await db.posts.findAll({ where: { userId: user.id } }); }

// GOOD: Single query with include const users = await db.users.findAll({ include: [{ model: db.posts }] });

Missing Pagination:

// BAD: Load all records const allUsers = await db.users.findAll();

// GOOD: Paginate const users = await db.users.findAll({ limit: 50, offset: page * 50 });

SELECT * When Few Columns Needed:

-- BAD: Fetching everything SELECT * FROM users WHERE active = true;

-- GOOD: Only needed columns SELECT id, name, email FROM users WHERE active = true;

Missing Indexes:

  • Columns used in WHERE clauses

  • Columns used in ORDER BY

  • Foreign key columns

  • Columns used in JOIN conditions

Memory Management

Unclosed Resources:

// BAD: Connection never closed const conn = await db.connect(); const data = await conn.query('...'); // conn stays open

// GOOD: Always close const conn = await db.connect(); try { return await conn.query('...'); } finally { conn.close(); }

Growing Caches:

// BAD: Cache grows forever const cache = {}; function getValue(key) { if (!cache[key]) cache[key] = expensiveLookup(key); return cache[key]; }

// GOOD: LRU or TTL cache const cache = new LRUCache({ max: 1000 });

Event Listener Leaks:

// BAD: Never removed useEffect(() => { window.addEventListener('resize', handler); }, []);

// GOOD: Cleanup useEffect(() => { window.addEventListener('resize', handler); return () => window.removeEventListener('resize', handler); }, []);

UI/Render Performance

Unnecessary Re-renders (React):

// BAD: New object every render <Child style={{ color: 'red' }} /> <Child onClick={() => handleClick(id)} />

// GOOD: Memoize const style = useMemo(() => ({ color: 'red' }), []); const handleClickMemo = useCallback(() => handleClick(id), [id]);

Missing Virtualization:

// BAD: Render 10,000 items {items.map(item => <Row key={item.id} {...item} />)}

// GOOD: Use virtualization <VirtualizedList data={items} renderItem={({ item }) => <Row {...item} />} />

Blocking Main Thread:

// BAD: Heavy sync computation function processData(data) { return data.map(item => expensiveTransform(item)); // Blocks UI }

// GOOD: Use web worker or chunk async function processData(data) { return await worker.process(data); }

Network/IO

Sequential Requests:

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

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

Missing Request Deduplication:

// BAD: Same request multiple times componentA.fetchUser(123); componentB.fetchUser(123); // Duplicate request

// GOOD: Cache or dedupe const { data } = useSWR(/users/${id}, fetcher);

Output Format

Performance Review: {scope}

Critical (user-facing slowdown)

  • {file}:{line} - {issue type}: {description} Impact: {why it matters} Fix: {solution with code example}

High Priority

  • {file}:{line} - {issue} Fix: {solution}

Medium Priority

  • {file} - {issue}

Suggestions

  • {optimization opportunity}

Examples

Staged changes introduce N+1 query:

/review-perf --staged

Reviews staged files and catches a new user list endpoint that queries posts per user in a loop. Reports it as Critical with the impact ("100 users = 101 queries") and provides a fix using eager loading with include .

Full audit finds memory leak in dashboard:

/review-perf --all

Parallel agents scan the full codebase by category. Finds an event listener in the dashboard component that is never cleaned up on unmount, plus an unbounded in-memory cache growing with every API call.

Troubleshooting

False positive on a rarely-executed code path

Solution: If the flagged code runs only during initialization or in admin-only flows, note the expected data size in a code comment. Re-run the review and the context will help distinguish hot paths from cold ones.

Cannot determine algorithmic complexity without runtime data

Solution: Add a brief comment with the expected input size (e.g., // n is typically < 50 ) so static analysis can assess impact. For uncertain cases, use /perf-test to measure actual performance with realistic data.

Notes

  • Focus on measurable impact, not micro-optimizations

  • Consider data size - O(n²) on 10 items is fine, on 10,000 is not

  • For --all , use parallel agents per category

  • Database issues often have the highest impact

  • UI issues matter most for user-facing code

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Research

research-online

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

pdf

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

theme-factory

No summary provided by upstream source.

Repository SourceNeeds Review