Files
gh-dieshen-claude-marketpla…/skills/performance-profiler.md
2025-11-29 18:21:19 +08:00

10 KiB

Performance Profiler Skill

Analyze code performance and provide optimization recommendations.

Performance Analysis Checklist

1. Algorithm Complexity

  • Time complexity documented (O(n), O(n²), etc.)
  • Space complexity analyzed
  • No nested loops where not necessary
  • Efficient data structures chosen
  • Binary search used instead of linear where possible

2. Database Performance

  • Queries use appropriate indexes
  • No N+1 query problems
  • Connection pooling implemented
  • Batch operations used for bulk updates
  • Query execution plans analyzed

3. Caching

  • Expensive computations cached
  • API responses cached appropriately
  • Cache invalidation strategy in place
  • CDN used for static assets
  • Redis/Memcached for distributed caching

4. Network & I/O

  • API calls batched where possible
  • Compression enabled (gzip, brotli)
  • HTTP/2 or HTTP/3 used
  • Keep-alive connections
  • Parallel requests for independent data

5. Frontend Performance

  • Code splitting implemented
  • Lazy loading for routes/components
  • Images optimized and lazy loaded
  • Virtual scrolling for long lists
  • Debouncing/throttling on events
  • Memoization for expensive renders

6. Memory Management

  • No memory leaks
  • Event listeners cleaned up
  • Large objects garbage collected
  • Streams used for large files
  • WeakMap/WeakSet for cached objects

Performance Profiling Tools

Node.js

// Built-in profiler
node --prof app.js
node --prof-process isolate-0xnnnnnnnnnnnn-v8.log > processed.txt

// Chrome DevTools
node --inspect app.js
// Then open chrome://inspect

// Clinic.js
clinic doctor -- node app.js
clinic flame -- node app.js
clinic bubbleprof -- node app.js

Browser

// Performance API
performance.mark('start');
// ... code to measure
performance.mark('end');
performance.measure('myOperation', 'start', 'end');
const measures = performance.getEntriesByType('measure');
console.log(measures[0].duration);

// Chrome DevTools Performance tab
// Record → Run code → Stop → Analyze flame graph

Python

import cProfile
import pstats

# Profile function
cProfile.run('my_function()', 'output.prof')

# Analyze results
stats = pstats.Stats('output.prof')
stats.sort_stats('cumulative')
stats.print_stats(20)  # Top 20 functions

# Line profiler
from line_profiler import LineProfiler
lp = LineProfiler()
lp.add_function(my_function)
lp.run('my_function()')
lp.print_stats()

Common Performance Issues & Fixes

Issue 1: N+1 Queries

// ❌ Bad: N+1 queries
const users = await User.findAll();
for (const user of users) {
  user.posts = await Post.findAll({ where: { userId: user.id } });
}

// ✅ Good: Single query with join
const users = await User.findAll({
  include: [{ model: Post }]
});

// ✅ Better: DataLoader for batching
const postLoader = new DataLoader(async (userIds) => {
  const posts = await Post.findAll({
    where: { userId: { $in: userIds } }
  });
  return userIds.map(id => posts.filter(p => p.userId === id));
});

Issue 2: Inefficient Loops

// ❌ Bad: O(n²)
function findDuplicates(arr: number[]): number[] {
  const duplicates = [];
  for (let i = 0; i < arr.length; i++) {
    for (let j = i + 1; j < arr.length; j++) {
      if (arr[i] === arr[j]) {
        duplicates.push(arr[i]);
      }
    }
  }
  return duplicates;
}

// ✅ Good: O(n)
function findDuplicates(arr: number[]): number[] {
  const seen = new Set();
  const duplicates = new Set();
  for (const num of arr) {
    if (seen.has(num)) {
      duplicates.add(num);
    }
    seen.add(num);
  }
  return Array.from(duplicates);
}

Issue 3: Large Lists Without Virtualization

// ❌ Bad: Renders all 10,000 items
{items.map(item => <ItemCard key={item.id} {...item} />)}

// ✅ Good: Virtual scrolling
import { FixedSizeList } from 'react-window';

<FixedSizeList
  height={600}
  itemCount={items.length}
  itemSize={80}
  width="100%"
>
  {({ index, style }) => (
    <div style={style}>
      <ItemCard {...items[index]} />
    </div>
  )}
</FixedSizeList>

Issue 4: Unnecessary Re-renders

// ❌ Bad: Re-renders on every parent render
function ExpensiveComponent({ data }) {
  const processed = processData(data);  // Runs every render
  return <div>{processed}</div>;
}

// ✅ Good: Memoized
const ExpensiveComponent = React.memo(({ data }) => {
  const processed = useMemo(() => processData(data), [data]);
  return <div>{processed}</div>;
});

Issue 5: Blocking Operations

// ❌ Bad: Blocks event loop
function processLargeFile() {
  const data = fs.readFileSync('large-file.json');  // Blocks!
  return JSON.parse(data);
}

// ✅ Good: Async
async function processLargeFile() {
  const data = await fs.promises.readFile('large-file.json', 'utf8');
  return JSON.parse(data);
}

// ✅ Better: Streaming
function processLargeFileStream() {
  return new Promise((resolve, reject) => {
    const stream = fs.createReadStream('large-file.json');
    let data = '';
    stream.on('data', chunk => data += chunk);
    stream.on('end', () => resolve(JSON.parse(data)));
    stream.on('error', reject);
  });
}

Performance Benchmarking

