# Performance Testing Guide This guide covers beads' performance testing framework, including running benchmarks, profiling, and diagnosing performance issues. ## Overview The beads performance testing framework provides: - **Benchmarks**: Measure operation speed on 10K-20K issue databases - **CPU Profiling**: Automatic profiling during benchmarks with flamegraph support - **User Diagnostics**: `bd doctor --perf` for end-user performance analysis - **Database Caching**: One-time generation of test databases, reused across runs Performance issues typically only manifest at scale (10K+ issues), so benchmarks focus on large databases. ## Running Benchmarks ### Full Benchmark Suite ```bash make bench ``` This runs all benchmarks with: - 1 second per benchmark (`-benchtime=1s`) - 10K and 20K issue databases - Automatic CPU profiling - 30 minute timeout Output includes: - `ns/op` - Nanoseconds per operation - `allocs/op` - Memory allocations per operation - Profile file path ### Quick Benchmarks For faster iteration during development: ```bash make bench-quick ``` Uses shorter benchmark time (100ms) for quicker feedback. ### Running Specific Benchmarks ```bash # Run only GetReadyWork benchmarks go test -bench=BenchmarkGetReadyWork -benchtime=1s -tags=bench -run=^$ ./internal/storage/sqlite/ # Run only Large (10K) benchmarks go test -bench=Large -benchtime=1s -tags=bench -run=^$ ./internal/storage/sqlite/ ``` ### Understanding Benchmark Output ``` BenchmarkGetReadyWork_Large-8 1234 812345 ns/op 12345 B/op 123 allocs/op ``` | Field | Meaning | |-------|---------| | `-8` | Number of CPU cores used | | `1234` | Number of iterations run | | `812345 ns/op` | ~0.8ms per operation | | `12345 B/op` | Bytes allocated per operation | | `123 allocs/op` | Heap allocations per operation | **Performance Targets:** - `GetReadyWork`: < 50ms on 20K database - `SearchIssues`: < 100ms on 20K database - `CreateIssue`: < 10ms ## Profiling and Analysis ### CPU Profiling Benchmarks automatically generate CPU profiles: ```bash # Run benchmarks (generates profile) make bench # View profile in browser (flamegraph) cd internal/storage/sqlite go tool pprof -http=:8080 bench-cpu-*.prof ``` This opens an interactive web UI at `http://localhost:8080` with: - **Flamegraph**: Visual call stack (wider = more time) - **Graph**: Call graph with time percentages - **Top**: Functions by CPU time ### Reading Flamegraphs 1. **Width = Time**: Wider bars consume more CPU time 2. **Stacks grow upward**: Callees above callers 3. **Look for wide bars**: These are optimization targets 4. **Click to zoom**: Focus on specific call stacks Common hotspots in database operations: - SQL query execution - JSON encoding/decoding - Memory allocations ### Memory Profiling For memory-focused analysis: ```bash # Generate memory profile go test -bench=BenchmarkGetReadyWork_Large -benchtime=1s -tags=bench -run=^$ \ -memprofile=mem.prof ./internal/storage/sqlite/ # View memory profile go tool pprof -http=:8080 mem.prof ``` Look for: - Large allocation sizes - Frequent small allocations - Retained memory that should be freed ## User Diagnostics ### Using `bd doctor --perf` End users can run performance diagnostics: ```bash bd doctor --perf ``` This: 1. Measures time for common operations 2. Generates a CPU profile 3. Reports any performance issues 4. Provides the profile file path for sharing ### Sharing Profiles with Bug Reports When reporting performance issues: 1. Run `bd doctor --perf` 2. Note the profile file path from output 3. Attach the `.prof` file to the bug report 4. Include the diagnostic output ### Understanding the Report ``` Performance Diagnostics ======================= Database size: 15,234 issues GetReadyWork: 45ms [OK] SearchIssues: 78ms [OK] CreateIssue: 8ms [OK] CPU profile saved: beads-perf-2024-01-15-143022.prof ``` Status indicators: - `[OK]` - Within acceptable range - `[SLOW]` - Slower than expected, may need investigation - `[CRITICAL]` - Significantly degraded, likely a bug ## Comparing Performance ### Using benchstat Install benchstat: ```bash go install golang.org/x/perf/cmd/benchstat@latest ``` Compare before/after: ```bash # Save baseline go test -bench=. -count=5 -tags=bench -run=^$ ./internal/storage/sqlite/ > old.txt # Make changes, then run again go test -bench=. -count=5 -tags=bench -run=^$ ./internal/storage/sqlite/ > new.txt # Compare benchstat old.txt new.txt ``` Output shows: - Performance change percentage - Statistical significance (p-value) - Confidence that change is real Example: ``` name old time/op new time/op delta GetReadyWork_Large-8 812µs ± 2% 654µs ± 1% -19.46% (p=0.000 n=5+5) ``` ### Detecting Regressions A change is significant if: - Delta is > 5% - p-value is < 0.05 - Consistent across multiple runs (`-count=5` or more) ## Tips for Optimization ### When to Profile vs Benchmark | Use Case | Tool | |----------|------| | "Is this fast enough?" | Benchmark | | "Why is this slow?" | Profile | | "Did my change help?" | benchstat | | "User reports slowness" | `bd doctor --perf` | ### Common Optimization Patterns 1. **Reduce allocations**: Reuse buffers, avoid `append` in loops 2. **Batch database operations**: One query instead of N 3. **Use indexes**: Ensure queries hit SQLite indexes 4. **Avoid N+1 queries**: Fetch related data in single query 5. **Cache computed values**: Store results that don't change ### Optimization Workflow 1. **Measure first**: Get baseline numbers 2. **Profile**: Identify the actual hotspot 3. **Optimize**: Make targeted changes 4. **Verify**: Confirm improvement with benchstat 5. **Test**: Ensure correctness wasn't sacrificed ### Database-Specific Tips - Check `EXPLAIN QUERY PLAN` for slow queries - Ensure indexes exist for filtered columns - Consider `PRAGMA optimize` after large imports - Watch for table scans on large tables ## Cleaning Up Remove benchmark artifacts: ```bash make clean ``` This removes: - CPU profile files (`bench-cpu-*.prof`) - User diagnostic profiles (`beads-perf-*.prof`) - Cached benchmark databases are in `/tmp/beads-bench-cache/` To clear cached databases: ```bash rm -rf /tmp/beads-bench-cache/ ``` ## See Also - [TESTING.md](TESTING.md) - General testing guide - [ARCHITECTURE.md](ARCHITECTURE.md) - System architecture - [INTERNALS.md](INTERNALS.md) - Implementation details