Skip to content

perf(discovery): pre-parse and cache whenExpr in Collector during Pack validation - #141

Merged
blue4209211 merged 2 commits into
mainfrom
bolt-preparse-when-guards
Aug 14, 2026
Merged

perf(discovery): pre-parse and cache whenExpr in Collector during Pack validation#141
blue4209211 merged 2 commits into
mainfrom
bolt-preparse-when-guards

Conversation

@blue4209211

@blue4209211 blue4209211 commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Description

⚡ Bolt Performance Optimization: Pre-parse and cache whenExpr in Collector during Pack validation

💡 Problem

During discovery_inventory runs across server fleets (up to 5,000 targets per request), runInventory calls pack.Select(res.Facts) for every single host.
Inside Pack.Select(), for every collector with a when guard, parseWhen(c.When) was previously called repeatedly for every host. parseWhen performs multiple strings.Split, string allocations, map lookups, and slice allocations for AST structures ([][]comparison) — even though Pack.validate() already checked the syntax when the pack was loaded.

For a realistic content pack with ~12 guarded collectors across a 1,000-host fleet, this caused 12,000 redundant AST parsing cycles and ~75,000 heap allocations on the inventory sweep path.

⚡ Solution

  1. Added an unexported expr *whenExpr field to Collector.
  2. In Pack.validate(), stored the compiled *whenExpr into c.expr during pack validation/verification.
  3. In Pack.Select(), evaluated c.expr directly (falling back to parseWhen(c.When) if c.expr is nil for defensive backward compatibility with ad-hoc unvalidated structs).
  4. Pre-allocated the run slice in Select() with make([]Collector, 0, len(p.Collectors)).
  5. Added benchmark coverage (BenchmarkPackSelect and BenchmarkExamplePackSelect).

📊 Benchmark Results (Apple M2 Pro)

# Before:
BenchmarkExamplePackSelect-10       331514      3690 ns/op      3536 B/op      75 allocs/op
BenchmarkPackSelect-10             1772901       671.8 ns/op     464 B/op      14 allocs/op

# After:
BenchmarkExamplePackSelect-10      2942226       399.2 ns/op    1024 B/op       1 allocs/op
BenchmarkPackSelect-10            14205189        98.47 ns/op    176 B/op       1 allocs/op
  • Speedup: 9.24x faster (89.2% latency reduction) for 17-collector production packs; 6.82x faster for 3-collector packs.
  • Memory: 71.0% reduction in bytes allocated per host selection.
  • Allocations: 98.7% reduction in allocations (from 75 allocs down to 1 single alloc per host).

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Enhancement (non-breaking change which improves existing functionality)
  • Refactor (non-breaking change which improves code structure)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation
  • CI/CD

How Has This Been Tested?

  • Unit tests
  • Manual testing

Ran make lint (0 issues), go test -race ./... (all packages pass), and go test -bench="BenchmarkPackSelect|BenchmarkExamplePackSelect" -benchmem ./pkg/proxy/discovery.

Checklist

  • CLA signed (the CLA bot will prompt on your first PR)
  • make validate passes (fmt + lint + test)
  • Docs updated if the wire shape, config surface, or proxy module behavior changed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces performance optimizations to the discovery pack parsing and evaluation logic. Key changes include replacing static map lookups with a switch statement to eliminate heap allocations, pre-parsing and caching guard expressions (when expressions) during pack validation to avoid repeated parsing during host sweeps, and optimizing signature verification to avoid duplicate line parsing. Additionally, several benchmarks have been added to track these performance improvements. There are no review comments, so no feedback is provided.

@blue4209211
blue4209211 force-pushed the bolt-preparse-when-guards branch from 26af385 to fabfb34 Compare August 14, 2026 15:27
@blue4209211
blue4209211 merged commit cec2767 into main Aug 14, 2026
6 checks passed
@blue4209211
blue4209211 deleted the bolt-preparse-when-guards branch August 14, 2026 16:41
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.

2 participants