Commit 100da609 authored by Austin Clements's avatar Austin Clements

runtime: track time spent in mutator assists

This time is tracked per P and periodically flushed to the global
controller state. This will be used to compute mutator assist
utilization in order to schedule background GC work.

Change-Id: Ib94f90903d426a02cf488bf0e2ef67a068eb3eec
Reviewed-on: https://go-review.googlesource.com/8837Reviewed-by: 's avatarRick Hudson <rlh@golang.org>
parent 4b2fde94
...@@ -203,6 +203,12 @@ type gcControllerState struct { ...@@ -203,6 +203,12 @@ type gcControllerState struct {
// it is both written and read throughout the cycle. // it is both written and read throughout the cycle.
bgScanCredit int64 bgScanCredit int64
// assistTime is the nanoseconds spent in mutator assists
// during this cycle. This is updated atomically. Updates
// occur in bounded batches, since it is both written and read
// throughout the cycle.
assistTime int64
// workRatioAvg is a moving average of the scan work ratio // workRatioAvg is a moving average of the scan work ratio
// (scan work per byte marked). // (scan work per byte marked).
workRatioAvg float64 workRatioAvg float64
...@@ -214,10 +220,11 @@ type gcControllerState struct { ...@@ -214,10 +220,11 @@ type gcControllerState struct {
} }
// startCycle resets the GC controller's state and computes estimates // startCycle resets the GC controller's state and computes estimates
// for a new GC cycle. // for a new GC cycle. The caller must hold worldsema.
func (c *gcControllerState) startCycle() { func (c *gcControllerState) startCycle() {
c.scanWork = 0 c.scanWork = 0
c.bgScanCredit = 0 c.bgScanCredit = 0
c.assistTime = 0
// If this is the first GC cycle or we're operating on a very // If this is the first GC cycle or we're operating on a very
// small heap, fake heap_marked so it looks like next_gc is // small heap, fake heap_marked so it looks like next_gc is
...@@ -247,6 +254,16 @@ func (c *gcControllerState) startCycle() { ...@@ -247,6 +254,16 @@ func (c *gcControllerState) startCycle() {
heapDistance = 1024 * 1024 heapDistance = 1024 * 1024
} }
c.assistRatio = float64(scanWorkExpected) / float64(heapDistance) c.assistRatio = float64(scanWorkExpected) / float64(heapDistance)
// Clear per-P state
for _, p := range &allp {
if p == nil {
break
}
p.gcAssistTime = 0
}
return
} }
// endCycle updates the GC controller state at the end of the // endCycle updates the GC controller state at the end of the
...@@ -269,6 +286,10 @@ func (c *gcControllerState) endCycle() { ...@@ -269,6 +286,10 @@ func (c *gcControllerState) endCycle() {
// memory contention. // memory contention.
const gcBgCreditSlack = 2000 const gcBgCreditSlack = 2000
// gcAssistTimeSlack is the nanoseconds of mutator assist time that
// can accumulate on a P before updating gcController.assistTime.
const gcAssistTimeSlack = 5000
// Determine whether to initiate a GC. // Determine whether to initiate a GC.
// If the GC is already working no need to trigger another one. // If the GC is already working no need to trigger another one.
// This should establish a feedback loop where if the GC does not // This should establish a feedback loop where if the GC does not
......
...@@ -221,6 +221,11 @@ func gcAssistAlloc(size uintptr, allowAssist bool) { ...@@ -221,6 +221,11 @@ func gcAssistAlloc(size uintptr, allowAssist bool) {
// Perform assist work // Perform assist work
systemstack(func() { systemstack(func() {
// Track time spent in this assist. Since we're on the
// system stack, this is non-preemptible, so we can
// just measure start and end time.
startTime := nanotime()
// drain own current wbuf first in the hopes that it // drain own current wbuf first in the hopes that it
// will be more cache friendly. // will be more cache friendly.
var gcw gcWork var gcw gcWork
...@@ -234,6 +239,14 @@ func gcAssistAlloc(size uintptr, allowAssist bool) { ...@@ -234,6 +239,14 @@ func gcAssistAlloc(size uintptr, allowAssist bool) {
// per-P gcWork cache (probably combined with the // per-P gcWork cache (probably combined with the
// write barrier wbuf cache). // write barrier wbuf cache).
gcw.dispose() gcw.dispose()
duration := nanotime() - startTime
_p_ := gp.m.p.ptr()
_p_.gcAssistTime += duration
if _p_.gcAssistTime > gcAssistTimeSlack {
xaddint64(&gcController.assistTime, _p_.gcAssistTime)
_p_.gcAssistTime = 0
}
}) })
} }
......
...@@ -366,6 +366,9 @@ type p struct { ...@@ -366,6 +366,9 @@ type p struct {
palloc persistentAlloc // per-P to avoid mutex palloc persistentAlloc // per-P to avoid mutex
// Per-P GC state
gcAssistTime int64 // Nanoseconds in assistAlloc
pad [64]byte pad [64]byte
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment