From 6f3707875166643a21c4d2a12adacaebbb4bcef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Fri, 26 Mar 2021 14:28:56 +0100 Subject: [PATCH] add benchmark --- examples/goroutine/go.mod | 3 ++ examples/goroutine/main_test.go | 68 +++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 examples/goroutine/go.mod create mode 100644 examples/goroutine/main_test.go diff --git a/examples/goroutine/go.mod b/examples/goroutine/go.mod new file mode 100644 index 0000000..a8affc9 --- /dev/null +++ b/examples/goroutine/go.mod @@ -0,0 +1,3 @@ +module github.com/felixge/go-profiler-notes/examples/goroutine + +go 1.16 diff --git a/examples/goroutine/main_test.go b/examples/goroutine/main_test.go new file mode 100644 index 0000000..104ace9 --- /dev/null +++ b/examples/goroutine/main_test.go @@ -0,0 +1,68 @@ +package main + +import ( + "fmt" + "runtime" + "testing" + "time" +) + +func BenchmarkProfilerGoroutines(b *testing.B) { + max := 1024 * 1024 + buf := make([]runtime.StackRecord, max*2) + for g := 1; g <= max; g = g * 2 { + g := g + name := fmt.Sprintf("%d goroutines", g) + + b.Run(name, func(b *testing.B) { + initalRoutines := runtime.NumGoroutine() + + readyCh := make(chan struct{}) + stopCh := make(chan struct{}) + for i := 0; i < g; i++ { + go atStackDepth(8, func() { + defer func() { stopCh <- struct{}{} }() + readyCh <- struct{}{} + }) + <-readyCh + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + n, ok := runtime.GoroutineProfile(buf) + if !ok { + b.Logf("GoroutineProfile not ok") + } else if gotRoutines := n - initalRoutines; gotRoutines != g { + b.Logf("want %d goroutines, but got %d on iteration %d", g, gotRoutines, i) + } + } + b.StopTimer() + for i := 0; i < g; i++ { + <-stopCh + } + start := time.Now() + for i := 0; ; i++ { + if runtime.NumGoroutine() == initalRoutines { + break + } + time.Sleep(20 * time.Millisecond) + if time.Since(start) > 10*time.Second { + b.Fatalf("%d goroutines still running, want %d", runtime.NumGoroutine(), initalRoutines) + } + } + }) + } +} + +func atStackDepth(depth int, fn func()) { + pcs := make([]uintptr, depth+10) + n := runtime.Callers(1, pcs) + if n > depth { + panic("depth exceeded") + } else if n < depth { + atStackDepth(depth, fn) + return + } + + fn() +}