mirror of
https://github.com/golang/go
synced 2024-11-18 06:14:46 -07:00
runtime: decentralize sweep termination and mark transition
This moves all of GC initialization, sweep termination, and the transition to concurrent marking in to the off->mark transition function. This means it's now handled on the goroutine that detected the state exit condition. As a result, malloc no longer needs to Gosched() at the beginning of the GC cycle to prevent over-allocation while the GC is starting up because it will now *help* the GC to start up. The Gosched hack is still necessary during GC shutdown (this is easy to test by enabling gctrace and hitting Ctrl-S to block the gctrace output). At this point, the GC coordinator still handles later phases. This requires a small tweak to how we start the GC coordinator. Currently, starting the GC coordinator is best-effort and may fail if the coordinator is about to park from the previous cycle but hasn't yet. We fix this by replacing the park/ready to wake up the coordinator with a semaphore. This is temporary since the coordinator will be going away in a few commits. Updates #11970. Change-Id: I2c6a11c91e72dfbc59c2d8e7c66146dee9a444fe Reviewed-on: https://go-review.googlesource.com/16357 Reviewed-by: Rick Hudson <rlh@golang.org> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
9630c47e8c
commit
a51905fa04
@ -737,7 +737,7 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
|
||||
if shouldhelpgc && gcShouldStart(false) {
|
||||
gcStart(gcBackgroundMode, false)
|
||||
} else if shouldhelpgc && bggc.working != 0 && gcBlackenEnabled == 0 {
|
||||
// The GC is starting up or shutting down, so we can't
|
||||
// The GC shutting down, so we can't
|
||||
// assist, but we also can't allocate unabated. Slow
|
||||
// down this G's allocation and help the GC stay
|
||||
// scheduled by yielding.
|
||||
|
@ -915,31 +915,23 @@ const (
|
||||
)
|
||||
|
||||
// startGCCoordinator starts and readies the GC coordinator goroutine.
|
||||
// If mode is gcBackgroundMode, this will
|
||||
// start GC in the background and return. Otherwise, this will block
|
||||
// until the new GC cycle is started and finishes.
|
||||
//
|
||||
// TODO(austin): This function is temporary and will go away when we
|
||||
// finish the transition to the decentralized state machine.
|
||||
func startGCCoordinator(mode gcMode) {
|
||||
if mode != gcBackgroundMode {
|
||||
// special synchronous cases
|
||||
gc(mode)
|
||||
return
|
||||
}
|
||||
|
||||
func startGCCoordinator() {
|
||||
// trigger concurrent GC
|
||||
readied := false
|
||||
lock(&bggc.lock)
|
||||
if !bggc.started {
|
||||
bggc.working = 1
|
||||
bggc.started = true
|
||||
bggc.wakeSema = 1
|
||||
readied = true
|
||||
go backgroundgc()
|
||||
} else if bggc.working == 0 {
|
||||
bggc.working = 1
|
||||
} else {
|
||||
bggc.working++
|
||||
readied = true
|
||||
ready(bggc.g, 0)
|
||||
semrelease(&bggc.wakeSema)
|
||||
}
|
||||
unlock(&bggc.lock)
|
||||
if readied {
|
||||
@ -952,20 +944,21 @@ func startGCCoordinator(mode gcMode) {
|
||||
// State of the background concurrent GC goroutine.
|
||||
var bggc struct {
|
||||
lock mutex
|
||||
g *g
|
||||
working uint
|
||||
started bool
|
||||
|
||||
wakeSema uint32
|
||||
}
|
||||
|
||||
// backgroundgc is running in a goroutine and does the concurrent GC work.
|
||||
// bggc holds the state of the backgroundgc.
|
||||
func backgroundgc() {
|
||||
bggc.g = getg()
|
||||
for {
|
||||
gc(gcBackgroundMode)
|
||||
lock(&bggc.lock)
|
||||
bggc.working = 0
|
||||
goparkunlock(&bggc.lock, "Concurrent GC wait", traceEvGoBlock, 1)
|
||||
bggc.working--
|
||||
unlock(&bggc.lock)
|
||||
semacquire(&bggc.wakeSema, false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1042,16 +1035,6 @@ func gcStart(mode gcMode, forceTrigger bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Move sweep termination and initialization from the
|
||||
// coordinator to here.
|
||||
startGCCoordinator(mode)
|
||||
|
||||
if useStartSema {
|
||||
semrelease(&work.startSema)
|
||||
}
|
||||
}
|
||||
|
||||
func gc(mode gcMode) {
|
||||
// Ok, we're doing it! Stop everybody else
|
||||
semacquire(&worldsema, false)
|
||||
|
||||
@ -1135,10 +1118,33 @@ func gc(mode gcMode) {
|
||||
gcController.assistStartTime = now
|
||||
work.tMark = now
|
||||
|
||||
// Enable background mark workers and wait for
|
||||
// background mark completion.
|
||||
// Enable background mark workers.
|
||||
gcController.bgMarkStartTime = now
|
||||
work.bgMark1.clear()
|
||||
|
||||
// TODO: Make mark 1 completion handle the transition.
|
||||
startGCCoordinator()
|
||||
} else {
|
||||
t := nanotime()
|
||||
work.tMark, work.tMarkTerm = t, t
|
||||
work.heapGoal = work.heap0
|
||||
|
||||
// Perform mark termination. This will restart the world.
|
||||
gc(mode)
|
||||
}
|
||||
|
||||
if useStartSema {
|
||||
semrelease(&work.startSema)
|
||||
}
|
||||
}
|
||||
|
||||
func gc(mode gcMode) {
|
||||
// If mode == gcBackgroundMode, world is not stopped.
|
||||
// If mode != gcBackgroundMode, world is stopped.
|
||||
// TODO(austin): This is temporary.
|
||||
|
||||
if mode == gcBackgroundMode {
|
||||
// Wait for background mark completion.
|
||||
work.bgMark1.wait()
|
||||
|
||||
gcMarkRootCheck()
|
||||
@ -1170,7 +1176,7 @@ func gc(mode gcMode) {
|
||||
work.bgMark2.wait()
|
||||
|
||||
// Begin mark termination.
|
||||
now = nanotime()
|
||||
now := nanotime()
|
||||
work.tMarkTerm = now
|
||||
work.pauseStart = now
|
||||
systemstack(stopTheWorldWithSema)
|
||||
@ -1192,10 +1198,6 @@ func gc(mode gcMode) {
|
||||
gcWakeAllAssists()
|
||||
|
||||
gcController.endCycle()
|
||||
} else {
|
||||
t := nanotime()
|
||||
work.tMark, work.tMarkTerm = t, t
|
||||
work.heapGoal = work.heap0
|
||||
}
|
||||
|
||||
// World is stopped.
|
||||
|
@ -773,7 +773,7 @@ func traceProcStop(pp *p) {
|
||||
}
|
||||
|
||||
func traceGCStart() {
|
||||
traceEvent(traceEvGCStart, 5)
|
||||
traceEvent(traceEvGCStart, 3)
|
||||
}
|
||||
|
||||
func traceGCDone() {
|
||||
|
Loading…
Reference in New Issue
Block a user