1
0
mirror of https://github.com/golang/go synced 2024-11-23 10:20:03 -07:00

runtime: convert gcController.dedicatedMarkWorkersNeeded to atomic type

In gcController.startCycle we just compute the initial value in a
local variable before assigning to the atomic field to avoid noisy
churn.

For #53821.

Change-Id: Ibde0ac8fd49aa6bbee3bd02fe3ffb17429abd5a9
Reviewed-on: https://go-review.googlesource.com/c/go/+/417784
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Austin Clements <austin@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Michael Pratt 2022-07-14 17:15:44 -04:00
parent dcd10375bc
commit e76155614a
2 changed files with 20 additions and 25 deletions

View File

@ -21,7 +21,6 @@ var AtomicFields = []uintptr{
unsafe.Offsetof(schedt{}.lastpoll),
unsafe.Offsetof(schedt{}.pollUntil),
unsafe.Offsetof(schedt{}.timeToRun),
unsafe.Offsetof(gcControllerState{}.dedicatedMarkWorkersNeeded),
unsafe.Offsetof(timeHistogram{}.underflow),
unsafe.Offsetof(profBuf{}.overflow),
unsafe.Offsetof(profBuf{}.overflowTime),

View File

@ -92,8 +92,6 @@ type gcControllerState struct {
// Initialized from GOGC. GOGC=off means no GC.
gcPercent atomic.Int32
_ uint32 // padding so following 64-bit values are 8-byte aligned
// memoryLimit is the soft memory limit in bytes.
//
// Initialized from GOMEMLIMIT. GOMEMLIMIT=off is equivalent to MaxInt64
@ -145,8 +143,6 @@ type gcControllerState struct {
// consMark; see consMark for details.
consMarkController piController
_ uint32 // Padding for atomics on 32-bit platforms.
// gcPercentHeapGoal is the goal heapLive for when next GC ends derived
// from gcPercent.
//
@ -289,11 +285,10 @@ type gcControllerState struct {
// that assists and background mark workers started.
markStartTime int64
// dedicatedMarkWorkersNeeded is the number of dedicated mark
// workers that need to be started. This is computed at the
// beginning of each cycle and decremented atomically as
// dedicated mark workers get started.
dedicatedMarkWorkersNeeded int64
// dedicatedMarkWorkersNeeded is the number of dedicated mark workers
// that need to be started. This is computed at the beginning of each
// cycle and decremented as dedicated mark workers get started.
dedicatedMarkWorkersNeeded atomic.Int64
// idleMarkWorkers is two packed int32 values in a single uint64.
// These two values are always updated simultaneously.
@ -448,26 +443,26 @@ func (c *gcControllerState) startCycle(markStartTime int64, procs int, trigger g
// 25%. For small GOMAXPROCS, this would introduce too much
// error, so we add fractional workers in that case.
totalUtilizationGoal := float64(procs) * gcBackgroundUtilization
c.dedicatedMarkWorkersNeeded = int64(totalUtilizationGoal + 0.5)
utilError := float64(c.dedicatedMarkWorkersNeeded)/totalUtilizationGoal - 1
dedicatedMarkWorkersNeeded := int64(totalUtilizationGoal + 0.5)
utilError := float64(dedicatedMarkWorkersNeeded)/totalUtilizationGoal - 1
const maxUtilError = 0.3
if utilError < -maxUtilError || utilError > maxUtilError {
// Rounding put us more than 30% off our goal. With
// gcBackgroundUtilization of 25%, this happens for
// GOMAXPROCS<=3 or GOMAXPROCS=6. Enable fractional
// workers to compensate.
if float64(c.dedicatedMarkWorkersNeeded) > totalUtilizationGoal {
if float64(dedicatedMarkWorkersNeeded) > totalUtilizationGoal {
// Too many dedicated workers.
c.dedicatedMarkWorkersNeeded--
dedicatedMarkWorkersNeeded--
}
c.fractionalUtilizationGoal = (totalUtilizationGoal - float64(c.dedicatedMarkWorkersNeeded)) / float64(procs)
c.fractionalUtilizationGoal = (totalUtilizationGoal - float64(dedicatedMarkWorkersNeeded)) / float64(procs)
} else {
c.fractionalUtilizationGoal = 0
}
// In STW mode, we just want dedicated workers.
if debug.gcstoptheworld > 0 {
c.dedicatedMarkWorkersNeeded = int64(procs)
dedicatedMarkWorkersNeeded = int64(procs)
c.fractionalUtilizationGoal = 0
}
@ -482,7 +477,7 @@ func (c *gcControllerState) startCycle(markStartTime int64, procs int, trigger g
// required. However, we need at least one dedicated mark worker or
// idle GC worker to ensure GC progress in some scenarios (see comment
// on maxIdleMarkWorkers).
if c.dedicatedMarkWorkersNeeded > 0 {
if dedicatedMarkWorkersNeeded > 0 {
c.setMaxIdleMarkWorkers(0)
} else {
// TODO(mknyszek): The fundamental reason why we need this is because
@ -492,13 +487,14 @@ func (c *gcControllerState) startCycle(markStartTime int64, procs int, trigger g
c.setMaxIdleMarkWorkers(1)
}
} else {
// N.B. gomaxprocs and dedicatedMarkWorkersNeeded is guaranteed not to
// N.B. gomaxprocs and dedicatedMarkWorkersNeeded are guaranteed not to
// change during a GC cycle.
c.setMaxIdleMarkWorkers(int32(procs) - int32(c.dedicatedMarkWorkersNeeded))
c.setMaxIdleMarkWorkers(int32(procs) - int32(dedicatedMarkWorkersNeeded))
}
// Compute initial values for controls that are updated
// throughout the cycle.
c.dedicatedMarkWorkersNeeded.Store(dedicatedMarkWorkersNeeded)
c.revise()
if debug.gcpacertrace > 0 {
@ -507,7 +503,7 @@ func (c *gcControllerState) startCycle(markStartTime int64, procs int, trigger g
" (scan ", gcController.heapScan.Load()>>20, " MB in ",
work.initialHeapLive>>20, "->",
heapGoal>>20, " MB)",
" workers=", c.dedicatedMarkWorkersNeeded,
" workers=", dedicatedMarkWorkersNeeded,
"+", c.fractionalUtilizationGoal, "\n")
}
}
@ -761,7 +757,7 @@ func (c *gcControllerState) enlistWorker() {
// There are no idle Ps. If we need more dedicated workers,
// try to preempt a running P so it will switch to a worker.
if c.dedicatedMarkWorkersNeeded <= 0 {
if c.dedicatedMarkWorkersNeeded.Load() <= 0 {
return
}
// Pick a random other P to preempt.
@ -831,14 +827,14 @@ func (c *gcControllerState) findRunnableGCWorker(pp *p, now int64) (*g, int64) {
return nil, now
}
decIfPositive := func(ptr *int64) bool {
decIfPositive := func(val *atomic.Int64) bool {
for {
v := atomic.Loadint64(ptr)
v := val.Load()
if v <= 0 {
return false
}
if atomic.Casint64(ptr, v, v-1) {
if val.CompareAndSwap(v, v-1) {
return true
}
}
@ -905,7 +901,7 @@ func (c *gcControllerState) markWorkerStop(mode gcMarkWorkerMode, duration int64
switch mode {
case gcMarkWorkerDedicatedMode:
c.dedicatedMarkTime.Add(duration)
atomic.Xaddint64(&c.dedicatedMarkWorkersNeeded, 1)
c.dedicatedMarkWorkersNeeded.Add(1)
case gcMarkWorkerFractionalMode:
c.fractionalMarkTime.Add(duration)
case gcMarkWorkerIdleMode: