1
0
mirror of https://github.com/golang/go synced 2024-11-12 00:20:22 -07:00

runtime: make gcTestMoveStackOnNextCall not double the stack

Currently, gcTestMoveStackOnNextCall doubles the stack allocation on
each call because stack movement always doubles the stack. That's
rather unfortunate if you're doing a bunch of stack movement tests in
a row that don't actually have to grow the stack because you'll
quickly hit the stack size limit even though you're hardly using any
of the stack.

Fix this by adding a special stack poison value for
gcTestMoveStackOnNextCall that newstack recognizes and inhibits the
allocation doubling.

Change-Id: Iace7055a0f33cb48dc97b8f4b46e45304bee832c
Reviewed-on: https://go-review.googlesource.com/c/go/+/306672
Trust: Austin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
Austin Clements 2021-04-01 16:50:53 -04:00
parent 41e8a9f1cf
commit 97b3ce430b
3 changed files with 30 additions and 2 deletions

View File

@ -242,6 +242,23 @@ func moveStackCheck(t *testing.T, new *int, old uintptr) bool {
return true return true
} }
func TestGCTestMoveStackRepeatedly(t *testing.T) {
// Move the stack repeatedly to make sure we're not doubling
// it each time.
for i := 0; i < 100; i++ {
runtime.GCTestMoveStackOnNextCall()
moveStack1(false)
}
}
//go:noinline
func moveStack1(x bool) {
// Make sure this function doesn't get auto-nosplit.
if x {
println("x")
}
}
func TestGCTestIsReachable(t *testing.T) { func TestGCTestIsReachable(t *testing.T) {
var all, half []unsafe.Pointer var all, half []unsafe.Pointer
var want uint64 var want uint64

View File

@ -2352,7 +2352,7 @@ func fmtNSAsMS(buf []byte, ns uint64) []byte {
// there's a preemption between this call and the next. // there's a preemption between this call and the next.
func gcTestMoveStackOnNextCall() { func gcTestMoveStackOnNextCall() {
gp := getg() gp := getg()
gp.stackguard0 = getcallersp() gp.stackguard0 = stackForceMove
} }
// gcTestIsReachable performs a GC and returns a bit set where bit i // gcTestIsReachable performs a GC and returns a bit set where bit i

View File

@ -132,6 +132,10 @@ const (
// Stored into g->stackguard0 to cause split stack check failure. // Stored into g->stackguard0 to cause split stack check failure.
// Must be greater than any real sp. // Must be greater than any real sp.
stackFork = uintptrMask & -1234 stackFork = uintptrMask & -1234
// Force a stack movement. Used for debugging.
// 0xfffffeed in hex.
stackForceMove = uintptrMask & -275
) )
// Global pool of spans that have free stacks. // Global pool of spans that have free stacks.
@ -1054,11 +1058,18 @@ func newstack() {
// recheck the bounds on return.) // recheck the bounds on return.)
if f := findfunc(gp.sched.pc); f.valid() { if f := findfunc(gp.sched.pc); f.valid() {
max := uintptr(funcMaxSPDelta(f)) max := uintptr(funcMaxSPDelta(f))
for newsize-oldsize < max+_StackGuard { for newsize-gp.sched.sp < max+_StackGuard {
newsize *= 2 newsize *= 2
} }
} }
if gp.stackguard0 == stackForceMove {
// Forced stack movement used for debugging.
// Don't double the stack (or we may quickly run out
// if this is done repeatedly).
newsize = oldsize
}
if newsize > maxstacksize || newsize > maxstackceiling { if newsize > maxstacksize || newsize > maxstackceiling {
if maxstacksize < maxstackceiling { if maxstacksize < maxstackceiling {
print("runtime: goroutine stack exceeds ", maxstacksize, "-byte limit\n") print("runtime: goroutine stack exceeds ", maxstacksize, "-byte limit\n")