
Performance Optimization
FreeEnhance RTK CLI performance with systematic analysis.
Free · Opens the source repo
What Performance Optimization does
The Performance Optimization skill provides a systematic approach to analyzing and optimizing the performance of the RTK CLI tool. It focuses on key metrics such as startup time, memory usage, and token savings, ensuring that the tool runs efficiently. By adhering to defined performance targets, users can maintain a responsive and lightweight command-line interface. This skill is particularly beneficial for developers who want to ensure that their CLI applications remain performant, especially as they evolve and change over time.
Users can automatically trigger performance checks after making changes to filters, regexes, or dependencies, or they can manually invoke the skill when they suspect performance degradation. The workflow includes establishing a baseline for performance metrics, implementing changes, and then measuring the impact of those changes. This structured approach helps developers identify regressions and optimize their code effectively.
The skill also includes detailed guidance on common performance issues, such as regex recompilation and excessive memory allocations, providing users with actionable insights to improve their code. By leveraging tools like hyperfine for benchmarking and cargo for building and profiling, developers can ensure that their CLI tool adheres to strict performance standards. This skill is ideal for developers who prioritize performance in their command-line applications and want to proactively manage and optimize their tools.
When to use it
Use this skill when you need to analyze and improve the performance of the RTK CLI tool after making changes or when performance issues are suspected.
When not to use it
This skill may not be suitable for applications where performance is not a critical concern or for users unfamiliar with command-line tools and performance benchmarking.
What you can build with it
Before a Release
Run performance checks to ensure that the RTK CLI tool meets startup and memory usage targets before deploying.
After Code Changes
Invoke the skill to analyze performance impacts after modifying filters or regexes in the CLI.
Identifying Performance Issues
Use the skill to systematically diagnose and fix performance regressions in the RTK CLI tool.
How to install Performance Optimization
View source1. Install with the skills CLI
npx skills add rtk-ai/rtk/performance --agent claude-code2. Or install it manually
Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.
Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs
Inside SKILL.md
Written by rtk-aiPerformance Optimization Skill
Systematic performance analysis and optimization for RTK CLI tool, focusing on startup time (<10ms), memory usage (<5MB), and token savings (60-90%).
When to Use
- Automatically triggered: After filter changes, regex modifications, or dependency additions
- Manual invocation: When performance degradation suspected or before release
- Proactive: After any code change that could impact startup time or memory
RTK Performance Targets
| Metric | Target | Verification Method | Failure Threshold |
|---|---|---|---|
| Startup time | <10ms | hyperfine 'rtk <cmd>' | >15ms = blocker |
| Memory usage | <5MB resident | /usr/bin/time -l rtk <cmd> (macOS) | >7MB = blocker |
| Token savings | 60-90% | Tests with count_tokens() | <60% = blocker |
| Binary size | <5MB stripped | ls -lh target/release/rtk | >8MB = investigate |
Performance Analysis Workflow
1. Establish Baseline
Before making any changes, capture current performance:
# Startup time baseline
hyperfine 'rtk git status' --warmup 3 --export-json /tmp/baseline_startup.json
# Memory usage baseline (macOS)
/usr/bin/time -l rtk git status 2>&1 | grep "maximum resident set size" > /tmp/baseline_memory.txt
# Memory usage baseline (Linux)
/usr/bin/time -v rtk git status 2>&1 | grep "Maximum resident set size" > /tmp/baseline_memory.txt
# Binary size baseline
ls -lh target/release/rtk | tee /tmp/baseline_binary_size.txt
2. Make Changes
Implement optimization or feature changes.
3. Rebuild and Measure
# Rebuild with optimizations
cargo build --release
# Measure startup time
hyperfine 'target/release/rtk git status' --warmup 3 --export-json /tmp/after_startup.json
# Measure memory usage
/usr/bin/time -l target/release/rtk git status 2>&1 | grep "maximum resident set size" > /tmp/after_memory.txt
# Check binary size
ls -lh target/release/rtk | tee /tmp/after_binary_size.txt
4. Compare Results
# Startup time comparison
hyperfine 'rtk git status' 'target/release/rtk git status' --warmup 3
# Example output:
# Benchmark 1: rtk git status
# Time (mean ± σ): 6.2 ms ± 0.3 ms [User: 4.1 ms, System: 1.8 ms]
# Benchmark 2: target/release/rtk git status
# Time (mean ± σ): 7.8 ms ± 0.4 ms [User: 5.2 ms, System: 2.1 ms]
#
# Summary
# 'rtk git status' ran 1.26 times faster than 'target/release/rtk git status'
# Memory comparison
diff /tmp/baseline_memory.txt /tmp/after_memory.txt
# Binary size comparison
diff /tmp/baseline_binary_size.txt /tmp/after_binary_size.txt
5. Identify Regressions
Startup time regression (>15% increase or >2ms absolute):
# Profile with flamegraph
cargo install flamegraph
cargo flamegraph -- target/release/rtk git status
# Open flamegraph.svg
open flamegraph.svg
# Look for:
# - Repeated fixed-regex compilation (should be in LazyLock init)
# - Excessive allocations
# - File I/O on startup (should be zero)
Memory regression (>20% increase or >1MB absolute):
# Profile allocations (requires nightly)
cargo +nightly build --release -Z build-std
RUSTFLAGS="-C link-arg=-fuse-ld=lld" cargo +nightly build --release
# Use DHAT for heap profiling
cargo install dhat
# Add to main.rs:
# #[global_allocator]
# static ALLOC: dhat::Alloc = dhat::Alloc;
Token savings regression (<60% savings):
# Run token accuracy tests
cargo test test_token_savings
# Example failure output:
# Git log filter: expected ≥60% savings, got 52.3%
# Fix: Improve filter condensation logic
Common Performance Issues
Issue 1: Regex Recompilation
Symptom: Startup time >20ms, flamegraph shows regex compilation in hot path
Detection:
# Flamegraph shows Regex::new() calls during execution
cargo flamegraph -- target/release/rtk git log -10
# Check whether fixed patterns are compiled outside LazyLock statics
Fix:
// ❌ WRONG: Recompiled on every call
fn filter_line(line: &str) -> Option<&str> {
let re = Regex::new(r"pattern").unwrap(); // RECOMPILED!
re.find(line).map(|m| m.as_str())
}
// ✅ RIGHT: Compiled once with LazyLock
use std::sync::LazyLock;
static LINE_PATTERN: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"pattern").unwrap());
fn filter_line(line: &str) -> Option<&str> {
LINE_PATTERN.find(line).map(|m| m.as_str())
}
Issue 2: Excessive Allocations
Symptom: Memory usage >5MB, many small allocations in flamegraph
Detection:
# DHAT heap profiling
cargo +nightly build --release
valgrind --tool=dhat target/release/rtk git status
Fix:
// ❌ WRONG: Allocates Vec for every line
fn filter_lines(input: &str) -> String {
input.lines()
.map(|line| line.to_string()) // Allocates String
.collect::<Vec<_>>()
.join("\n")
}
// ✅ RIGHT: Borrow slices, single allocation
fn filter_lines(input: &str) -> String {
input.lines()
.collect::<Vec<_>>() // Vec of &str (no String allocation)
.join("\n")
}
Issue 3: Startup I/O
Symptom: Startup time varies wildly (5ms to 50ms), flamegraph shows file reads
Detection:
# strace on Linux
strace -c target/release/rtk git status 2>&1 | grep -E "open|read"
# dtrace on macOS (requires SIP disabled)
sudo dtrace -n 'syscall::open*:entry { @[execname] = count(); }' &
target/release/rtk git status
sudo pkill dtrace
Fix:
// ❌ WRONG: File I/O on startup
fn main() {
let config = load_config().unwrap(); // Reads ~/.config/rtk/config.toml
// ...
}
// ✅ RIGHT: Lazy config loading (only if needed)
fn main() {
// No I/O on startup
// Config loaded on-demand when first accessed
}
Issue 4: Dependency Bloat
Symptom: Binary size >5MB, many unused dependencies in Cargo.toml
Detection:
# Analyze dependency tree
cargo tree
# Find heavy dependencies
cargo install cargo-bloat
cargo bloat --release --crates
# Example output:
# File .text Size Crate
# 0.5% 2.1% 42.3KB regex
# 0.4% 1.8% 36.1KB clap
# ...
Fix:
# ❌ WRONG: Full feature set (bloat)
[dependencies]
clap = { version = "4", features = ["derive", "color", "suggestions"] }
# ✅ RIGHT: Minimal features
[dependencies]
clap = { version = "4", features = ["derive"], default-features = false }
Optimization Techniques
Technique 1: LazyLock Initialization
Use case: Regex patterns, static configuration, one-time allocations
Implementation:
use regex::Regex;
use std::sync::LazyLock;
static COMMIT_HASH: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"[0-9a-f]{7,40}").unwrap());
static AUTHOR_LINE: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"^Author: (.+)$").unwrap());
static DATE_LINE: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"^Date: (.+)$").unwrap());
// Fixed regexes compile on first use and are then reused
Impact: ~5-10ms saved per regex pattern (if compiled at runtime)
Technique 2: Zero-Copy String Processing
Use case: Filter output without allocating intermediate Strings
Implementation:
// ❌ WRONG: Allocates String for every line
fn filter(input: &str) -> String {
input.lines()
.filter(|line| !line.is_empty())
.map(|line| line.to_string()) // Allocates!
.collect::<Vec<_>>()
.join("\n")
}
// ✅ RIGHT: Borrow slices, single final allocation
fn filter(input: &str) -> String {
input.lines()
.filter(|line| !line.is_empty())
.collect::<Vec<_>>() // Vec<&str> (no String alloc)
.join("\n") // Single allocation for joined result
}
Impact: ~1-2MB memory saved, ~1-2ms startup saved
Technique 3: Minimal Dependencies
Use case: Reduce binary size and compile time
Implementation:
# Only include features you actually use
[dependencies]
clap = { version = "4", features = ["derive"], default-features = false }
serde = { version = "1", features = ["derive"], default-features = false }
# Avoid heavy dependencies
# ❌ Avoid: tokio (adds 5-10ms startup overhead)
# ❌ Avoid: full regex (use regex-lite if possible)
# ✅ Use: anyhow (lightweight error handling)
# ✅ Use: LazyLock (zero runtime overhead)
Impact: ~1-2MB binary size reduction, ~2-5ms startup saved
Performance Testing Checklist
Before committing filter changes:
Startup Time
- Benchmark with
hyperfine 'rtk <cmd>' --warmup 3 - Verify <10ms mean time
- Check variance (σ) is small (<1ms)
- Compare against baseline (regression <2ms)
Memory Usage
- Profile with
/usr/bin/time -l rtk <cmd> - Verify <5MB resident set size
- Compare against baseline (regression <1MB)
Token Savings
- Run
cargo test test_token_savings - Verify all filters achieve ≥60% savings
- Check real fixtures used (not synthetic)
Binary Size
- Check
ls -lh target/release/rtk - Verify <5MB stripped binary
- Run
cargo bloat --release --cratesif >5MB
Continuous Performance Monitoring
Pre-Commit Hook
Add to .claude/hooks/bash/pre-commit-performance.sh:
#!/bin/bash
# Performance regression check before commit
echo "🚀 Running performance checks..."
# Benchmark startup time
CURRENT_TIME=$(hyperfine 'rtk git status' --warmup 3 --export-json /tmp/perf.json 2>&1 | grep "Time (mean" | awk '{print $4}')
# Extract numeric value (remove "ms")
CURRENT_MS=$(echo $CURRENT_TIME | sed 's/ms//')
# Check if > 10ms
if (( $(echo "$CURRENT_MS > 10" | bc -l) )); then
echo "❌ Startup time regression: ${CURRENT_MS}ms (target: <10ms)"
exit 1
fi
# Check binary size
BINARY_SIZE=$(ls -l target/release/rtk | awk '{print $5}')
MAX_SIZE=$((5 * 1024 * 1024)) # 5MB
if [ $BINARY_SIZE -gt $MAX_SIZE ]; then
echo "❌ Binary size regression: $(($BINARY_SIZE / 1024 / 1024))MB (target: <5MB)"
exit 1
fi
echo "✅ Performance checks passed"
CI/CD Integration
Add to .github/workflows/ci.yml:
- name: Performance Regression Check
run: |
cargo build --release
cargo install hyperfine
# Benchmark startup time
hyperfine 'target/release/rtk git status' --warmup 3 --max-runs 10
# Check binary size
BINARY_SIZE=$(ls -l target/release/rtk | awk '{print $5}')
MAX_SIZE=$((5 * 1024 * 1024))
if [ $BINARY_SIZE -gt $MAX_SIZE ]; then
echo "Binary too large: $(($BINARY_SIZE / 1024 / 1024))MB"
exit 1
fi
Performance Optimization Priorities
Priority order (highest to lowest impact):
- 🔴 LazyLock regex (5-10ms per pattern if compiled at runtime)
- 🔴 Remove startup I/O (10-50ms for config file reads)
- 🟡 Zero-copy processing (1-2MB memory, 1-2ms startup)
- 🟡 Minimal dependencies (1-2MB binary, 2-5ms startup)
- 🟢 Algorithm optimization (varies, measure first)
When in doubt: Profile first with flamegraph, then optimize the hottest path.
Tools Reference
| Tool | Purpose | Command |
|---|---|---|
| hyperfine | Benchmark startup time | hyperfine 'rtk <cmd>' --warmup 3 |
| time | Memory usage (macOS) | /usr/bin/time -l rtk <cmd> |
| time | Memory usage (Linux) | /usr/bin/time -v rtk <cmd> |
| flamegraph | CPU profiling | cargo flamegraph -- rtk <cmd> |
| cargo bloat | Binary size analysis | cargo bloat --release --crates |
| cargo tree | Dependency tree | cargo tree |
| DHAT | Heap profiling | cargo +nightly build && valgrind --tool=dhat |
| strace | System call tracing (Linux) | strace -c target/release/rtk <cmd> |
| dtrace | System call tracing (macOS) | sudo dtrace -n 'syscall::open*:entry' |
Install tools:
# macOS
brew install hyperfine
# Linux / cross-platform via cargo
cargo install hyperfine
cargo install flamegraph
cargo install cargo-bloat
Frequently asked questions about Performance Optimization
Similar skills
Heap Snapshot Analysis
Investigate V8 heap snapshots for memory issues.
VS Code Performance Workflow
Automate performance investigations in VS Code.
Memory Leak Audit
Prevent memory leaks with effective coding patterns.
CPU Profile Analysis
Analyze V8 and Chrome performance profiles for optimization.
Chat Performance Testing
Benchmark and validate chat UI performance in VS Code.
Vercel React Best Practices
Optimize your React and Next.js applications for performance.
