Skip to content

Commit 4a5d78f

Browse files
committed
runtime: move pacer time updates and state resets into methods
Currently GC pacer updates are applied somewhat haphazardly via direct field access. To facilitate ease of testing, move these field updates into methods. Further CLs will move more of these updates into methods. For #44167. Change-Id: I25b10d2219ae27b356b5f236d44827546c86578d Reviewed-on: https://go-review.googlesource.com/c/go/+/309274 Trust: Michael Knyszek <[email protected]> Run-TryBot: Michael Knyszek <[email protected]> Reviewed-by: Michael Pratt <[email protected]>
1 parent 903f313 commit 4a5d78f

File tree

2 files changed

+51
-29
lines changed

2 files changed

+51
-29
lines changed

src/runtime/mgc.go

+11-28
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,9 @@ func gcStart(trigger gcTrigger) {
661661

662662
work.cycles++
663663

664-
gcController.startCycle()
664+
// Assists and workers can start the moment we start
665+
// the world.
666+
gcController.startCycle(now)
665667
work.heapGoal = gcController.heapGoal
666668

667669
// In STW mode, disable scheduling of user Gs. This may also
@@ -704,10 +706,6 @@ func gcStart(trigger gcTrigger) {
704706
// mutators.
705707
atomic.Store(&gcBlackenEnabled, 1)
706708

707-
// Assists and workers can start the moment we start
708-
// the world.
709-
gcController.markStartTime = now
710-
711709
// In STW mode, we could block the instant systemstack
712710
// returns, so make sure we're not preemptible.
713711
mp = acquirem()
@@ -965,8 +963,7 @@ func gcMarkTermination(nextTriggerRatio float64) {
965963
throw("gc done but gcphase != _GCoff")
966964
}
967965

968-
// Record heapGoal and heap_inuse for scavenger.
969-
gcController.lastHeapGoal = gcController.heapGoal
966+
// Record heap_inuse for scavenger.
970967
memstats.last_heap_inuse = memstats.heap_inuse
971968

972969
// Update GC trigger and pacing for the next cycle.
@@ -1291,15 +1288,9 @@ func gcBgMarkWorker() {
12911288

12921289
// Account for time.
12931290
duration := nanotime() - startTime
1294-
switch pp.gcMarkWorkerMode {
1295-
case gcMarkWorkerDedicatedMode:
1296-
atomic.Xaddint64(&gcController.dedicatedMarkTime, duration)
1297-
atomic.Xaddint64(&gcController.dedicatedMarkWorkersNeeded, 1)
1298-
case gcMarkWorkerFractionalMode:
1299-
atomic.Xaddint64(&gcController.fractionalMarkTime, duration)
1291+
gcController.logWorkTime(pp.gcMarkWorkerMode, duration)
1292+
if pp.gcMarkWorkerMode == gcMarkWorkerFractionalMode {
13001293
atomic.Xaddint64(&pp.gcFractionalMarkTime, duration)
1301-
case gcMarkWorkerIdleMode:
1302-
atomic.Xaddint64(&gcController.idleMarkTime, duration)
13031294
}
13041295

13051296
// Was this the last worker and did we run out
@@ -1419,30 +1410,22 @@ func gcMark(startTime int64) {
14191410
gcw.dispose()
14201411
}
14211412

1422-
// Update the marked heap stat.
1423-
gcController.heapMarked = work.bytesMarked
1424-
14251413
// Flush scanAlloc from each mcache since we're about to modify
14261414
// heapScan directly. If we were to flush this later, then scanAlloc
14271415
// might have incorrect information.
1416+
//
1417+
// Note that it's not important to retain this information; we know
1418+
// exactly what heapScan is at this point via scanWork.
14281419
for _, p := range allp {
14291420
c := p.mcache
14301421
if c == nil {
14311422
continue
14321423
}
1433-
gcController.heapScan += uint64(c.scanAlloc)
14341424
c.scanAlloc = 0
14351425
}
14361426

1437-
// Update other GC heap size stats. This must happen after
1438-
// cachestats (which flushes local statistics to these) and
1439-
// flushallmcaches (which modifies gcController.heapLive).
1440-
gcController.heapLive = work.bytesMarked
1441-
gcController.heapScan = uint64(gcController.scanWork)
1442-
1443-
if trace.enabled {
1444-
traceHeapAlloc()
1445-
}
1427+
// Reset controller state.
1428+
gcController.resetLive(work.bytesMarked)
14461429
}
14471430

14481431
// gcSweep must be called on the system stack because it acquires the heap

src/runtime/mgcpacer.go

+40-1
Original file line numberDiff line numberDiff line change
@@ -268,13 +268,14 @@ func (c *gcControllerState) init(gcPercent int32) {
268268
// startCycle resets the GC controller's state and computes estimates
269269
// for a new GC cycle. The caller must hold worldsema and the world
270270
// must be stopped.
271-
func (c *gcControllerState) startCycle() {
271+
func (c *gcControllerState) startCycle(markStartTime int64) {
272272
c.scanWork = 0
273273
c.bgScanCredit = 0
274274
c.assistTime = 0
275275
c.dedicatedMarkTime = 0
276276
c.fractionalMarkTime = 0
277277
c.idleMarkTime = 0
278+
c.markStartTime = markStartTime
278279

279280
// Ensure that the heap goal is at least a little larger than
280281
// the current live heap size. This may not be the case if GC
@@ -441,6 +442,10 @@ func (c *gcControllerState) revise() {
441442
// userForced indicates whether the current GC cycle was forced
442443
// by the application.
443444
func (c *gcControllerState) endCycle(userForced bool) float64 {
445+
// Record last heap goal for the scavenger.
446+
// We'll be updating the heap goal soon.
447+
gcController.lastHeapGoal = gcController.heapGoal
448+
444449
if userForced {
445450
// Forced GC means this cycle didn't start at the
446451
// trigger, so where it finished isn't good
@@ -630,6 +635,40 @@ func (c *gcControllerState) findRunnableGCWorker(_p_ *p) *g {
630635
return gp
631636
}
632637

638+
// resetLive sets up the controller state for the next mark phase after the end
639+
// of the previous one. Must be called after endCycle and before commit, before
640+
// the world is started.
641+
//
642+
// The world must be stopped.
643+
func (c *gcControllerState) resetLive(bytesMarked uint64) {
644+
c.heapMarked = bytesMarked
645+
c.heapLive = bytesMarked
646+
c.heapScan = uint64(c.scanWork)
647+
648+
// heapLive was updated, so emit a trace event.
649+
if trace.enabled {
650+
traceHeapAlloc()
651+
}
652+
}
653+
654+
// logWorkTime updates mark work accounting in the controller by a duration of
655+
// work in nanoseconds.
656+
//
657+
// Safe to execute at any time.
658+
func (c *gcControllerState) logWorkTime(mode gcMarkWorkerMode, duration int64) {
659+
switch mode {
660+
case gcMarkWorkerDedicatedMode:
661+
atomic.Xaddint64(&c.dedicatedMarkTime, duration)
662+
atomic.Xaddint64(&c.dedicatedMarkWorkersNeeded, 1)
663+
case gcMarkWorkerFractionalMode:
664+
atomic.Xaddint64(&c.fractionalMarkTime, duration)
665+
case gcMarkWorkerIdleMode:
666+
atomic.Xaddint64(&c.idleMarkTime, duration)
667+
default:
668+
throw("logWorkTime: unknown mark worker mode")
669+
}
670+
}
671+
633672
// commit sets the trigger ratio and updates everything
634673
// derived from it: the absolute trigger, the heap goal, mark pacing,
635674
// and sweep pacing.

0 commit comments

Comments
 (0)