Skip to content

feat: performance optimizations and test coverage improvements#2

Merged
leonardomso merged 8 commits into
masterfrom
feat/improvements
Jan 1, 2026
Merged

feat: performance optimizations and test coverage improvements#2
leonardomso merged 8 commits into
masterfrom
feat/improvements

Conversation

@leonardomso

Copy link
Copy Markdown
Owner

Summary

This PR introduces significant performance optimizations, improved test coverage, and documentation updates for the Gone dead link checker.

Changes

Performance Optimizations

  • 22x faster backoff delay - Replaced crypto/rand with math/rand/v2 for jitter calculation
  • Reduced memory allocations - Pre-allocated slices/maps across hot paths
  • Optimized parsing - Moved regex to package level, replaced bytes.Split with bytes.IndexByte
  • Struct field alignment - Optimized memory layout for better CPU cache utilization
  • Reduced bandwidth - Response body drain limit reduced from 1MB to 64KB

Test Coverage

  • Added comprehensive tests for stats and helpers packages (100% coverage)
  • Improved parser package coverage from 79.9% to 95.1%
  • Added benchmark tests for performance validation
  • Total: 197 tests across all packages

Documentation

  • Updated README with correct default values (concurrency: 50, timeout: 5s, retries: 1)
  • Removed "(coming soon)" from Homebrew section
  • Added --stats flag documentation

Benchmark Results

Benchmark Before After Improvement
BackoffDelay 206.9 ns/op, 3 allocs 9.2 ns/op, 0 allocs 22x faster
ExtractRefDefs 92.5 μs, 42KB 83.4 μs, 19KB 10% faster, 55% less memory
Summarize_Small 6.8 μs, 9 allocs 3.9 μs, 3 allocs 43% faster
BuildLineIndex 74 μs, 11 allocs 70.5 μs, 1 alloc 90% fewer allocs
FilterResultsWarnings 24 μs, 92KB 12 μs, 41KB 50% faster, 55% less memory

Commits

  • perf: optimize allocations and reduce hot path overhead
  • docs: update README with correct defaults and Homebrew availability
  • test: improve parser package coverage from 79.9% to 95.1%
  • test: add comprehensive tests for stats and helpers packages
  • chore: add gone-test to gitignore
  • perf: optimize performance with new defaults and stats tracking
  • refactor: reorganize code for better maintainability
  • perf: optimize struct field alignment for better memory usage

Testing

  • All 197 tests passing
  • Linter: 0 issues
  • Benchmarks validated performance improvements

Apply betteralign to reorder struct fields for optimal memory alignment.
This reduces memory usage by ~728 bytes across 26 structs in:
- checker (4 structs)
- parser (2 structs)
- fixer (3 structs)
- output (14 structs)
- ui (3 structs)
Split cmd/check.go (642 lines) into focused files:
- cmd/check.go (260 lines) - command definition and main flow
- cmd/check_output.go (171 lines) - output formatting functions
- cmd/check_print.go (162 lines) - text printing functions

Extract shared utilities:
- cmd/helpers.go (147 lines) - shared CLI helpers (CreateFilter, CountUniqueURLs, etc.)
- internal/helpers/helpers.go (37 lines) - generic utilities (TruncateText, TruncateURL)

Remove code duplication:
- Consolidated createFilter/createFixFilter/createInteractiveFilter into CreateFilter
- Consolidated countUniqueURLs/countFixUniqueURLs into CountUniqueURLs
- Added FilterParserLinks and ConvertParserLinks helpers

Add documentation:
- Package-level docs for ui package
- Function docs for state handlers and renderers in ui/app.go
- Enhanced docs for checker and parser packages
- Update default settings for faster checking:
  - Concurrency: 10 → 50
  - Timeout: 10s → 5s
  - MaxRetries: 2 → 1
  - MaxRedirects: 10 → 5

- Optimize HTTP transport:
  - Increase connection pool sizes (500 idle, 50 per host)
  - Enable HTTP/2 with ForceAttemptHTTP2
  - Reduce idle timeouts for faster connection cycling

- Add --stats flag for performance statistics:
  - Timing breakdown (scan/parse/check phases)
  - Throughput metrics (URLs/sec, avg response time)
  - Memory usage (heap, allocations, GC cycles)
  - Included in JSON/YAML output when requested

- Memory optimizations:
  - Pre-defined strings for status methods (avoid allocations)
  - Pre-allocated slice capacities in filter functions
  - Parallel file parsing with worker pool (bounded by NumCPU)

- Performance improvement: 84s → 14s for 755 URLs (~6x faster)
- Add tests for internal/helpers package (100% coverage):
  - TruncateText: empty, whitespace, length edge cases, unicode
  - TruncateURL: empty, shorter/equal/longer than max
  - CountUniqueStrings: nil, empty, unique, duplicates

- Add tests for internal/stats package (100% coverage):
  - Phase tracking (scan, parse, check)
  - Duration calculations
  - Throughput metrics (URLs/sec, avg response time)
  - FormatDuration and FormatBytes formatting
  - String output and JSON serialization

- Add guard clause to TruncateText for maxLen < 4
- Add testdata files for parallel processing tests (5 files)
- Add tests for parallel link extraction with 3+ files
- Add comprehensive HTML link edge case tests
- Add position tracking tests for various link types
- Add code block handling tests
- Add empty content and edge case tests

Coverage improvements:
- extractLinksParallel: 0% → 100%
- Overall parser: 79.9% → 95.1%
- Remove '(coming soon)' from Homebrew section - it's now available
- Update default values to match optimized settings:
  - concurrency: 10 → 50
  - timeout: 10s → 5s
  - retries: 2 → 1
- Add --stats flag documentation to flags tables
- Fix Go version in CI example (1.24)
Performance optimizations with benchmark validation:

checker.go:
- Replace crypto/rand with math/rand/v2 for backoff jitter (22x faster)
- Pre-allocate maps/slices in Check() deduplication
- Pre-allocate redirect chain slice (typical 1-4 hops)
- Reduce response body drain limit 1MB → 64KB

result.go:
- Combine double iteration in Summarize() into single pass
- Use struct{} for seen map to reduce memory

parser.go:
- Move refDefRegex to package level (avoid recompile per call)
- Replace bytes.Split with bytes.IndexByte (avoid allocating line slice)
- Pre-allocate links slice with estimated capacity
- Pre-allocate line index with estimated lines

cmd/helpers.go:
- Pre-allocate filter result slices with estimated ratios

output/markdown.go:
- Pre-grow string builder based on result count

Benchmark improvements:
- BenchmarkBackoffDelay: 206.9ns → 9.2ns (22x faster, 0 allocs vs 3)
- BenchmarkExtractRefDefs: 92μs → 83μs (10% faster, 55% fewer bytes)
- BenchmarkSummarize_Small: 6.8μs → 3.9μs (43% faster)
- BenchmarkBuildLineIndex: 74μs → 70μs (5% faster, 90% fewer allocs)
- BenchmarkFilterResultsWarnings: 24μs → 12μs (50% faster, 55% less memory)
@leonardomso leonardomso merged commit a33c733 into master Jan 1, 2026
2 checks passed
@leonardomso leonardomso deleted the feat/improvements branch January 1, 2026 17:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant