summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2023-01-04 12:31:23 -0500
committerCherry Mui <cherryyz@google.com>2023-03-15 21:35:15 +0000
commit3a50af126c1817a8285b3342f5fff4e039c7469b (patch)
treeaeb73265fe123aa956ac7313484c03944855fd67
parentfbf4c04f82a60b1f05d76765e429294ae7785236 (diff)
downloadgo-git-3a50af126c1817a8285b3342f5fff4e039c7469b.tar.gz
[release-branch.go1.19] runtime/pprof: improve output of TestLabelSystemstack
The current output of TestLabelSystemstack is a bit cryptic. This CL improves various messages and hopefully simplifies the logic in the test. Simplifying the logic leads to three changes in possible outcomes, which I verified by running the logic before and after this change through all 2^4 possibilities (https://go.dev/play/p/bnfb-OQCT4j): 1. If a sample both must be labeled and must not be labeled, the test now reports that explicitly rather than giving other confusing output. 2. If a sample must not be labeled but is, the current logic will print two identical error messages. The new logic prints only one. 3. If the test finds no frames at all that it recognizes, but the sample is labeled, it will currently print a confusing "Sample labeled got true want false" message. The new logic prints nothing. We've seen this triggered by empty stacks in profiles. Fixes #51550. This bug was caused by case 3 above, where it was triggered by a profile label on an empty stack. It's valid for empty stacks to appear in a profile if we sample a goroutine just as it's exiting (and that goroutine may have a profile label), so the test shouldn't fail in this case. For #58939. Change-Id: I1593ec4ac33eced5bb89572a3ba7623e56f2fb3d Reviewed-on: https://go-review.googlesource.com/c/go/+/460516 Run-TryBot: Austin Clements <austin@google.com> Reviewed-by: Felix Geisendörfer <felix.geisendoerfer@datadoghq.com> Reviewed-by: Michael Pratt <mpratt@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> (cherry picked from commit d9f23cfe78eadcdbde31fd931e90bebb72455648) Reviewed-on: https://go-review.googlesource.com/c/go/+/474618 Run-TryBot: Michael Pratt <mpratt@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com>
-rw-r--r--src/runtime/pprof/pprof_test.go46
1 files changed, 26 insertions, 20 deletions
diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go
index aabc180de3..47f49ac923 100644
--- a/src/runtime/pprof/pprof_test.go
+++ b/src/runtime/pprof/pprof_test.go
@@ -609,7 +609,7 @@ func matchAndAvoidStacks(matches sampleMatchFunc, need []string, avoid []string)
var total uintptr
for i, name := range need {
total += have[i]
- t.Logf("%s: %d\n", name, have[i])
+ t.Logf("found %d samples in expected function %s\n", have[i], name)
}
if total == 0 {
t.Logf("no samples in expected functions")
@@ -729,6 +729,9 @@ func TestGoroutineSwitch(t *testing.T) {
}
func fprintStack(w io.Writer, stk []*profile.Location) {
+ if len(stk) == 0 {
+ fmt.Fprintf(w, " (stack empty)")
+ }
for _, loc := range stk {
fmt.Fprintf(w, " %#x", loc.Address)
fmt.Fprintf(w, " (")
@@ -1825,14 +1828,14 @@ func TestLabelSystemstack(t *testing.T) {
isLabeled := s.Label != nil && contains(s.Label["key"], "value")
var (
mayBeLabeled bool
- mustBeLabeled bool
- mustNotBeLabeled bool
+ mustBeLabeled string
+ mustNotBeLabeled string
)
for _, loc := range s.Location {
for _, l := range loc.Line {
switch l.Function.Name {
case "runtime/pprof.labelHog", "runtime/pprof.parallelLabelHog", "runtime/pprof.parallelLabelHog.func1":
- mustBeLabeled = true
+ mustBeLabeled = l.Function.Name
case "runtime/pprof.Do":
// Do sets the labels, so samples may
// or may not be labeled depending on
@@ -1844,7 +1847,7 @@ func TestLabelSystemstack(t *testing.T) {
// (such as those identified by
// runtime.isSystemGoroutine). These
// should never be labeled.
- mustNotBeLabeled = true
+ mustNotBeLabeled = l.Function.Name
case "gogo", "gosave_systemstack_switch", "racecall":
// These are context switch/race
// critical that we can't do a full
@@ -1866,25 +1869,28 @@ func TestLabelSystemstack(t *testing.T) {
}
}
}
- if mustNotBeLabeled {
- // If this must not be labeled, then mayBeLabeled hints
- // are not relevant.
- mayBeLabeled = false
- }
- if mustBeLabeled && !isLabeled {
+ errorStack := func(f string, args ...any) {
var buf bytes.Buffer
fprintStack(&buf, s.Location)
- t.Errorf("Sample labeled got false want true: %s", buf.String())
+ t.Errorf("%s: %s", fmt.Sprintf(f, args...), buf.String())
}
- if mustNotBeLabeled && isLabeled {
- var buf bytes.Buffer
- fprintStack(&buf, s.Location)
- t.Errorf("Sample labeled got true want false: %s", buf.String())
+ if mustBeLabeled != "" && mustNotBeLabeled != "" {
+ errorStack("sample contains both %s, which must be labeled, and %s, which must not be labeled", mustBeLabeled, mustNotBeLabeled)
+ continue
}
- if isLabeled && !(mayBeLabeled || mustBeLabeled) {
- var buf bytes.Buffer
- fprintStack(&buf, s.Location)
- t.Errorf("Sample labeled got true want false: %s", buf.String())
+ if mustBeLabeled != "" || mustNotBeLabeled != "" {
+ // We found a definitive frame, so mayBeLabeled hints are not relevant.
+ mayBeLabeled = false
+ }
+ if mayBeLabeled {
+ // This sample may or may not be labeled, so there's nothing we can check.
+ continue
+ }
+ if mustBeLabeled != "" && !isLabeled {
+ errorStack("sample must be labeled because of %s, but is not", mustBeLabeled)
+ }
+ if mustNotBeLabeled != "" && isLabeled {
+ errorStack("sample must not be labeled because of %s, but is", mustNotBeLabeled)
}
}
}