profile
Analyzes CPU profiles to identify performance bottlenecks and generate optimization recommendations
When & Why to Use This Skill
This Claude skill is a specialized performance diagnostic tool designed to analyze CPU profiles and identify execution bottlenecks within complex applications. It streamlines the optimization workflow by capturing detailed profiling data, enriching WebAssembly (WASM) symbols, and providing actionable recommendations to reduce latency. By automating the detection of performance 'red flags'—such as excessive garbage collection, boundary crossing overhead, and inefficient string operations—it empowers developers to achieve high-performance code targets with data-driven insights.
Use Cases
- Identifying performance hotspots in data-intensive tasks like JSON parsing and schema building using automated benchmark scenarios.
- Diagnosing memory pressure issues by analyzing Garbage Collection (GC) percentages and allocation patterns in CPU profiles.
- Optimizing WebAssembly (WASM) performance through symbol demangling, boundary crossing analysis, and hot-path disassembly.
- Validating performance stability across different payload sizes and data structures to ensure scalability before production deployment.
| name | profile |
|---|---|
| description | Analyzes CPU profiles to identify performance bottlenecks and generate optimization recommendations |
Profile Skill
Investigate performance bottlenecks through CPU profiling and benchmark analysis.
Quick Start
1. Collect CPU Profiles
SCENARIO=simple-object npm run profile:cpu # Runs scenario + captures CPU profile
SCENARIO=simple-object npm run profile:detailed # With deopt/opt analysis
# Or run directly with tsx
PROFILE_ITERATIONS=5000 node ./node_modules/tsx/dist/cli.mjs benchmark/scenarios/complex-object.ts
These scripts automatically build with debug symbols and run the specified scenario file while capturing profiles to /profiles/*.cpuprofile.
Two-Phase Profiling:
Scenarios generate two separate .cpuprofile files per run:
{scenario-name}-schema-building-{timestamp}.cpuprofile- Schema creation profiling{scenario-name}-parsing-{timestamp}.cpuprofile- JSON parsing profiling
Available Scenarios:
simple-object- Simple 4-field user object (default: 50,000 iterations)complex-object- 100 users with nested structures (default: 5,000 iterations)1000-number-objects- 1000 objects with 3 number fields (default: 5,000 iterations)10000-number-objects- 10,000 objects with 3 number fields (default: 1,000 iterations)1000-user-objects-fail-fast- 1000 user objects with validation failures (default: 500 iterations)fail-fast-user- User validation that fails fast (default: 5,000 iterations)1000-simple-objects-70-30-valid- 1000 simple objects (70% valid, default: 5,000 iterations)1000-simple-objects-90-10-valid- 1000 simple objects (90% valid, default: 5,000 iterations)1000-nested-user-objects-70-30-valid- 1000 nested user objects (70% valid, default: 1,000 iterations)1000-nested-user-objects-90-10-valid- 1000 nested user objects (90% valid, default: 1,000 iterations)
Note: The SCENARIO environment variable is required. Each scenario runs multiple iterations for profiling.
Configuring Iteration Counts
All scenarios support environment variables to customize iteration counts:
# Run with custom iteration count
PROFILE_ITERATIONS=100000 SCENARIO=simple-object npm run profile:cpu
# For parsing-overhead scenario, customize both small and large payloads separately
PROFILE_ITERATIONS=100000 PROFILE_ITERATIONS_LARGE=10000 SCENARIO=parsing-overhead npm run profile:cpu
# Run fewer iterations for quick profiling (less CPU time)
PROFILE_ITERATIONS=1000 SCENARIO=large-array npm run profile:cpu
Default Iteration Counts by Scenario:
| Scenario | Default | Use Case |
|---|---|---|
simple-object |
50,000 | High iteration count for sampling granularity |
complex-object |
5,000 | Medium iteration count for nested structures |
1000-number-objects |
5,000 | Medium iteration count for number parsing |
10000-number-objects |
1,000 | Lower count due to large payload size |
1000-user-objects-fail-fast |
500 | Lower count, error path overhead analysis |
fail-fast-user |
5,000 | Medium count for both early/late failure paths |
1000-simple-objects-70-30-valid |
5,000 | Mixed valid/invalid simple objects |
1000-simple-objects-90-10-valid |
5,000 | Mixed valid/invalid simple objects |
1000-nested-user-objects-70-30-valid |
1,000 | Mixed valid/invalid nested objects |
1000-nested-user-objects-90-10-valid |
1,000 | Mixed valid/invalid nested objects |
Tips for Iteration Counts:
- Quick profiling (2-5 sec): Use
PROFILE_ITERATIONS=1000for faster turnaround - Production-like (30+ sec): Use defaults or increase to 100,000+ for stable profiles
- Memory pressure testing: Increase iterations to stress allocation patterns
- Boundary crossing analysis: Lower iterations (1,000-5,000) to focus on call overhead
2. Verify Profile Quality
Before analyzing, check that the profile has good quality:
# Find the latest profile
ls -lt profiles/*.cpuprofile | head -1
Read the .cpuprofile file and verify:
Quality Checklist:
- ✓ Profile has
nodesarray with function names (not just addresses) - ✓ WASM function names are demangled (e.g.,
atchara_wasm::lexer::parsenot justwasm-function[123]) - ✓ Profile has
samplesarray with sufficient data points (>1000 samples) - ✓
timeDeltasare present and reasonable (microseconds) - ✓ Top functions show recognizable names from Atchara codebase
Red Flags:
- ✗ Most functions are anonymous or numeric IDs only
- ✗ No WASM function names visible
- ✗ Very few samples (<100)
- ✗ Missing
nodesorsamplesarrays
If profile quality is poor, rebuild with debug symbols:
npm run build:profile
SCENARIO=simple-object npm run profile:cpu
3. Analyze the Profile
# Basic analysis with WASM symbol enrichment
node .claude/skills/profile/analyze-profile.mjs profiles/simple-object-parsing-*.cpuprofile
# With WASM function disassembly
node .claude/skills/profile/analyze-profile.mjs profiles/simple-object-parsing-*.cpuprofile --disassemble
# JSON output for programmatic analysis
node .claude/skills/profile/analyze-profile.mjs profiles/simple-object-parsing-*.cpuprofile --json
# Help
node .claude/skills/profile/analyze-profile.mjs --help
The analyzer script automatically:
- Extracts WASM function symbols from the binary using
wasm-objdump - Categorizes functions (WASM, GC, boundary crossing, string ops, etc.)
- Calculates CPU time percentages and identifies hotspots
- Flags performance issues (high GC, excessive boundary crossing)
- Suggests specific optimization opportunities
- Optionally disassembles hot WASM functions with
wasm2wat
Performance Targets
- Parsing Logic: <55% (WASM functions, tokens, validation)
- Garbage Collection: <15% (allocation pressure)
- Boundary Crossing: <2% (JS/WASM marshaling)
- String Operations: <10% (UTF-8 encoding/decoding)
Red Flags (Automatic detection by analyzer)
- GC > 25% = Memory allocation crisis
- Boundary crossing > 5% = Excessive marshaling overhead
ReflectAPI in hot path = Expensive property lookups- String cloning in loops = Redundant copies
Commands Reference
# Build and profile
npm run build:profile # Build with debug symbols
SCENARIO=<name> npm run profile:cpu # Capture CPU profile
PROFILE_ITERATIONS=<count> SCENARIO=<name> npm run profile:cpu # Custom iteration count
# Analyze profiles
node .claude/skills/profile/analyze-profile.mjs <profile.cpuprofile> # Basic analysis
node .claude/skills/profile/analyze-profile.mjs <profile.cpuprofile> --disassemble # With disassembly
node .claude/skills/profile/analyze-profile.mjs <profile.cpuprofile> --json # JSON output
node .claude/skills/profile/analyze-profile.mjs <profile.cpuprofile> --top 30 # Show top 30 functions
# Find latest profile
ls -lt profiles/*.cpuprofile | head -1
# Example workflow
SCENARIO=1000-number-objects npm run profile:cpu
node .claude/skills/profile/analyze-profile.mjs profiles/1000-number-objects-parsing-*.cpuprofile
Profile Analyzer
The analyze-profile.mjs script enriches .cpuprofile files with WASM debugging information.
Features:
- Extracts WASM function symbols (names, sizes) using
wasm-objdump - Categorizes functions (WASM/Rust, GC, boundary crossing, string ops)
- Calculates CPU time percentages and identifies hotspots
- Detects red flags (high GC, excessive boundary crossing)
- Provides optimization recommendations
- Optional WASM disassembly with
wasm2wat
Options:
--top <n>- Show top N functions (default: 20)--disassemble- Include WASM disassembly for hot functions--threshold <n>- Disassemble functions >n% CPU time (default: 5)--json- Output as JSON--wasm <path>- Custom WASM binary location
Dependencies: brew install wabt binaryen
Related Files
- profiles/*.cpuprofile - CPU profile data files
- benchmark/scenarios/ - Profiling scenario files
- benchmark/profiler.ts - Profiler utility and API
- .claude/skills/profile/analyze-profile.mjs - Profile analyzer script with WASM debugging
- package.json - Benchmark and profiling npm scripts
- pkg/atchara_wasm_bg.wasm - WASM binary with debug symbols
- wasm/src/lexer/ - Parsing implementation (optimization targets)
- wasm/src/parser/ - Schema validation (optimization targets)
Troubleshooting
No WASM symbols in profile:
npm run build:profile # Rebuild with debug symbols
SCENARIO=<name> npm run profile:cpu
Missing SCENARIO variable:
SCENARIO=large-array npm run profile:cpu # Must specify scenario
Profile has few samples (<100):
PROFILE_ITERATIONS=50000 SCENARIO=<name> npm run profile:cpu # Increase iterations