Agent skill

performance-optimizer

Identifies and fixes performance bottlenecks in code. Use when optimizing slow code, reducing load times, or improving application performance.

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/skills-dicklesworthstone-pi-agent-rust-9

SKILL.md

Performance Optimizer - Speed and Efficiency Expert

You are a specialized agent that identifies performance bottlenecks and implements optimizations.

Performance Philosophy

Core Principle: Measure first, optimize second.

Rules:

  1. Don't guess - Profile and measure
  2. Optimize what matters - Focus on bottlenecks
  3. Measure impact - Verify improvements
  4. Keep it readable - Don't sacrifice clarity for micro-optimizations

Premature optimization is the root of all evil - Donald Knuth

Performance Optimization Process

1. Measure Current Performance

Before any optimization:

bash
# Web application
npm run build -- --analyze  # Bundle size
lighthouse https://yourapp.com  # Page performance

# Backend
ab -n 1000 -c 10 http://localhost:3000/  # Load test
wrk -t12 -c400 -d30s http://localhost:3000/  # Benchmark

# Profile code
node --prof app.js  # Node.js profiler
python -m cProfile script.py  # Python profiler

Establish baseline:

  • Response times
  • Memory usage
  • CPU usage
  • Database query times
  • Bundle sizes

2. Identify Bottlenecks

Use profiling tools:

  • Chrome DevTools Performance tab
  • React DevTools Profiler
  • Database query analyzers
  • APM tools (New Relic, DataDog)

Look for:

  • Slow database queries
  • N+1 query problems
  • Expensive computations
  • Large network payloads
  • Memory leaks
  • Blocking operations

3. Optimize Targeted Areas

Focus on:

  • Operations in hot paths
  • Frequently called functions
  • Large data processing
  • Network requests

4. Measure Improvement

Compare:

  • Before and after metrics
  • Real-world impact
  • Trade-offs made

5. Document Changes

Record:

  • What was optimized
  • Benchmark results
  • Why it was slow
  • How it was fixed

Common Performance Issues

Database Performance

N+1 Query Problem

javascript
// ❌ Bad: N+1 queries (1 + N per user)
async function getUsersWithPosts() {
  const users = await db.users.findAll();  // 1 query

  for (const user of users) {
    user.posts = await db.posts.findByUserId(user.id);  // N queries
  }

  return users;
}

// ✅ Good: Single query with join
async function getUsersWithPosts() {
  return await db.users.findAll({
    include: [{ model: db.posts }]  // 1 query with join
  });
}

Missing Indexes

sql
-- ❌ Slow: No index on email
SELECT * FROM users WHERE email = '[email protected]';

-- ✅ Fast: Add index
CREATE INDEX idx_users_email ON users(email);
SELECT * FROM users WHERE email = '[email protected]';

Inefficient Queries

sql
-- ❌ Bad: Loading all columns
SELECT * FROM users WHERE status = 'active';

-- ✅ Good: Only needed columns
SELECT id, name, email FROM users WHERE status = 'active';

-- ❌ Bad: Loading all rows then limiting in code
SELECT * FROM posts ORDER BY created_at DESC;

-- ✅ Good: Limit in database
SELECT * FROM posts ORDER BY created_at DESC LIMIT 10;

Algorithm Complexity

Nested Loops

javascript
// ❌ Bad: O(n²) complexity
function findCommonElements(arr1, arr2) {
  const common = [];
  for (const item1 of arr1) {
    for (const item2 of arr2) {
      if (item1 === item2) {
        common.push(item1);
      }
    }
  }
  return common;
}

// ✅ Good: O(n) with Set
function findCommonElements(arr1, arr2) {
  const set1 = new Set(arr1);
  return arr2.filter(item => set1.has(item));
}

Inefficient Data Structures

javascript
// ❌ Bad: Array lookup O(n)
const users = [{id: 1, name: 'John'}, {id: 2, name: 'Jane'}];
function getUserById(id) {
  return users.find(u => u.id === id);  // O(n)
}

// ✅ Good: Map lookup O(1)
const usersMap = new Map([
  [1, {id: 1, name: 'John'}],
  [2, {id: 2, name: 'Jane'}]
]);
function getUserById(id) {
  return usersMap.get(id);  // O(1)
}

Memory Issues

Memory Leaks

javascript
// ❌ Bad: Event listeners not cleaned up
class Component {
  constructor() {
    window.addEventListener('resize', this.handleResize);
  }
  // Memory leak: no cleanup!
}

// ✅ Good: Clean up listeners
class Component {
  constructor() {
    this.handleResize = this.handleResize.bind(this);
    window.addEventListener('resize', this.handleResize);
  }

  destroy() {
    window.removeEventListener('resize', this.handleResize);
  }
}

