Skip to content

Add Go benchmarks for hot paths: Check, Lookup, GetRoute, statsd emission #35

@dolph

Description

@dolph

Summary

The codebase has no *_test.go benchmarks. Every performance discussion (this issue, #11, and the proposed fixes in #21) ends up arguing about ballpark numbers. A small benchmark suite gives a real baseline before any rework and prevents regressions after.

Scope

Add Benchmark* functions covering the per-check hot paths and the metric pipeline. Suggested set:

  1. BenchmarkCheck (destinations_bench_test.go) — full Check() against localhost with a stub statsd drain. Measures end-to-end per-check overhead including DNS, routing, dial, HTTPS.

  2. BenchmarkLookup (resolver_bench_test.go) — pure DNS path. Pairs with #-DNS-caching once filed.

  3. BenchmarkGetRoute (router_bench_test.go) — quantifies routing.New() per-call cost. Pairs with the routing-table-cache issue.

  4. BenchmarkDestinationIncrement + BenchmarkTagsRebuild (destinations_bench_test.go) — allocations in the metric tag path. Pairs with the dest.tags() caching issue.

  5. BenchmarkStatsdSender (statsd_bench_test.go) — connection-per-metric cost; needs a UDP listener on 127.0.0.1:0 as a sink. Pairs with Statsd emitter can stall checks when statsd is down; opens a new connection per metric #11.

  6. BenchmarkGetLocalIPs (source_bench_test.go) — quantifies the per-log-line cost flagged in Logs are unstructured plain text without levels; GetLocalIPs runs per log line #21.

  7. BenchmarkMonitorThroughput — simulates 100/500/1000 destinations to measure goroutine + GC + statsd-queue behavior with b.RunParallel and a stub server.

Helpful conventions

  • All benchmarks call b.ReportAllocs() so allocs/op is in the output.
  • Use testing.B.Run(name, ...) to parameterize by destination count for the monitor-throughput benchmark.
  • Add a make bench target (or ./build.sh bench) running go test -bench=. -benchmem ./....
  • Optionally wire into CI as a smoke run (-benchtime=1x) and a separate manual go test -bench=. -benchtime=10s workflow for serious measurement.

Stub statsd sink

Most of the above benchmarks need a way to keep the queue <- s send from blocking. Two options:

// Option A: drain into /dev/null
func init() { go func() { for range queue {} }() }

// Option B: replace the sender for the test

Either works; Option B is cleaner once #11 lands and the sender becomes an interface.

Why bother

Related

Cross-references: #11 (statsd sender), #21 (GetLocalIPs per log line), plus the three perf issues filed alongside this one.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions