review-perf

📁 nielsmadan/agentic-coding 📅 1 day ago
0
总安装量
1
周安装量
安装命令
npx skills add https://github.com/nielsmadan/agentic-coding --skill review-perf

Agent 安装分布

kilo 1
amp 1
cline 1
openclaw 1
opencode 1
cursor 1

Skill 文档

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

  1. Determine scope based on flags (see Scope table above)
  2. Review each file against all 5 categories in the Performance Checklist below: Algorithmic Complexity, Database/Query Patterns, Memory Management, UI/Render Performance, Network/IO
  3. Parallelize if scope has >5 files: spawn one sub-agent per category, each scanning all files for that category. Merge results and deduplicate.
  4. 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
  5. 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