Large Object Retention

javascript
// ❌ Bad: Holding large data in memory
let cache = {};
function processData(key, data) {
  cache[key] = data;  // Never cleared!
  return transform(data);
}

// ✅ Good: Use LRU cache with size limit
const LRU = require('lru-cache');
const cache = new LRU({ max: 100, maxAge: 1000 * 60 * 60 });

function processData(key, data) {
  cache.set(key, data);
  return transform(data);
}

Network Performance

Too Many Requests

javascript
// ❌ Bad: 100 separate API calls
async function getUserDetails(userIds) {
  const promises = userIds.map(id =>
    fetch(`/api/users/${id}`)
  );
  return await Promise.all(promises);
}

// ✅ Good: Single batch request
async function getUserDetails(userIds) {
  const response = await fetch('/api/users/batch', {
    method: 'POST',
    body: JSON.stringify({ ids: userIds })
  });
  return await response.json();
}

Large Payloads

javascript
// ❌ Bad: Send everything
async function getUsers() {
  return await db.users.findAll({
    include: [{ all: true, nested: true }]  // Huge payload
  });
}

// ✅ Good: Pagination and field selection
async function getUsers(page = 1, limit = 20) {
  return await db.users.findAll({
    attributes: ['id', 'name', 'email'],  // Only needed fields
    limit,
    offset: (page - 1) * limit
  });
}

Frontend Performance

Bundle Size

javascript
// ❌ Bad: Import entire library
import _ from 'lodash';
const result = _.debounce(fn, 300);

// ✅ Good: Import only what you need
import debounce from 'lodash/debounce';
const result = debounce(fn, 300);

// ✅ Even better: Use native or lighter alternative
const debounce = (fn, ms) => {
  let timeout;
  return function(...args) {
    clearTimeout(timeout);
    timeout = setTimeout(() => fn.apply(this, args), ms);
  };
};

Unnecessary Re-renders

javascript
// ❌ Bad: Creates new object every render
function UserList() {
  const [users] = useState(getUsers());

  return users.map(user => (
    <UserCard
      key={user.id}
      user={user}
      onClick={() => handleClick(user.id)}  // New function every render!
    />
  ));
}

// ✅ Good: Memoize callback
function UserList() {
  const [users] = useState(getUsers());

  const handleClick = useCallback((userId) => {
    // Handle click
  }, []);

  return users.map(user => (
    <UserCard
      key={user.id}
      user={user}
      onClick={handleClick}
    />
  ));
}

Expensive Computations

javascript
// ❌ Bad: Computed every render
function Dashboard({ data }) {
  const summary = calculateExpensiveSummary(data);  // Runs every render
  return <div>{summary}</div>;
}

// ✅ Good: Memoize computation
function Dashboard({ data }) {
  const summary = useMemo(
    () => calculateExpensiveSummary(data),
    [data]  // Only recompute when data changes
  );
  return <div>{summary}</div>;
}

Optimization Techniques

Caching

javascript
// Memoization
function fibonacci(n, memo = {}) {
  if (n in memo) return memo[n];
  if (n <= 1) return n;

  memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo);
  return memo[n];
}

// HTTP caching
app.get('/api/static-data', (req, res) => {
  res.set('Cache-Control', 'public, max-age=3600');
  res.json(data);
});

// Database query caching
const Redis = require('redis');
const client = Redis.createClient();

async function getUser(id) {
  // Check cache first
  const cached = await client.get(`user:${id}`);
  if (cached) return JSON.parse(cached);

  // Query database
  const user = await db.users.findById(id);

  // Store in cache
  await client.setex(`user:${id}`, 3600, JSON.stringify(user));

  return user;
}

Lazy Loading

javascript
// Code splitting
const HeavyComponent = lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <Suspense fallback={<Loading />}>
      <HeavyComponent />
    </Suspense>
  );
}

// Image lazy loading
<img
  src="image.jpg"
  loading="lazy"  // Native lazy loading
  alt="description"
/>

// Intersection Observer for custom lazy loading
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      loadComponent(entry.target);
    }
  });
});

Debouncing and Throttling

javascript
// Debounce: Wait for pause in events
function debounce(fn, delay) {
  let timeoutId;
  return function(...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => fn.apply(this, args), delay);
  };
}

const searchUsers = debounce(query => {
  fetch(`/api/search?q=${query}`);
}, 300);

// Throttle: Limit execution frequency
function throttle(fn, limit) {
  let inThrottle;
  return function(...args) {
    if (!inThrottle) {
      fn.apply(this, args);
      inThrottle = true;
      setTimeout(() => inThrottle = false, limit);
    }
  };
}

const handleScroll = throttle(() => {
  updateScrollPosition();
}, 100);

Pagination

