benchinit
benchinit copied to clipboard
Benchmark the init cost of Go packages
benchinit
Benchmark the initialization cost of your packages or programs. Requires Go 1.18 or later.
go install mvdan.cc/benchinit@latest
This includes the cost of init functions and initialising globals.
In other words, a package's contribution to the slowness before main is run.
Quickstart
Benchmarking a single package is simple:
benchinit cmd/go
You can benchmark multiple packages too; there must be at most one main package:
benchinit cmd/go go/parser go/build
You can also include all dependencies in the benchmark:
benchinit -r cmd/go
Finally, like any other benchmark, you can pass in go test flags:
benchinit -r -count=5 -benchtime=2s cmd/go
Further reading
The original tool was result of a discussion with @josharian.
You can read more about Josh's idea in his blog post.
Since then, GODEBUG=inittrace=1 was added in Go 1.16,
which this tool now uses.
The following design decisions were made:
-
GODEBUG=inittrace=1requires us to run a new Go process for every benchmark iteration, sobenchinitsets up a wrapping benchmarkBenchmarkInitwhich does this and collects theinittraceoutput.BenchmarkInitthen produces oneBenchmarkPkgPathresult per package passed tobenchinit, which is shown to the user. -
benchinitsupports most build and test flags, which are passed down as needed. For example, you can use-benchtimeand-countto control how the benchmark is run, and-tagsto use build tags. Note that some test flags like-bencharen't supported, as we always run onlyBenchmarkInit. -
To avoid building a new binary,
BenchmarkInitreuses its own test binary to run the Go process for each benchmark iteration. To prevent test globals andinitfuncs from being part of the result, all*_test.gofiles are masked as deleted via-overlay. The same overlay is used to insert a temporary file containingBenchmarkInit. -
BenchmarkInitonly runs one Go process per benchmark iteration, even when benchmarking multiple packages at once. This is possible sinceinittraceprints one line per package being initialized, so we only need to ensure the test binary imports all the necessary packages to initialize them. For the same reason, we can only benchmark onemainpackage at a time. -
If none of the given packages are a
mainpackage, the benchmark is run from the first given package. This helps us support benchmarking internal packages.