aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/pprof
diff options
context:
space:
mode:
authorFelix Geisendörfer <felix.geisendoerfer@datadoghq.com>2021-09-20 16:09:47 +0200
committerMichael Pratt <mpratt@google.com>2021-11-02 15:15:09 +0000
commitda7173a2ed637c803b8ff59d0c948e7c7d056c50 (patch)
treecf43b024f8f2a587b6351a409e8410cefd30c837 /src/runtime/pprof
parent4d7bf41bebc7ad4f71150b8b57fca12aff6da144 (diff)
downloadgo-da7173a2ed637c803b8ff59d0c948e7c7d056c50.tar.xz
runtime: fix missing pprof labels
Use gp.m.curg instead of the gp when recording cpu profiler stack traces. This ensures profiler labels are captured when systemstack or similar is executing on behalf of the current goroutine. After this there are still rare cases of samples containing the labelHog function, so more work might be needed. This patch should fix ~99% of the problem. Fixes #48577. Change-Id: I27132110e3d09721ec3b3ef417122bc70d8f3279 Reviewed-on: https://go-review.googlesource.com/c/go/+/351751 Reviewed-by: Michael Pratt <mpratt@google.com> Run-TryBot: Michael Pratt <mpratt@google.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Michael Knyszek <mknyszek@google.com>
Diffstat (limited to 'src/runtime/pprof')
-rw-r--r--src/runtime/pprof/pprof_test.go67
1 files changed, 67 insertions, 0 deletions
diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go
index 06e0274e9a..da006cbe45 100644
--- a/src/runtime/pprof/pprof_test.go
+++ b/src/runtime/pprof/pprof_test.go
@@ -1361,6 +1361,73 @@ func TestLabelRace(t *testing.T) {
})
}
+func TestLabelSystemstack(t *testing.T) {
+ // See http://golang.org/cl/351751.
+ prof := testCPUProfile(t, stackContainsLabeled, []string{"runtime.systemstack;key=value"}, avoidFunctions(), func(dur time.Duration) {
+ Do(context.Background(), Labels("key", "value"), func(context.Context) {
+ var wg sync.WaitGroup
+ stop := make(chan struct{})
+ for i := 0; i < runtime.GOMAXPROCS(0); i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ labelHog(stop)
+ }()
+ }
+
+ time.Sleep(dur)
+ close(stop)
+ wg.Wait()
+ })
+ })
+
+ var withLabel, withoutLabel int64
+ for _, s := range prof.Sample {
+ var systemstack, labelHog bool
+ for _, loc := range s.Location {
+ for _, l := range loc.Line {
+ switch l.Function.Name {
+ case "runtime.systemstack":
+ systemstack = true
+ case "runtime/pprof.labelHog":
+ labelHog = true
+ }
+ }
+ }
+
+ if systemstack && labelHog {
+ if s.Label != nil && contains(s.Label["key"], "value") {
+ withLabel += s.Value[0]
+ } else {
+ withoutLabel += s.Value[0]
+ }
+ }
+ }
+
+ // ratio on 2019 Intel MBP before/after CL 351751 for n=30 runs:
+ // before: mean=0.013 stddev=0.013 min=0.000 max=0.039
+ // after : mean=0.996 stddev=0.007 min=0.967 max=1.000
+ //
+ // TODO: Figure out why some samples still contain labelHog without labels.
+ // Once fixed this test case can be simplified to just check that all samples
+ // containing labelHog() have the label, and no other samples do.
+ ratio := float64(withLabel) / float64((withLabel + withoutLabel))
+ if ratio < 0.9 {
+ t.Fatalf("only %.1f%% of labelHog(systemstack()) samples have label", ratio*100)
+ }
+}
+
+func labelHog(stop chan struct{}) {
+ for i := 0; ; i++ {
+ select {
+ case <-stop:
+ return
+ default:
+ fmt.Fprintf(io.Discard, "%d", i)
+ }
+ }
+}
+
// Check that there is no deadlock when the program receives SIGPROF while in
// 64bit atomics' critical section. Used to happen on mips{,le}. See #20146.
func TestAtomicLoadStore64(t *testing.T) {