JavaScript/TypeScript

import Benchmark from 'benchmark';

const suite = new Benchmark.Suite();

suite
  .add('Array.forEach', () => {
    const arr = Array.from({ length: 1000 }, (_, i) => i);
    arr.forEach(x => x * 2);
  })
  .add('for loop', () => {
    const arr = Array.from({ length: 1000 }, (_, i) => i);
    for (let i = 0; i < arr.length; i++) {
      arr[i] * 2;
    }
  })
  .add('Array.map', () => {
    const arr = Array.from({ length: 1000 }, (_, i) => i);
    arr.map(x => x * 2);
  })
  .on('cycle', (event) => {
    console.log(String(event.target));
  })
  .on('complete', function() {
    console.log('Fastest is ' + this.filter('fastest').map('name'));
  })
  .run();

Python

import timeit

def method1():
    return [x * 2 for x in range(1000)]

def method2():
    return list(map(lambda x: x * 2, range(1000)))

time1 = timeit.timeit(method1, number=10000)
time2 = timeit.timeit(method2, number=10000)

print(f"Method 1: {time1:.4f}s")
print(f"Method 2: {time2:.4f}s")

Database Query Optimization

Analyze Slow Queries

-- PostgreSQL: Enable slow query logging
ALTER SYSTEM SET log_min_duration_statement = 1000;  -- Log queries > 1s
SELECT pg_reload_conf();

-- View slow queries
SELECT
  calls,
  total_exec_time,
  mean_exec_time,
  max_exec_time,
  query
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 20;

-- Explain query
EXPLAIN ANALYZE
SELECT u.*, COUNT(p.id) as post_count
FROM users u
LEFT JOIN posts p ON u.id = p.user_id
GROUP BY u.id;

Add Indexes

-- Before: Sequential scan
SELECT * FROM users WHERE email = 'user@example.com';
-- Seq Scan on users (cost=0.00..180.00 rows=1)

-- Add index
CREATE INDEX idx_users_email ON users(email);

-- After: Index scan
-- Index Scan using idx_users_email on users (cost=0.42..8.44 rows=1)

Memory Leak Detection

Node.js

// Detect memory leaks
const heapdump = require('heapdump');

// Take heap snapshot
heapdump.writeSnapshot(`./heap-${Date.now()}.heapsnapshot`);

// Compare snapshots in Chrome DevTools
// Memory → Load → Compare snapshots

// Monitor memory usage
setInterval(() => {
  const used = process.memoryUsage();
  console.log({
    rss: `${Math.round(used.rss / 1024 / 1024)}MB`,
    heapTotal: `${Math.round(used.heapTotal / 1024 / 1024)}MB`,
    heapUsed: `${Math.round(used.heapUsed / 1024 / 1024)}MB`,
    external: `${Math.round(used.external / 1024 / 1024)}MB`,
  });
}, 5000);

Performance Budget

Define acceptable performance metrics:

Web Application

  • First Contentful Paint (FCP): < 1.8s
  • Largest Contentful Paint (LCP): < 2.5s
  • Time to Interactive (TTI): < 3.8s
  • Total Blocking Time (TBT): < 200ms
  • Cumulative Layout Shift (CLS): < 0.1
  • Bundle Size: < 200KB (gzipped)

API

  • Response Time (p50): < 100ms
  • Response Time (p95): < 500ms
  • Response Time (p99): < 1000ms
  • Throughput: > 1000 req/s
  • Error Rate: < 0.1%

Database

  • Query Time (avg): < 50ms
  • Connection Pool: < 80% utilization
  • Cache Hit Rate: > 90%

Optimization Priority

  1. Measure First: Profile before optimizing
  2. Focus on Bottlenecks: 20% of code causes 80% of issues
  3. User-Facing First: Optimize what users experience
  4. Low-Hanging Fruit: Easy wins first
  5. Monitor Continuously: Set up alerts for regressions

Performance Testing

// Load testing with autocannon
import autocannon from 'autocannon';

autocannon({
  url: 'http://localhost:3000/api/users',
  connections: 100,
  duration: 30,
  headers: {
    'Authorization': 'Bearer token'
  }
}, (err, result) => {
  console.log('Requests/sec:', result.requests.average);
  console.log('Latency p50:', result.latency.p50);
  console.log('Latency p99:', result.latency.p99);
});

Report Template

# Performance Analysis Report

## Executive Summary
- **Current Performance**: X req/s, Yms avg response
- **Target Performance**: A req/s, Bms avg response
- **Gap**: Need to improve by Z%

## Findings

### Critical Issues
1. **N+1 Query in /api/users** (Impact: High)
   - Current: 500ms avg response time
   - Each user triggers 10 additional queries
   - **Recommendation**: Add eager loading with `include`
   - **Expected Impact**: Reduce to 50ms (10x improvement)

### Major Issues
2. **Large Bundle Size** (Impact: Medium)
   - Current: 800KB (gzipped)
   - **Recommendation**: Code splitting, lazy loading
   - **Expected Impact**: Reduce to 200KB

## Optimization Roadmap

1. **Week 1**: Fix N+1 queries (High impact, Low effort)
2. **Week 2**: Implement caching (High impact, Medium effort)
3. **Week 3**: Code splitting (Medium impact, Medium effort)
4. **Week 4**: Database indexing (Medium impact, Low effort)

## Success Metrics
- Response time reduced by 60%
- Throughput increased by 3x
- Error rate reduced to < 0.1%