Skip to content

Commit

Permalink
runtime: track the amount of scannable allocated stack for the GC pacer
Browse files Browse the repository at this point in the history
This change adds two fields to gcControllerState: stackScan, used for
pacing decisions, and scannableStackSize, which directly tracks the
amount of space allocated for inuse stacks that will be scanned.

scannableStackSize is not updated directly, but is instead flushed from
each P when at an least 8 KiB delta has accumulated. This helps reduce
issues with atomics contention for newly created goroutines. Stack
growth paths are largely unaffected.

StackGrowth-48			51.4ns ± 0%	51.4ns ± 0%	~	(p=0.927 n=10+10)
StackGrowthDeep-48		6.14µs ± 3%	6.25µs ± 4%	~	(p=0.090 n=10+9)
CreateGoroutines-48		273ns ± 1%	273ns ± 1%	~	(p=0.676 n=9+10)
CreateGoroutinesParallel-48	65.5ns ± 5%	66.6ns ± 7%	~	(p=0.340 n=9+9)
CreateGoroutinesCapture-48	2.06µs ± 1%	2.07µs ± 4%	~	(p=0.217 n=10+10)
CreateGoroutinesSingle-48	550ns ± 3%	563ns ± 4%	+2.41%	(p=0.034 n=8+10)

For #44167.

Change-Id: Id1800d41d3a6c211b43aeb5681c57c0dc8880daf
Reviewed-on: https://go-review.googlesource.com/c/go/+/309589
Trust: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Pratt <mpratt@google.com>
  • Loading branch information
mknyszek committed Oct 29, 2021
1 parent 8e112a7 commit 9ac1ee2
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 2 deletions.
29 changes: 29 additions & 0 deletions src/runtime/mgcpacer.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ const (

// defaultHeapMinimum is the value of heapMinimum for GOGC==100.
defaultHeapMinimum = 4 << 20

// scannableStackSizeSlack is the bytes of stack space allocated or freed
// that can accumulate on a P before updating gcController.stackSize.
scannableStackSizeSlack = 8 << 10
)

func init() {
Expand Down Expand Up @@ -166,6 +170,18 @@ type gcControllerState struct {
// Read and written atomically or with the world stopped.
heapScan uint64

// stackScan is a snapshot of scannableStackSize taken at each GC
// STW pause and is used in pacing decisions.
//
// Updated only while the world is stopped.
stackScan uint64

// scannableStackSize is the amount of allocated goroutine stack space in
// use by goroutines.
//
// Read and updated atomically.
scannableStackSize uint64

// heapMarked is the number of bytes marked by the previous
// GC. After mark termination, heapLive == heapMarked, but
// unlike heapLive, heapMarked does not change until the
Expand Down Expand Up @@ -276,6 +292,7 @@ func (c *gcControllerState) startCycle(markStartTime int64) {
c.fractionalMarkTime = 0
c.idleMarkTime = 0
c.markStartTime = markStartTime
c.stackScan = atomic.Load64(&c.scannableStackSize)

// Ensure that the heap goal is at least a little larger than
// the current live heap size. This may not be the case if GC
Expand Down Expand Up @@ -686,6 +703,18 @@ func (c *gcControllerState) update(dHeapLive, dHeapScan int64) {
}
}

func (c *gcControllerState) addScannableStack(pp *p, amount int64) {
if pp == nil {
atomic.Xadd64(&c.scannableStackSize, amount)
return
}
pp.scannableStackSizeDelta += amount
if pp.scannableStackSizeDelta >= scannableStackSizeSlack || pp.scannableStackSizeDelta <= -scannableStackSizeSlack {
atomic.Xadd64(&c.scannableStackSize, pp.scannableStackSizeDelta)
pp.scannableStackSizeDelta = 0
}
}

// commit sets the trigger ratio and updates everything
// derived from it: the absolute trigger, the heap goal, mark pacing,
// and sweep pacing.
Expand Down
7 changes: 5 additions & 2 deletions src/runtime/proc.go
Original file line number Diff line number Diff line change
Expand Up @@ -3623,8 +3623,10 @@ func goexit1() {
// goexit continuation on g0.
func goexit0(gp *g) {
_g_ := getg()
_p_ := _g_.m.p.ptr()

casgstatus(gp, _Grunning, _Gdead)
gcController.addScannableStack(_p_, -int64(gp.stack.hi-gp.stack.lo))
if isSystemGoroutine(gp, false) {
atomic.Xadd(&sched.ngsys, -1)
}
Expand Down Expand Up @@ -3655,15 +3657,15 @@ func goexit0(gp *g) {
dropg()

if GOARCH == "wasm" { // no threads yet on wasm
gfput(_g_.m.p.ptr(), gp)
gfput(_p_, gp)
schedule() // never returns
}

if _g_.m.lockedInt != 0 {
print("invalid m->lockedInt = ", _g_.m.lockedInt, "\n")
throw("internal lockOSThread error")
}
gfput(_g_.m.p.ptr(), gp)
gfput(_p_, gp)
if locked {
// The goroutine may have locked this thread because
// it put it in an unusual kernel state. Kill it
Expand Down Expand Up @@ -4292,6 +4294,7 @@ func newproc1(fn *funcval, callergp *g, callerpc uintptr) *g {
newg.tracking = true
}
casgstatus(newg, _Gdead, _Grunnable)
gcController.addScannableStack(_p_, int64(newg.stack.hi-newg.stack.lo))

if _p_.goidcache == _p_.goidcacheend {
// Sched.goidgen is the last allocated id,
Expand Down
6 changes: 6 additions & 0 deletions src/runtime/runtime2.go
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,12 @@ type p struct {
// Race context used while executing timer functions.
timerRaceCtx uintptr

// scannableStackSizeDelta accumulates the amount of stack space held by
// live goroutines (i.e. those eligible for stack scanning).
// Flushed to gcController.scannableStackSize once scannableStackSizeSlack
// or -scannableStackSizeSlack is reached.
scannableStackSizeDelta int64

// preempt is set to indicate that this P should be enter the
// scheduler ASAP (regardless of what G is running on it).
preempt bool
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,11 @@ func copystack(gp *g, newsize uintptr) {
throw("nil stackbase")
}
used := old.hi - gp.sched.sp
// Add just the difference to gcController.addScannableStack.
// g0 stacks never move, so this will never account for them.
// It's also fine if we have no P, addScannableStack can deal with
// that case.
gcController.addScannableStack(getg().m.p.ptr(), int64(newsize)-int64(old.hi-old.lo))

// allocate new stack
new := stackalloc(uint32(newsize))
Expand Down

0 comments on commit 9ac1ee2

Please sign in to comment.