test benchmarks
Run benchmarks with:
go test -bench=. -benchmem
func BenchmarkIsPalindrome(b *testing.B) {
for i := 0; i < b.N; i++ {
IsPalindrome("A man, a plan, a canal: Panama")
}
}
benchmark non-tests
cpu
Slap this at the start of your program.
f, err := os.Create("cpu.prof")
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
One problem you might run into is that your defer wont run if you control-c out of your program. This is a general rule, but in this particular case if means your profile wont be written. You can catch that signal and stop the profile there and then exit out:
f, err := os.Create("cpu.prof")
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
<-c
pprof.StopCPUProfile()
os.Exit(1)
}()
mem
Memory profiling is similar except that the relevant function needs called just once before the program closes.
f, err := os.Create("mem.prof")
if err != nil {
log.Fatal(err)
}
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
<-c
runtime.GC()
if err := pprof.WriteHeapProfile(f); err != nil {
log.Fatal("could not write memory profile: ", err)
}
f.Close()
os.Exit(1)
}()
https://pkg.go.dev/golang.org/x/perf/cmd/benchstat
This tool makes it super easy to store benchmark results and later compare them.
profiling
Generate profiles:
go test -cpuprofile=cpu.out
go test -blockprofile=block.out
go test -memprofile=mem.out
Often you want profiles for benchmarks not tests:
go test -run=NONE -bench=BenchmarkIsPalindrome -cpuprofile=cpu.out
Printing out text info about a profile:
go tool pprof -text -nodecount=10 ./palindrome.test cpu.out
You can also render it to a nice SVG or DOT format if the graphviz program is installed. The SVG renders great in a web browser.
Additionally, there's a nice package that can be used to profile some specific
code easily:
https://github.com/pkg/profile
disable CPU frequency scaling
This will give a more fair benchmark when comparing tools.
!/bin/bash
for i in /sys/devices/system/cpu/cpu[0-7]
do
echo performance > $i/cpufreq/scaling_governor
done
fake io.Writer
Sometimes you need to benchmark a function with an io.Writer, but don't actually
want to waste memory or space by storing the data. You can using the
iotest.TrunctateWriter
for this:
buf := new(bytes.Buffer)
w := iotest.TruncateWriter(buf, 0) // no need to actually store the data
tricks
struct alignment
There's also a linter (disabled by default) as part of golintci called:
fieldalignment
which checks for places where you can improve this.