Skip to content

Commit 0e6a6c5

Browse files
committed
runtime: simplify process for starting GC goroutine
Currently, when allocation reaches the GC trigger, the runtime uses readyExecute to start the GC goroutine immediately rather than wait for the scheduler to get around to the GC goroutine while the mutator continues to grow the heap. Now that the scheduler runs the most recently readied goroutine when a goroutine yields its time slice, this rigmarole is no longer necessary. The runtime can simply ready the GC goroutine and yield from the readying goroutine. Change-Id: I3b4ebadd2a72a923b1389f7598f82973dd5c8710 Reviewed-on: https://go-review.googlesource.com/9292 Reviewed-by: Rick Hudson <[email protected]> Reviewed-by: Russ Cox <[email protected]> Run-TryBot: Austin Clements <[email protected]>
1 parent ce502b0 commit 0e6a6c5

File tree

2 files changed

+9
-52
lines changed

2 files changed

+9
-52
lines changed

src/runtime/mgc.go

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -655,28 +655,24 @@ func startGC(mode int) {
655655
}
656656

657657
// trigger concurrent GC
658+
readied := false
658659
lock(&bggc.lock)
659660
if !bggc.started {
660661
bggc.working = 1
661662
bggc.started = true
662-
// This puts the G on the end of the current run
663-
// queue, so it may take a while to actually start.
664-
// This is only a problem for the first GC cycle.
663+
readied = true
665664
go backgroundgc()
666665
} else if bggc.working == 0 {
667666
bggc.working = 1
668-
if getg().m.lockedg != nil {
669-
// We can't directly switch to GC on a locked
670-
// M, so put it on the run queue and someone
671-
// will get to it.
672-
ready(bggc.g, 0)
673-
} else {
674-
unlock(&bggc.lock)
675-
readyExecute(bggc.g, 0)
676-
return
677-
}
667+
readied = true
668+
ready(bggc.g, 0)
678669
}
679670
unlock(&bggc.lock)
671+
if readied {
672+
// This G just started or ready()d the GC goroutine.
673+
// Switch directly to it by yielding.
674+
Gosched()
675+
}
680676
}
681677

682678
// State of the background concurrent GC goroutine.

src/runtime/proc1.go

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -155,45 +155,6 @@ func ready(gp *g, traceskip int) {
155155
}
156156
}
157157

158-
// readyExecute marks gp ready to run, preempt the current g, and execute gp.
159-
// This is used to start concurrent GC promptly when we reach its trigger.
160-
func readyExecute(gp *g, traceskip int) {
161-
// Squirrel away gp so we don't allocate a closure for the
162-
// mcall'd func below. If we allocate a closure, it could go
163-
// away as soon as we put _g_ on the runqueue.
164-
getg().readyg = gp
165-
166-
mcall(func(_g_ *g) {
167-
gp := _g_.readyg
168-
_g_.readyg = nil
169-
170-
if trace.enabled {
171-
traceGoUnpark(gp, traceskip)
172-
traceGoSched()
173-
}
174-
175-
if _g_.m.locks != 0 {
176-
throw("readyExecute: holding locks")
177-
}
178-
if _g_.m.lockedg != nil {
179-
throw("cannot readyExecute from a locked g")
180-
}
181-
if readgstatus(gp)&^_Gscan != _Gwaiting {
182-
dumpgstatus(gp)
183-
throw("bad gp.status in readyExecute")
184-
}
185-
186-
// Preempt the current g
187-
casgstatus(_g_, _Grunning, _Grunnable)
188-
runqput(_g_.m.p.ptr(), _g_, false)
189-
dropg()
190-
191-
// Ready gp and switch to it
192-
casgstatus(gp, _Gwaiting, _Grunnable)
193-
execute(gp, false)
194-
})
195-
}
196-
197158
func gcprocs() int32 {
198159
// Figure out how many CPUs to use during GC.
199160
// Limited by gomaxprocs, number of actual CPUs, and MaxGcproc.

0 commit comments

Comments
 (0)