| name | performance |
| description | This skill should be used when profiling code, optimizing bottlenecks, benchmarking, or when performance, profiling, optimization, or --perf are mentioned. |
| metadata | {"version":"1.0.1"} |
Performance Engineering
Evidence-based performance optimization โ measure โ profile โ optimize โ validate.
<when_to_use>
- Profiling slow code paths or bottlenecks
- Identifying memory leaks or excessive allocations
- Optimizing latency-critical operations (P95, P99)
- Benchmarking competing implementations
- Database query optimization
- Reducing CPU usage in hot paths
- Improving throughput (RPS, ops/sec)
NOT for: premature optimization, optimization without measurement, guessing at bottlenecks
</when_to_use>
<iron_law>
NO OPTIMIZATION WITHOUT MEASUREMENT
Required workflow:
- Measure baseline performance with realistic workload
- Profile to identify actual bottleneck
- Optimize the bottleneck (not what you think is slow)
- Measure again to verify improvement
- Document gains and tradeoffs
Optimizing unmeasured code wastes time and introduces bugs.
</iron_law>
Load the maintain-tasks skill for stage tracking:
Stage 1: Establishing baseline
- content: "Establish performance baseline with realistic workload"
- activeForm: "Establishing performance baseline"
Stage 2: Profiling bottlenecks
- content: "Profile code to identify actual bottlenecks"
- activeForm: "Profiling code to identify bottlenecks"
Stage 3: Analyzing root cause
- content: "Analyze profiling data to determine root cause"
- activeForm: "Analyzing profiling data"
Stage 4: Implementing optimization
- content: "Implement targeted optimization for identified bottleneck"
- activeForm: "Implementing optimization"
Stage 5: Validating improvement
- content: "Measure performance gains and verify no regressions"
- activeForm: "Validating performance improvement"
Key Performance Indicators
Latency (response time):
- P50 (median) โ typical case
- P95 โ most users
- P99 โ tail latency
- P99.9 โ outliers
- TTFB โ time to first byte
- TTLB โ time to last byte
Throughput:
- RPS โ requests per second
- ops/sec โ operations per second
- bytes/sec โ data transfer rate
- queries/sec โ database throughput
Memory:
- Heap usage โ allocated memory
- GC frequency โ garbage collection pauses
- GC duration โ stop-the-world time
- Allocation rate โ memory churn
- Resident set size (RSS) โ total memory
CPU:
- CPU time โ total compute
- Wall time โ elapsed time
- Hot paths โ frequently executed code
- Time complexity โ algorithmic efficiency
- CPU utilization โ percentage used
Always measure:
- Before optimization (baseline)
- After optimization (improvement)
- Under realistic load (not toy data)
- Multiple runs (account for variance)
<profiling_tools>
TypeScript/Bun
Built-in timing:
console.time("operation");
console.timeEnd("operation");
const start = Bun.nanoseconds();
const elapsed = Bun.nanoseconds() - start;
console.log(`Took ${elapsed / 1_000_000}ms`);
Performance API:
const mark1 = performance.mark("start");
const mark2 = performance.mark("end");
performance.measure("operation", "start", "end");
const measure = performance.getEntriesByName("operation")[0];
console.log(`Duration: ${measure.duration}ms`);
Memory profiling:
- Chrome DevTools โ Memory tab โ heap snapshots
- Node.js
--inspect flag + Chrome DevTools
process.memoryUsage() for RSS/heap tracking
CPU profiling:
- Chrome DevTools โ Performance tab โ record session
- Node.js
--prof flag + node --prof-process
- Flamegraphs for visualization
Rust
Benchmarking:
#[cfg(test)]
mod benches {
use criterion::{black_box, criterion_group, criterion_main, Criterion};
fn benchmark_function(c: &mut Criterion) {
c.bench_function("my_function", |b| {
b.iter(|| my_function(black_box(42)))
});
}
criterion_group!(benches, benchmark_function);
criterion_main!(benches);
}
Profiling:
cargo bench โ criterion benchmarks
perf record + perf report โ Linux profiling
cargo flamegraph โ visual flamegraphs
cargo bloat โ binary size analysis
valgrind --tool=callgrind โ detailed profiling
heaptrack โ memory profiling
Instrumentation:
use std::time::Instant;
let start = Instant::now();
let duration = start.elapsed();
println!("Took: {:?}", duration);
</profiling_tools>
<optimization_patterns>
Algorithm Improvements
Time complexity:
- O(nยฒ) โ O(n log n) โ sorting, searching
- O(n) โ O(log n) โ binary search, trees
- O(n) โ O(1) โ hash maps, memoization
Space-time tradeoffs:
- Cache computed results (memoization)
- Precompute expensive operations
- Index data for faster lookup
- Use hash maps for O(1) access
Memory Optimization
Reduce allocations:
for (const item of items) {
const results = [];
results.push(process(item));
}
const results = [];
for (const item of items) {
results.push(process(item));
}
fn format_user(name: &str) -> String {
format!("User: {}", name)
}
fn format_user(name: &str, buf: &mut String) {
buf.clear();
buf.push_str("User: ");
buf.push_str(name);
}
Memory pooling:
- Reuse expensive objects (connections, buffers)
- Object pools for frequently allocated types
- Arena allocators for batch allocations
Lazy evaluation:
- Compute only when needed
- Stream processing vs loading all data
- Iterators over materialized collections
I/O Optimization
Batching:
- Batch API calls (1 request vs 100)
- Batch database writes (bulk insert)
- Batch file operations (single write vs many)
Caching:
- Cache expensive computations
- Cache database queries (Redis, in-memory)
- Cache API responses (HTTP caching)
- Invalidate stale cache entries
Async I/O:
- Non-blocking operations (async/await)
- Concurrent requests (Promise.all, tokio::spawn)
- Connection pooling (reuse connections)
Database Optimization
Query optimization:
- Add indexes for common queries
- Use EXPLAIN/EXPLAIN ANALYZE
- Avoid N+1 queries (use joins or batch loading)
- Select only needed columns
- Filter at database level (WHERE vs client filter)
Schema design:
- Normalize to reduce duplication
- Denormalize for read-heavy workloads
- Partition large tables
- Use appropriate data types
Connection management:
- Connection pooling (don't create per request)
- Prepared statements (avoid SQL parsing)
- Transaction batching (reduce round trips)
</optimization_patterns>
Loop: Measure โ Profile โ Analyze โ Optimize โ Validate
- Define performance goal โ target metric (e.g., P95 < 100ms)
- Establish baseline โ measure current performance under realistic load
- Profile systematically โ identify actual bottleneck (not guesses)
- Analyze root cause โ understand why code is slow
- Design optimization โ plan targeted improvement
- Implement optimization โ make focused change
- Measure improvement โ verify gains, check for regressions
- Document results โ record baseline, optimization, gains, tradeoffs
At each step:
- Document measurements with methodology
- Note profiling tool output
- Track optimization attempts (what worked/failed)
- Update performance documentation
Before declaring optimization complete:
Check gains:
- โ Measured improvement meets target?
- โ Improvement statistically significant?
- โ Tested under realistic load?
- โ Multiple runs confirm consistency?
Check regressions:
- โ No degradation in other metrics?
- โ Memory usage still acceptable?
- โ Code complexity still manageable?
- โ Tests still pass?
Check documentation:
- โ Baseline measurements recorded?
- โ Optimization approach explained?
- โ Gains quantified with numbers?
- โ Tradeoffs documented?
ALWAYS:
- Measure before optimizing (baseline)
- Profile to find actual bottleneck
- Use realistic workload (not toy data)
- Measure multiple runs (account for variance)
- Document baseline and improvements
- Check for regressions in other metrics
- Consider readability vs performance tradeoff
- Verify statistical significance
NEVER:
- Optimize without measuring first
- Guess at bottleneck without profiling
- Benchmark with unrealistic data
- Trust single-run measurements
- Skip documentation of results
- Sacrifice correctness for speed
- Optimize without clear performance goal
- Ignore algorithmic improvements
Methodology:
Related skills:
- codebase-analysis โ evidence-based investigation (foundation)
- debugging โ structured bug investigation
- typescript-fieldguide โ correctness before performance