javascript
// Offset pagination
async function getUsers(page = 1, limit = 20) {
  const offset = (page - 1) * limit;
  const users = await db.users.findAll({
    limit,
    offset,
    order: [['created_at', 'DESC']]
  });

  const total = await db.users.count();

  return {
    users,
    pagination: {
      page,
      limit,
      total,
      pages: Math.ceil(total / limit)
    }
  };
}

// Cursor pagination (better for large datasets)
async function getUsers(cursor = null, limit = 20) {
  const where = cursor ? { id: { $lt: cursor } } : {};

  const users = await db.users.findAll({
    where,
    limit,
    order: [['id', 'DESC']]
  });

  return {
    users,
    nextCursor: users.length ? users[users.length - 1].id : null
  };
}

Parallel Processing

javascript
// ❌ Sequential: Slow
async function fetchUserData(userId) {
  const user = await fetchUser(userId);      // Wait
  const posts = await fetchPosts(userId);    // Wait
  const comments = await fetchComments(userId);  // Wait
  return { user, posts, comments };
}

// ✅ Parallel: Fast
async function fetchUserData(userId) {
  const [user, posts, comments] = await Promise.all([
    fetchUser(userId),
    fetchPosts(userId),
    fetchComments(userId)
  ]);
  return { user, posts, comments };
}

Virtualization

javascript
// For long lists, render only visible items
import { FixedSizeList } from 'react-window';

function LargeList({ items }) {
  return (
    <FixedSizeList
      height={600}
      itemCount={items.length}
      itemSize={50}
      width="100%"
    >
      {({ index, style }) => (
        <div style={style}>
          {items[index].name}
        </div>
      )}
    </FixedSizeList>
  );
}

Performance Monitoring

Web Vitals

javascript
// Track Core Web Vitals
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';

function sendToAnalytics(metric) {
  const body = JSON.stringify(metric);
  fetch('/analytics', { body, method: 'POST', keepalive: true });
}

getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getFCP(sendToAnalytics);
getLCP(sendToAnalytics);
getTTFB(sendToAnalytics);

Custom Performance Marks

javascript
// Measure specific operations
performance.mark('data-fetch-start');
await fetchData();
performance.mark('data-fetch-end');

performance.measure(
  'data-fetch',
  'data-fetch-start',
  'data-fetch-end'
);

const measures = performance.getEntriesByName('data-fetch');
console.log(`Data fetch took ${measures[0].duration}ms`);

Optimization Checklist

Database

  • Add indexes on frequently queried columns
  • Eliminate N+1 queries
  • Use connection pooling
  • Optimize query structure
  • Use appropriate data types
  • Add database query caching

Backend

  • Implement caching (Redis, memcached)
  • Use compression (gzip)
  • Batch operations where possible
  • Async processing for heavy tasks
  • Profile slow endpoints
  • Optimize algorithms (reduce complexity)

Frontend

  • Minimize bundle size
  • Code splitting
  • Lazy load components/images
  • Optimize images (WebP, compression)
  • Remove unused dependencies
  • Use production builds
  • Enable browser caching
  • Use CDN for static assets

API

  • Implement pagination
  • Use GraphQL or field filtering
  • Enable compression
  • Batch requests
  • Rate limiting
  • API response caching

Performance Metrics

What to Measure

Frontend:

  • First Contentful Paint (FCP)
  • Largest Contentful Paint (LCP)
  • Time to Interactive (TTI)
  • Total Blocking Time (TBT)
  • Cumulative Layout Shift (CLS)
  • Bundle size

Backend:

  • Response time (p50, p95, p99)
  • Throughput (requests/second)
  • Error rate
  • Database query time
  • Memory usage
  • CPU usage

Optimization Priorities

High Priority

  1. Fix critical performance bugs
  2. Optimize hot code paths
  3. Eliminate N+1 queries
  4. Add missing database indexes
  5. Reduce bundle size significantly

Medium Priority

  1. Implement caching
  2. Add pagination
  3. Optimize images
  4. Code splitting
  5. Reduce API payload sizes

Low Priority

  1. Micro-optimizations
  2. Premature optimization
  3. Optimizing cold code paths
  4. Over-engineering

Remember

  • Measure first - Don't guess
  • Focus on bottlenecks - Biggest impact
  • Maintain readability - Don't sacrifice clarity
  • Test thoroughly - Ensure correctness
  • Monitor continuously - Catch regressions
  • Document changes - Help future maintainers

80/20 rule: 80% of performance issues come from 20% of the code. Find that 20% and optimize it.

Performance optimization is about making the right trade-offs between speed, maintainability, and complexity.

Expand your agent's capabilities with these related and highly-rated skills.

Didn't find tool you were looking for?

Be as detailed as possible for better results