From f8f6e88e3aa178ec0483ce79cf359fb8b11f345b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Sat, 3 Apr 2021 12:47:19 +0200 Subject: [PATCH] callers-func-length --- examples/callers-func-length/README.md | 14 ++ examples/callers-func-length/go.mod | 3 + examples/callers-func-length/main.go | 17 +++ examples/callers-func-length/main_test.go | 157 ++++++++++++++++++++++ 4 files changed, 191 insertions(+) create mode 100644 examples/callers-func-length/README.md create mode 100644 examples/callers-func-length/go.mod create mode 100644 examples/callers-func-length/main.go create mode 100644 examples/callers-func-length/main_test.go diff --git a/examples/callers-func-length/README.md b/examples/callers-func-length/README.md new file mode 100644 index 0000000..790ba11 --- /dev/null +++ b/examples/callers-func-length/README.md @@ -0,0 +1,14 @@ +# callers-func-length + +A simple benchmark that shows that the costs of stack unwinding in Go increase for larger functions. This is due to the way `gopclntab` based unwinding is implemented. + +``` +go test -bench . +goos: darwin +goarch: amd64 +pkg: github.com/felixge/go-profiler-notes/examples/callers-func-length +cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz +BenchmarkCallers/short-12 2623002 454.1 ns/op +BenchmarkCallers/loop-12 2590384 466.8 ns/op +BenchmarkCallers/long-12 638096 1862 ns/op +``` diff --git a/examples/callers-func-length/go.mod b/examples/callers-func-length/go.mod new file mode 100644 index 0000000..07f30ed --- /dev/null +++ b/examples/callers-func-length/go.mod @@ -0,0 +1,3 @@ +module github.com/felixge/go-profiler-notes/examples/callers-func-length + +go 1.16 diff --git a/examples/callers-func-length/main.go b/examples/callers-func-length/main.go new file mode 100644 index 0000000..46a46c3 --- /dev/null +++ b/examples/callers-func-length/main.go @@ -0,0 +1,17 @@ +package main + +import ( + "fmt" + "os" +) + +func main() { + if err := run(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func run() error { + return nil +} diff --git a/examples/callers-func-length/main_test.go b/examples/callers-func-length/main_test.go new file mode 100644 index 0000000..f35a3fb --- /dev/null +++ b/examples/callers-func-length/main_test.go @@ -0,0 +1,157 @@ +package main + +import ( + "runtime" + "testing" +) + +var callers = make([]uintptr, 32) + +func BenchmarkCallers(b *testing.B) { + b.Run("short", func(b *testing.B) { + short(func() { + for i := 0; i < b.N; i++ { + runtime.Callers(0, callers) + } + }) + }) + + b.Run("loop", func(b *testing.B) { + loop(func() { + for i := 0; i < b.N; i++ { + runtime.Callers(0, callers) + } + }) + }) + + b.Run("long", func(b *testing.B) { + long(func() { + for i := 0; i < b.N; i++ { + runtime.Callers(0, callers) + } + }) + }) +} + +func short(fn func()) { + other() + fn() +} + +func loop(fn func()) { + for i := 0; i < 1000; i++ { + other() + } + fn() +} + +func long(fn func()) { + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + other() + fn() +} + +func other() int { + m := map[int]string{} + m[0] = "foo" + m[100] = "bar" + return len(m) +}