aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/stack_test.go
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2017-10-27 15:20:21 -0400
committerAustin Clements <austin@google.com>2017-10-30 16:33:55 +0000
commit15d6ab69fbd8c84cde109def59c7e002296c19e8 (patch)
tree4e41f0e94965a21024d4c3bd13011edfea04922c /src/runtime/stack_test.go
parent67a7d5d88503646a7e411cf5ae9c38e485b9be1b (diff)
downloadgo-15d6ab69fbd8c84cde109def59c7e002296c19e8.tar.gz
go-15d6ab69fbd8c84cde109def59c7e002296c19e8.zip
runtime: make systemstack tail call if already switched
Currently systemstack always calls its argument, even if we're already on the system stack. Unfortunately, traceback with _TraceJump stops at the first systemstack it sees, which often cuts off runtime stacks early in profiles. Fix this by performing a tail call if we're already on the system stack. This eliminates it from the traceback entirely, so it won't stop prematurely (or all get mushed into a single node in the profile graph). Change-Id: Ibc69e8765e899f8d3806078517b8c7314da196f4 Reviewed-on: https://go-review.googlesource.com/74050 Reviewed-by: Cherry Zhang <cherryyz@google.com> Reviewed-by: Keith Randall <khr@golang.org>
Diffstat (limited to 'src/runtime/stack_test.go')
-rw-r--r--src/runtime/stack_test.go33
1 files changed, 33 insertions, 0 deletions
diff --git a/src/runtime/stack_test.go b/src/runtime/stack_test.go
index c9b84be066..8e7c7d47a8 100644
--- a/src/runtime/stack_test.go
+++ b/src/runtime/stack_test.go
@@ -5,6 +5,7 @@
package runtime_test
import (
+ "bytes"
"fmt"
. "runtime"
"strings"
@@ -685,3 +686,35 @@ func TestStackWrapperStack(t *testing.T) {
t.Fatalf("<autogenerated> appears in stack trace:\n%s", stk)
}
}
+
+func TestTracebackSystemstack(t *testing.T) {
+ if GOARCH == "ppc64" || GOARCH == "ppc64le" {
+ t.Skip("systemstack tail call not implemented on ppc64x")
+ }
+
+ // Test that profiles correctly jump over systemstack,
+ // including nested systemstack calls.
+ pcs := make([]uintptr, 20)
+ pcs = pcs[:TracebackSystemstack(pcs, 5)]
+ // Check that runtime.TracebackSystemstack appears five times
+ // and that we see TestTracebackSystemstack.
+ countIn, countOut := 0, 0
+ frames := CallersFrames(pcs)
+ var tb bytes.Buffer
+ for {
+ frame, more := frames.Next()
+ fmt.Fprintf(&tb, "\n%s+0x%x %s:%d", frame.Function, frame.PC-frame.Entry, frame.File, frame.Line)
+ switch frame.Function {
+ case "runtime.TracebackSystemstack":
+ countIn++
+ case "runtime_test.TestTracebackSystemstack":
+ countOut++
+ }
+ if !more {
+ break
+ }
+ }
+ if countIn != 5 || countOut != 1 {
+ t.Fatalf("expected 5 calls to TracebackSystemstack and 1 call to TestTracebackSystemstack, got:%s", tb.String())
+ }
+}