mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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>
This commit is contained in:
parent
67a7d5d885
commit
15d6ab69fb
11 changed files with 83 additions and 18 deletions
|
|
@ -474,11 +474,12 @@ switch:
|
||||||
RET
|
RET
|
||||||
|
|
||||||
noswitch:
|
noswitch:
|
||||||
// already on system stack, just call directly
|
// already on system stack; tail call the function
|
||||||
|
// Using a tail call here cleans up tracebacks since we won't stop
|
||||||
|
// at an intermediate systemstack.
|
||||||
MOVL DI, DX
|
MOVL DI, DX
|
||||||
MOVL 0(DI), DI
|
MOVL 0(DI), DI
|
||||||
CALL DI
|
JMP DI
|
||||||
RET
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* support for morestack
|
* support for morestack
|
||||||
|
|
|
||||||
|
|
@ -419,11 +419,12 @@ switch:
|
||||||
RET
|
RET
|
||||||
|
|
||||||
noswitch:
|
noswitch:
|
||||||
// already on m stack, just call directly
|
// already on m stack; tail call the function
|
||||||
|
// Using a tail call here cleans up tracebacks since we won't stop
|
||||||
|
// at an intermediate systemstack.
|
||||||
MOVQ DI, DX
|
MOVQ DI, DX
|
||||||
MOVQ 0(DI), DI
|
MOVQ 0(DI), DI
|
||||||
CALL DI
|
JMP DI
|
||||||
RET
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* support for morestack
|
* support for morestack
|
||||||
|
|
|
||||||
|
|
@ -306,10 +306,11 @@ switch:
|
||||||
|
|
||||||
noswitch:
|
noswitch:
|
||||||
// already on m stack, just call directly
|
// already on m stack, just call directly
|
||||||
|
// Using a tail call here cleans up tracebacks since we won't stop
|
||||||
|
// at an intermediate systemstack.
|
||||||
MOVL DI, DX
|
MOVL DI, DX
|
||||||
MOVL 0(DI), DI
|
MOVL 0(DI), DI
|
||||||
CALL DI
|
JMP DI
|
||||||
RET
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* support for morestack
|
* support for morestack
|
||||||
|
|
|
||||||
|
|
@ -358,10 +358,12 @@ switch:
|
||||||
RET
|
RET
|
||||||
|
|
||||||
noswitch:
|
noswitch:
|
||||||
|
// Using a tail call here cleans up tracebacks since we won't stop
|
||||||
|
// at an intermediate systemstack.
|
||||||
MOVW R0, R7
|
MOVW R0, R7
|
||||||
MOVW 0(R0), R0
|
MOVW 0(R0), R0
|
||||||
BL (R0)
|
MOVW.P 4(R13), R14 // restore LR
|
||||||
RET
|
B (R0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* support for morestack
|
* support for morestack
|
||||||
|
|
|
||||||
|
|
@ -239,9 +239,11 @@ switch:
|
||||||
|
|
||||||
noswitch:
|
noswitch:
|
||||||
// already on m stack, just call directly
|
// already on m stack, just call directly
|
||||||
|
// Using a tail call here cleans up tracebacks since we won't stop
|
||||||
|
// at an intermediate systemstack.
|
||||||
MOVD 0(R26), R3 // code pointer
|
MOVD 0(R26), R3 // code pointer
|
||||||
BL (R3)
|
MOVD.P 16(RSP), R30 // restore LR
|
||||||
RET
|
B (R3)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* support for morestack
|
* support for morestack
|
||||||
|
|
|
||||||
|
|
@ -214,9 +214,12 @@ switch:
|
||||||
|
|
||||||
noswitch:
|
noswitch:
|
||||||
// already on m stack, just call directly
|
// already on m stack, just call directly
|
||||||
|
// Using a tail call here cleans up tracebacks since we won't stop
|
||||||
|
// at an intermediate systemstack.
|
||||||
MOVV 0(REGCTXT), R4 // code pointer
|
MOVV 0(REGCTXT), R4 // code pointer
|
||||||
JAL (R4)
|
MOVV 0(R29), R31 // restore LR
|
||||||
RET
|
ADDV $8, R29
|
||||||
|
JMP (R4)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* support for morestack
|
* support for morestack
|
||||||
|
|
|
||||||
|
|
@ -215,9 +215,12 @@ switch:
|
||||||
|
|
||||||
noswitch:
|
noswitch:
|
||||||
// already on m stack, just call directly
|
// already on m stack, just call directly
|
||||||
|
// Using a tail call here cleans up tracebacks since we won't stop
|
||||||
|
// at an intermediate systemstack.
|
||||||
MOVW 0(REGCTXT), R4 // code pointer
|
MOVW 0(REGCTXT), R4 // code pointer
|
||||||
JAL (R4)
|
MOVW 0(R29), R31 // restore LR
|
||||||
RET
|
ADD $4, R29
|
||||||
|
JMP (R4)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* support for morestack
|
* support for morestack
|
||||||
|
|
|
||||||
|
|
@ -265,6 +265,9 @@ switch:
|
||||||
|
|
||||||
noswitch:
|
noswitch:
|
||||||
// already on m stack, just call directly
|
// already on m stack, just call directly
|
||||||
|
// On other arches we do a tail call here, but it appears to be
|
||||||
|
// impossible to tail call a function pointer in shared mode on
|
||||||
|
// ppc64 because the caller is responsible for restoring the TOC.
|
||||||
MOVD 0(R11), R12 // code pointer
|
MOVD 0(R11), R12 // code pointer
|
||||||
MOVD R12, CTR
|
MOVD R12, CTR
|
||||||
BL (CTR)
|
BL (CTR)
|
||||||
|
|
|
||||||
|
|
@ -224,9 +224,12 @@ switch:
|
||||||
|
|
||||||
noswitch:
|
noswitch:
|
||||||
// already on m stack, just call directly
|
// already on m stack, just call directly
|
||||||
|
// Using a tail call here cleans up tracebacks since we won't stop
|
||||||
|
// at an intermediate systemstack.
|
||||||
MOVD 0(R12), R3 // code pointer
|
MOVD 0(R12), R3 // code pointer
|
||||||
BL (R3)
|
MOVD 0(R15), LR // restore LR
|
||||||
RET
|
ADD $8, R15
|
||||||
|
BR (R3)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* support for morestack
|
* support for morestack
|
||||||
|
|
|
||||||
|
|
@ -395,3 +395,16 @@ func LockOSCounts() (external, internal uint32) {
|
||||||
}
|
}
|
||||||
return g.m.lockedExt, g.m.lockedInt
|
return g.m.lockedExt, g.m.lockedInt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:noinline
|
||||||
|
func TracebackSystemstack(stk []uintptr, i int) int {
|
||||||
|
if i == 0 {
|
||||||
|
pc, sp := getcallerpc(), getcallersp(unsafe.Pointer(&stk))
|
||||||
|
return gentraceback(pc, sp, 0, getg(), 0, &stk[0], len(stk), nil, nil, _TraceJumpStack)
|
||||||
|
}
|
||||||
|
n := 0
|
||||||
|
systemstack(func() {
|
||||||
|
n = TracebackSystemstack(stk, i-1)
|
||||||
|
})
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
package runtime_test
|
package runtime_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
. "runtime"
|
. "runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -685,3 +686,35 @@ func TestStackWrapperStack(t *testing.T) {
|
||||||
t.Fatalf("<autogenerated> appears in stack trace:\n%s", stk)
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue