Loading...
Loading...
Performance profiling and bottleneck detection for Node.js, Python, and browser apps
npx skill4agent add manastalukdar/claude-devstudio performance-profile$ARGUMENTSnode|python|browserCACHE_FILE=".claude/cache/performance-profile/runtime.json"
CACHE_TTL=86400 # 24 hours (tools don't change frequently)
mkdir -p .claude/cache/performance-profile
if [ -f "$CACHE_FILE" ]; then
CACHE_AGE=$(($(date +%s) - $(stat -c %Y "$CACHE_FILE" 2>/dev/null || stat -f %m "$CACHE_FILE" 2>/dev/null)))
if [ $CACHE_AGE -lt $CACHE_TTL ]; then
# Use cached runtime info
RUNTIME=$(jq -r '.runtime' "$CACHE_FILE")
NODE_VERSION=$(jq -r '.node_version' "$CACHE_FILE")
PYTHON_VERSION=$(jq -r '.python_version' "$CACHE_FILE")
TOOLS_INSTALLED=$(jq -r '.tools_installed' "$CACHE_FILE")
echo "Using cached runtime: $RUNTIME"
echo "Tools available: $TOOLS_INSTALLED"
SKIP_DETECTION="true"
fi
fi
# First run: detect and cache
if [ "$SKIP_DETECTION" != "true" ]; then
detect_runtime # Expensive operation
detect_tools # Expensive operation
# Cache results
jq -n \
--arg runtime "$RUNTIME" \
--arg node "$NODE_VERSION" \
--arg python "$PYTHON_VERSION" \
--arg tools "$TOOLS_INSTALLED" \
'{runtime: $runtime, node_version: $node, python_version: $python, tools_installed: $tools}' \
> "$CACHE_FILE"
fiif [ -f ".claude/profiling/profile-node.sh" ] && [ -f ".claude/profiling/profile-$TIMESTAMP.md" ]; then
if [ "$RECONFIGURE" != "true" ]; then
echo "Profiling already configured"
echo ""
echo "Available profiling scripts:"
ls .claude/profiling/profile-*.sh 2>/dev/null
echo ""
echo "Last report: $(ls -t .claude/profiling/profile-*.md | head -1)"
echo ""
echo "Use --reconfigure to regenerate setup"
exit 0
fi
fi# Default: Only create scripts for detected runtime
case "$RUNTIME" in
nodejs)
create_node_profiling_script # 800 tokens
# Skip Python and browser scripts
;;
python)
create_python_profiling_script # 700 tokens
# Skip Node and browser scripts
;;
browser)
create_browser_profiling_guide # 600 tokens
# Skip Node and Python scripts
;;
esac
# Only create all scripts if explicitly requested
if [ "$GENERATE_ALL" = "true" ]; then
create_node_profiling_script
create_python_profiling_script
create_browser_profiling_guide
fi# Efficient anti-pattern detection with head limit
echo "Scanning for performance anti-patterns..."
# Show only first 10 sync blocking operations
SYNC_BLOCKING=$(grep -r "readFileSync\|writeFileSync\|execSync" \
--include="*.js" --include="*.ts" \
--exclude-dir=node_modules --exclude-dir=dist \
. 2>/dev/null | head -10)
if [ -n "$SYNC_BLOCKING" ]; then
COUNT=$(echo "$SYNC_BLOCKING" | wc -l)
echo "⚠️ Found synchronous blocking operations (showing first 10):"
echo "$SYNC_BLOCKING" | head -5 | while read line; do
echo " - $line"
done
if [ $COUNT -gt 5 ]; then
echo " ... and $((COUNT - 5)) more"
fi
fi# Efficient: Grep returns only matching lines
detect_performance_issues() {
local issue_count=0
# Check for console.log (only in src directories)
if grep -q -r "console\.log" --include="*.{js,ts,jsx,tsx}" src/ 2>/dev/null; then
issue_count=$((issue_count + 1))
echo "⚠️ Issue $issue_count: console.log statements in source code"
fi
# Check for sync operations
if grep -q -r "readFileSync\|writeFileSync" --include="*.{js,ts}" src/ 2>/dev/null; then
issue_count=$((issue_count + 1))
echo "⚠️ Issue $issue_count: Synchronous file operations detected"
fi
# Show count, not full lists (efficient summary)
echo ""
echo "Total issues detected: $issue_count"
}# All operations in bash
case "$PROFILE_TYPE" in
node)
# Direct bash execution
clinic doctor -- node index.js
;;
python)
# Direct bash execution
python -m cProfile -o profile.stats main.py
;;
browser)
# Direct bash execution
lighthouse http://localhost:3000 --output html
;;
esacREPORT_LEVEL="${REPORT_LEVEL:-summary}"
case "$REPORT_LEVEL" in
summary)
# Minimal report (400 tokens)
cat > "$REPORT" << EOF
# Performance Profile Summary
**Runtime:** $RUNTIME
**Tools:** $TOOLS_INSTALLED
## Quick Start
Run profiling:
$PROFILE_DIR/profile-$RUNTIME.sh
See full report: cat $REPORT --full
EOF
;;
full)
# Comprehensive report (2,000 tokens)
generate_full_performance_report
;;
esaccheck_tool_availability() {
local tool="$1"
if ! command -v "$tool" >/dev/null 2>&1; then
echo "⚠️ $tool not installed"
echo " Install: $(get_install_command $tool)"
TOOLS_MISSING="true"
else
echo "✓ $tool available"
fi
}
# No actual npm install, just guidance
if [ "$TOOLS_MISSING" = "true" ]; then
echo ""
echo "Install missing tools to proceed with profiling"
exit 0
fi--clear-cacheclaude "/performance-profile"
# Shows: runtime detected, tools available, profiling commands
# Tokens: 400-800claude "/performance-profile --verbose"
# Shows: full anti-pattern detection, all profiling options
# Tokens: 1,200-1,800claude "/performance-profile --full"
# Shows: detailed report, all runtimes, complete recommendations
# Tokens: 2,000-3,000.claude/cache/performance-profile/runtime.json.claude/cache/performance-profile/anti-patterns.txt--reconfigure--verbose--full--all-runtimes--clear-cache#!/bin/bash
# Performance Profiling - Environment Detection
echo "=== Performance Profiling Setup ==="
echo ""
# Create profiling directory
mkdir -p .claude/profiling
PROFILE_DIR=".claude/profiling"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
REPORT="$PROFILE_DIR/profile-$TIMESTAMP.md"
detect_runtime() {
local runtime=""
# Check for Node.js
if [ -f "package.json" ]; then
if command -v node >/dev/null 2>&1; then
runtime="nodejs"
NODE_VERSION=$(node --version)
echo "✓ Node.js detected: $NODE_VERSION"
fi
fi
# Check for Python
if [ -f "requirements.txt" ] || [ -f "setup.py" ] || [ -f "pyproject.toml" ]; then
if command -v python >/dev/null 2>&1; then
runtime="python"
PYTHON_VERSION=$(python --version)
echo "✓ Python detected: $PYTHON_VERSION"
elif command -v python3 >/dev/null 2>&1; then
runtime="python"
PYTHON_VERSION=$(python3 --version)
echo "✓ Python detected: $PYTHON_VERSION"
fi
fi
# Check for browser-based app
if [ -f "package.json" ]; then
if grep -q "\"react\"\|\"vue\"\|\"angular\"\|\"svelte\"" package.json; then
if [ -z "$runtime" ]; then
runtime="browser"
else
runtime="$runtime,browser"
fi
echo "✓ Frontend framework detected - browser profiling available"
fi
fi
echo "$runtime"
}
RUNTIME=$(detect_runtime)
if [ -z "$RUNTIME" ]; then
echo "❌ Unable to detect runtime environment"
echo ""
echo "Supported environments:"
echo " - Node.js applications"
echo " - Python applications"
echo " - Browser-based applications (React, Vue, Angular, Svelte)"
exit 1
fi
echo ""
echo "Environment: $RUNTIME"echo ""
echo "=== Installing Profiling Tools ==="
install_profiling_tools() {
case "$RUNTIME" in
*nodejs*)
echo "Setting up Node.js profiling tools..."
# Check for clinic.js
if ! npm list -g clinic >/dev/null 2>&1; then
echo "Installing clinic.js (performance profiling suite)..."
echo " npm install -g clinic"
echo ""
echo "Clinic.js tools:"
echo " - clinic doctor - Diagnose performance issues"
echo " - clinic flame - CPU flame graphs"
echo " - clinic bubbleprof - Async operations"
echo " - clinic heapprofiler - Memory profiling"
else
echo "✓ clinic.js already installed"
fi
# Check for autocannon (benchmarking)
if ! npm list -g autocannon >/dev/null 2>&1; then
echo ""
echo "Installing autocannon (HTTP benchmarking)..."
echo " npm install -g autocannon"
else
echo "✓ autocannon already installed"
fi
echo ""
echo "Node.js profiling methods available:"
echo " 1. Built-in --inspect flag"
echo " 2. clinic.js suite"
echo " 3. Chrome DevTools"
;;
*python*)
echo "Setting up Python profiling tools..."
# Check for profiling packages
if ! python -c "import cProfile" 2>/dev/null; then
echo "cProfile not available (should be in stdlib)"
else
echo "✓ cProfile available (built-in)"
fi
# Check for line_profiler
if ! python -c "import line_profiler" 2>/dev/null; then
echo ""
echo "Install line_profiler for line-by-line profiling:"
echo " pip install line_profiler"
else
echo "✓ line_profiler available"
fi
# Check for memory_profiler
if ! python -c "import memory_profiler" 2>/dev/null; then
echo ""
echo "Install memory_profiler for memory analysis:"
echo " pip install memory_profiler"
else
echo "✓ memory_profiler available"
fi
echo ""
echo "Python profiling methods available:"
echo " 1. cProfile (CPU profiling)"
echo " 2. line_profiler (line-by-line)"
echo " 3. memory_profiler (memory usage)"
;;
*browser*)
echo "Browser profiling setup..."
echo ""
echo "Browser profiling tools:"
echo " 1. Chrome DevTools Performance tab"
echo " 2. Lighthouse CI"
echo " 3. webpack-bundle-analyzer"
echo " 4. React DevTools Profiler"
# Check for bundle analyzer
if [ -f "package.json" ]; then
if ! grep -q "webpack-bundle-analyzer" package.json; then
echo ""
echo "Install webpack-bundle-analyzer:"
echo " npm install --save-dev webpack-bundle-analyzer"
fi
fi
;;
esac
}
install_profiling_toolsif [[ "$RUNTIME" == *"nodejs"* ]]; then
echo ""
echo "=== Node.js Performance Profiling ==="
# Create profiling scripts
cat > "$PROFILE_DIR/profile-node.sh" << 'NODEPROFILE'
#!/bin/bash
# Node.js Performance Profiling
echo "Node.js Profiling Options:"
echo ""
echo "1. CPU Profiling (clinic doctor)"
echo "2. Flame Graph (clinic flame)"
echo "3. Async Operations (clinic bubbleprof)"
echo "4. Memory Profiling (clinic heapprofiler)"
echo "5. Built-in V8 Profiler (--prof)"
echo "6. HTTP Load Testing (autocannon)"
echo ""
# Option 1: Clinic Doctor (comprehensive diagnosis)
clinic_doctor() {
echo "Running clinic doctor..."
echo "This will start your app and collect performance data"
echo ""
# Find entry point
ENTRY=$(node -p "require('./package.json').main || 'index.js'")
clinic doctor -- node "$ENTRY"
echo ""
echo "✓ Profile complete! Opening report in browser..."
}
# Option 2: Flame Graph
clinic_flame() {
echo "Running clinic flame..."
echo "Generating CPU flame graph"
echo ""
ENTRY=$(node -p "require('./package.json').main || 'index.js'")
clinic flame -- node "$ENTRY"
echo ""
echo "✓ Flame graph generated!"
}
# Option 3: Async Operations
clinic_bubble() {
echo "Running clinic bubbleprof..."
echo "Analyzing async operations"
echo ""
ENTRY=$(node -p "require('./package.json').main || 'index.js'")
clinic bubbleprof -- node "$ENTRY"
echo ""
echo "✓ Async analysis complete!"
}
# Option 4: V8 Profiler
v8_profiler() {
echo "Running V8 profiler..."
echo ""
ENTRY=$(node -p "require('./package.json').main || 'index.js'")
node --prof "$ENTRY"
# Process the profile
PROFILE=$(ls isolate-*.log | head -1)
if [ -n "$PROFILE" ]; then
node --prof-process "$PROFILE" > processed-profile.txt
echo "✓ Profile processed: processed-profile.txt"
fi
}
# Option 5: HTTP Load Test
http_load_test() {
echo "HTTP Load Testing with autocannon"
echo ""
read -p "Enter URL to test (e.g., http://localhost:3000): " URL
read -p "Duration in seconds (default: 10): " DURATION
DURATION=${DURATION:-10}
echo ""
echo "Running load test..."
autocannon -d $DURATION "$URL"
}
# Main menu
case "${1:-1}" in
1) clinic_doctor ;;
2) clinic_flame ;;
3) clinic_bubble ;;
4) clinic_heapprofiler -- node $(node -p "require('./package.json').main || 'index.js'") ;;
5) v8_profiler ;;
6) http_load_test ;;
*) echo "Invalid option" ;;
esac
NODEPROFILE
chmod +x "$PROFILE_DIR/profile-node.sh"
echo "✓ Created Node.js profiling script: $PROFILE_DIR/profile-node.sh"
# Identify potential bottlenecks in code
echo ""
echo "Scanning for potential performance issues..."
# Check for synchronous blocking operations
SYNC_BLOCKING=$(grep -r "readFileSync\|writeFileSync\|execSync" \
--include="*.js" --include="*.ts" \
--exclude-dir=node_modules \
--exclude-dir=dist \
. 2>/dev/null | wc -l)
if [ "$SYNC_BLOCKING" -gt 0 ]; then
echo "⚠️ Found $SYNC_BLOCKING synchronous blocking operations"
echo " Consider using async versions (readFile, writeFile, exec)"
fi
# Check for missing await
MISSING_AWAIT=$(grep -r "^\s*async.*function" \
--include="*.js" --include="*.ts" \
--exclude-dir=node_modules \
. 2>/dev/null | wc -l)
echo "💡 Async functions found: $MISSING_AWAIT"
echo " Verify all async calls use await or proper promise handling"
# Check for large dependencies
echo ""
echo "Analyzing bundle size..."
if [ -f "package.json" ]; then
DEPS_COUNT=$(cat package.json | jq '.dependencies | length' 2>/dev/null || echo "N/A")
echo " Dependencies: $DEPS_COUNT"
# Suggest bundle analyzer
echo ""
echo "To analyze bundle size:"
echo " npm install --save-dev webpack-bundle-analyzer"
echo " # Add to webpack config and run build"
fi
fiif [[ "$RUNTIME" == *"python"* ]]; then
echo ""
echo "=== Python Performance Profiling ==="
cat > "$PROFILE_DIR/profile-python.sh" << 'PYTHONPROFILE'
#!/bin/bash
# Python Performance Profiling
echo "Python Profiling Options:"
echo ""
echo "1. cProfile (CPU profiling)"
echo "2. line_profiler (line-by-line)"
echo "3. memory_profiler (memory usage)"
echo ""
# Option 1: cProfile
cpu_profile() {
echo "Running cProfile..."
echo ""
# Find main Python file
if [ -f "main.py" ]; then
ENTRY="main.py"
elif [ -f "app.py" ]; then
ENTRY="app.py"
else
read -p "Enter Python file to profile: " ENTRY
fi
python -m cProfile -o profile.stats "$ENTRY"
# Analyze profile
python << 'ANALYZE'
import pstats
from pstats import SortKey
p = pstats.Stats('profile.stats')
print("\n=== Top 20 Functions by Cumulative Time ===")
p.sort_stats(SortKey.CUMULATIVE).print_stats(20)
print("\n=== Top 20 Functions by Total Time ===")
p.sort_stats(SortKey.TIME).print_stats(20)
ANALYZE
echo ""
echo "✓ Profile saved to: profile.stats"
}
# Option 2: line_profiler
line_profile() {
echo "Using line_profiler..."
echo ""
echo "Add @profile decorator to functions you want to profile"
echo "Example:"
echo " @profile"
echo " def slow_function():"
echo " pass"
echo ""
read -p "Enter Python file with @profile decorators: " ENTRY
kernprof -l -v "$ENTRY"
}
# Option 3: memory_profiler
memory_profile() {
echo "Using memory_profiler..."
echo ""
echo "Add @profile decorator to functions you want to profile"
echo ""
read -p "Enter Python file with @profile decorators: " ENTRY
python -m memory_profiler "$ENTRY"
}
case "${1:-1}" in
1) cpu_profile ;;
2) line_profile ;;
3) memory_profile ;;
*) echo "Invalid option" ;;
esac
PYTHONPROFILE
chmod +x "$PROFILE_DIR/profile-python.sh"
echo "✓ Created Python profiling script: $PROFILE_DIR/profile-python.sh"
# Identify potential bottlenecks
echo ""
echo "Scanning for potential performance issues..."
# Check for list comprehensions that could be generators
LIST_COMP=$(grep -r "\[.*for .* in .*\]" \
--include="*.py" \
--exclude-dir=venv \
--exclude-dir=env \
. 2>/dev/null | wc -l)
echo "💡 List comprehensions found: $LIST_COMP"
echo " Consider using generators for large datasets"
# Check for database queries without indexing hints
DB_QUERIES=$(grep -r "SELECT.*FROM\|\.filter(\|\.get(" \
--include="*.py" \
. 2>/dev/null | wc -l)
if [ "$DB_QUERIES" -gt 0 ]; then
echo "💡 Database queries found: $DB_QUERIES"
echo " Ensure proper indexing and use select_related/prefetch_related"
fi
fiif [[ "$RUNTIME" == *"browser"* ]]; then
echo ""
echo "=== Browser Performance Profiling ==="
cat > "$PROFILE_DIR/profile-browser.md" << 'BROWSERPROFILE'
# Browser Performance Profiling Guide
## Chrome DevTools Performance Profiling
1. **Open Chrome DevTools**
- F12 or Right-click → Inspect
- Go to "Performance" tab
2. **Record Performance**
- Click Record button (circle)
- Interact with your app (navigate, click, scroll)
- Click Stop
3. **Analyze Results**
- Look for long tasks (> 50ms)
- Identify JavaScript execution time
- Check layout/reflow operations
- Analyze network waterfall
4. **Key Metrics**
- FCP (First Contentful Paint) - < 1.8s
- LCP (Largest Contentful Paint) - < 2.5s
- TBT (Total Blocking Time) - < 200ms
- CLS (Cumulative Layout Shift) - < 0.1
## Lighthouse Audit
```bash
# Install Lighthouse CLI
npm install -g lighthouse
# Run audit
lighthouse http://localhost:3000 --view
# Or programmatically
npx lighthouse http://localhost:3000 --output html --output-path ./lighthouse-report.htmlnpm install --save-dev webpack-bundle-analyzer
# Add to webpack.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
}
# Run build
npm run buildnpm install --save-dev rollup-plugin-visualizer
# Add to vite.config.js
import { visualizer } from 'rollup-plugin-visualizer';
export default {
plugins: [
visualizer({ open: true })
]
}
# Run build
npm run buildimport { Profiler } from 'react';
function onRenderCallback(
id, phase, actualDuration, baseDuration, startTime, commitTime
) {
console.log(`${id} took ${actualDuration}ms to render`);
}
<Profiler id="MyComponent" onRender={onRenderCallback}>
<MyComponent />
</Profiler>
## Phase 6: Generate Performance Report
I'll create a comprehensive performance analysis report:
```bash
echo ""
echo "=== Generating Performance Report ==="
cat > "$REPORT" << EOF
# Performance Profile Report
**Generated:** $(date)
**Runtime:** $RUNTIME
**Project:** $(basename $(pwd))
---
## Profiling Setup
### Environment
- **Runtime:** $RUNTIME
- **Node Version:** ${NODE_VERSION:-N/A}
- **Python Version:** ${PYTHON_VERSION:-N/A}
### Tools Available
EOF
# Add tool-specific sections
if [[ "$RUNTIME" == *"nodejs"* ]]; then
cat >> "$REPORT" << 'EOF'
#### Node.js Profiling Tools
- clinic.js suite (doctor, flame, bubbleprof, heapprofiler)
- V8 built-in profiler (--prof)
- Chrome DevTools inspector
- autocannon (HTTP benchmarking)
**Run profiling:**
```bash
./claude/profiling/profile-node.sh 1 # Clinic doctor
./claude/profiling/profile-node.sh 2 # Flame graph
./claude/profiling/profile-node.sh 6 # Load test./claude/profiling/profile-python.sh 1 # cProfile
./claude/profiling/profile-python.sh 2 # line_profilercat .claude/profiling/profile-browser.md
## Summary
```bash
echo ""
echo "=== ✓ Performance Profiling Setup Complete ==="
echo ""
echo "🎯 Runtime Environment: $RUNTIME"
echo ""
echo "📁 Generated files:"
echo " - $REPORT"
if [[ "$RUNTIME" == *"nodejs"* ]]; then
echo " - $PROFILE_DIR/profile-node.sh"
fi
if [[ "$RUNTIME" == *"python"* ]]; then
echo " - $PROFILE_DIR/profile-python.sh"
fi
if [[ "$RUNTIME" == *"browser"* ]]; then
echo " - $PROFILE_DIR/profile-browser.md"
fi
echo ""
echo "🚀 Quick Start:"
echo ""
if [[ "$RUNTIME" == *"nodejs"* ]]; then
echo "Node.js Profiling:"
echo " $PROFILE_DIR/profile-node.sh 1 # Comprehensive diagnosis"
echo " $PROFILE_DIR/profile-node.sh 2 # CPU flame graph"
echo " $PROFILE_DIR/profile-node.sh 6 # HTTP load test"
echo ""
fi
if [[ "$RUNTIME" == *"python"* ]]; then
echo "Python Profiling:"
echo " $PROFILE_DIR/profile-python.sh 1 # CPU profiling"
echo " $PROFILE_DIR/profile-python.sh 2 # Line-by-line"
echo ""
fi
if [[ "$RUNTIME" == *"browser"* ]]; then
echo "Browser Profiling:"
echo " lighthouse http://localhost:3000 --view"
echo " cat $PROFILE_DIR/profile-browser.md # Full guide"
echo ""
fi
echo "📊 Performance Analysis Workflow:"
echo ""
echo "1. Establish baseline performance"
echo " - Run profiling on current code"
echo " - Record key metrics (response time, memory, CPU)"
echo ""
echo "2. Identify bottlenecks"
echo " - Find slowest functions/routes"
echo " - Check database queries"
echo " - Analyze bundle size"
echo ""
echo "3. Optimize iteratively"
echo " - Fix highest-impact issues first"
echo " - Re-profile after each change"
echo " - Measure improvement"
echo ""
echo "4. Set performance budgets"
echo " - Bundle size limits"
echo " - Response time targets"
echo " - Memory usage constraints"
echo ""
echo "💡 Common Bottlenecks:"
echo " - Synchronous blocking operations"
echo " - N+1 database queries"
echo " - Large bundle sizes"
echo " - Unoptimized images"
echo " - Missing caching"
echo " - Inefficient algorithms"
echo ""
echo "🔗 Integration Points:"
echo " - /debug-root-cause - Investigate performance issues"
echo " - /test - Add performance tests"
echo " - /ci-setup - Add performance budgets to CI"
echo ""
echo "View full report: cat $REPORT"