Skip to content

Commit 0906d64

Browse files
committed
runtime: eliminate gchelper mechanism
Now that we do no mark work during mark termination, we no longer need the gchelper mechanism. Updates #26903. Updates #17503. Change-Id: Ie94e5c0f918cfa047e88cae1028fece106955c1b Reviewed-on: https://go-review.googlesource.com/c/134785 Run-TryBot: Austin Clements <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Rick Hudson <[email protected]>
1 parent 550dfc8 commit 0906d64

File tree

5 files changed

+9
-157
lines changed

5 files changed

+9
-157
lines changed

src/runtime/mgc.go

+4-64
Original file line numberDiff line numberDiff line change
@@ -938,11 +938,10 @@ var work struct {
938938
markrootNext uint32 // next markroot job
939939
markrootJobs uint32 // number of markroot jobs
940940

941-
nproc uint32
942-
tstart int64
943-
nwait uint32
944-
ndone uint32
945-
alldone note
941+
nproc uint32
942+
tstart int64
943+
nwait uint32
944+
ndone uint32
946945

947946
// Number of roots of various root types. Set by gcMarkRootPrepare.
948947
nFlushCacheRoots int
@@ -1898,30 +1897,12 @@ func gcMark(start_time int64) {
18981897
}
18991898
work.tstart = start_time
19001899

1901-
work.nwait = 0
1902-
work.ndone = 0
1903-
work.nproc = uint32(gcprocs())
1904-
19051900
// Check that there's no marking work remaining.
19061901
if work.full != 0 || work.markrootNext < work.markrootJobs {
19071902
print("runtime: full=", hex(work.full), " next=", work.markrootNext, " jobs=", work.markrootJobs, " nDataRoots=", work.nDataRoots, " nBSSRoots=", work.nBSSRoots, " nSpanRoots=", work.nSpanRoots, " nStackRoots=", work.nStackRoots, "\n")
19081903
panic("non-empty mark queue after concurrent mark")
19091904
}
19101905

1911-
// Clear root marking queue.
1912-
work.markrootNext = 0
1913-
work.markrootJobs = 0
1914-
1915-
if work.nproc > 1 {
1916-
noteclear(&work.alldone)
1917-
helpgc(int32(work.nproc))
1918-
}
1919-
1920-
gchelperstart()
1921-
1922-
gcw := &getg().m.p.ptr().gcw
1923-
gcDrain(gcw, 0)
1924-
19251906
if debug.gccheckmark > 0 {
19261907
// This is expensive when there's a large number of
19271908
// Gs, so only do it if checkmark is also enabled.
@@ -1931,10 +1912,6 @@ func gcMark(start_time int64) {
19311912
throw("work.full != 0")
19321913
}
19331914

1934-
if work.nproc > 1 {
1935-
notesleep(&work.alldone)
1936-
}
1937-
19381915
// Clear out buffers and double-check that all gcWork caches
19391916
// are empty. This should be ensured by gcMarkDone before we
19401917
// enter mark termination.
@@ -2094,43 +2071,6 @@ func clearpools() {
20942071
unlock(&sched.deferlock)
20952072
}
20962073

2097-
// gchelper runs mark termination tasks on Ps other than the P
2098-
// coordinating mark termination.
2099-
//
2100-
// The caller is responsible for ensuring that this has a P to run on,
2101-
// even though it's running during STW. Because of this, it's allowed
2102-
// to have write barriers.
2103-
//
2104-
//go:yeswritebarrierrec
2105-
func gchelper() {
2106-
_g_ := getg()
2107-
_g_.m.traceback = 2
2108-
gchelperstart()
2109-
2110-
// Parallel mark over GC roots and heap
2111-
if gcphase == _GCmarktermination {
2112-
gcw := &_g_.m.p.ptr().gcw
2113-
gcDrain(gcw, 0)
2114-
}
2115-
2116-
nproc := atomic.Load(&work.nproc) // work.nproc can change right after we increment work.ndone
2117-
if atomic.Xadd(&work.ndone, +1) == nproc-1 {
2118-
notewakeup(&work.alldone)
2119-
}
2120-
_g_.m.traceback = 0
2121-
}
2122-
2123-
func gchelperstart() {
2124-
_g_ := getg()
2125-
2126-
if _g_.m.helpgc < 0 || _g_.m.helpgc >= _MaxGcproc {
2127-
throw("gchelperstart: bad m->helpgc")
2128-
}
2129-
if _g_ != _g_.m.g0 {
2130-
throw("gchelper not running on g0 stack")
2131-
}
2132-
}
2133-
21342074
// Timing
21352075

21362076
// itoaDiv formats val/(10**dec) into buf.

src/runtime/mgcmark.go

-4
Original file line numberDiff line numberDiff line change
@@ -685,10 +685,6 @@ func scanstack(gp *g, gcw *gcWork) {
685685
if gp == getg() {
686686
throw("can't scan our own stack")
687687
}
688-
mp := gp.m
689-
if mp != nil && mp.helpgc != 0 {
690-
throw("can't scan gchelper stack")
691-
}
692688

693689
// Shrink the stack if not much of it is being used.
694690
shrinkstack(gp)

src/runtime/proc.go

+3-86
Original file line numberDiff line numberDiff line change
@@ -663,59 +663,6 @@ func ready(gp *g, traceskip int, next bool) {
663663
}
664664
}
665665

666-
func gcprocs() int32 {
667-
// Figure out how many CPUs to use during GC.
668-
// Limited by gomaxprocs, number of actual CPUs, and MaxGcproc.
669-
lock(&sched.lock)
670-
n := gomaxprocs
671-
if n > ncpu {
672-
n = ncpu
673-
}
674-
if n > _MaxGcproc {
675-
n = _MaxGcproc
676-
}
677-
if n > sched.nmidle+1 { // one M is currently running
678-
n = sched.nmidle + 1
679-
}
680-
unlock(&sched.lock)
681-
return n
682-
}
683-
684-
func needaddgcproc() bool {
685-
lock(&sched.lock)
686-
n := gomaxprocs
687-
if n > ncpu {
688-
n = ncpu
689-
}
690-
if n > _MaxGcproc {
691-
n = _MaxGcproc
692-
}
693-
n -= sched.nmidle + 1 // one M is currently running
694-
unlock(&sched.lock)
695-
return n > 0
696-
}
697-
698-
func helpgc(nproc int32) {
699-
_g_ := getg()
700-
lock(&sched.lock)
701-
pos := 0
702-
for n := int32(1); n < nproc; n++ { // one M is currently running
703-
if allp[pos].mcache == _g_.m.mcache {
704-
pos++
705-
}
706-
mp := mget()
707-
if mp == nil {
708-
throw("gcprocs inconsistency")
709-
}
710-
mp.helpgc = n
711-
mp.p.set(allp[pos])
712-
mp.mcache = allp[pos].mcache
713-
pos++
714-
notewakeup(&mp.park)
715-
}
716-
unlock(&sched.lock)
717-
}
718-
719666
// freezeStopWait is a large value that freezetheworld sets
720667
// sched.stopwait to in order to request that all Gs permanently stop.
721668
const freezeStopWait = 0x7fffffff
@@ -1132,11 +1079,6 @@ func stopTheWorldWithSema() {
11321079
}
11331080
}
11341081

1135-
func mhelpgc() {
1136-
_g_ := getg()
1137-
_g_.m.helpgc = -1
1138-
}
1139-
11401082
func startTheWorldWithSema(emitTraceEvent bool) int64 {
11411083
_g_ := getg()
11421084

@@ -1145,7 +1087,6 @@ func startTheWorldWithSema(emitTraceEvent bool) int64 {
11451087
list := netpoll(false) // non-blocking
11461088
injectglist(&list)
11471089
}
1148-
add := needaddgcproc()
11491090
lock(&sched.lock)
11501091

11511092
procs := gomaxprocs
@@ -1175,7 +1116,6 @@ func startTheWorldWithSema(emitTraceEvent bool) int64 {
11751116
} else {
11761117
// Start M to run P. Do not start another M below.
11771118
newm(nil, p)
1178-
add = false
11791119
}
11801120
}
11811121

@@ -1192,16 +1132,6 @@ func startTheWorldWithSema(emitTraceEvent bool) int64 {
11921132
wakep()
11931133
}
11941134

1195-
if add {
1196-
// If GC could have used another helper proc, start one now,
1197-
// in the hope that it will be available next time.
1198-
// It would have been even better to start it before the collection,
1199-
// but doing so requires allocating memory, so it's tricky to
1200-
// coordinate. This lazy approach works out in practice:
1201-
// we don't mind if the first couple gc rounds don't have quite
1202-
// the maximum number of procs.
1203-
newm(mhelpgc, nil)
1204-
}
12051135
_g_.m.locks--
12061136
if _g_.m.locks == 0 && _g_.preempt { // restore the preemption request in case we've cleared it in newstack
12071137
_g_.stackguard0 = stackPreempt
@@ -1276,10 +1206,7 @@ func mstart1() {
12761206
fn()
12771207
}
12781208

1279-
if _g_.m.helpgc != 0 {
1280-
_g_.m.helpgc = 0
1281-
stopm()
1282-
} else if _g_.m != &m0 {
1209+
if _g_.m != &m0 {
12831210
acquirep(_g_.m.nextp.ptr())
12841211
_g_.m.nextp = 0
12851212
}
@@ -2003,21 +1930,11 @@ func stopm() {
20031930
throw("stopm spinning")
20041931
}
20051932

2006-
retry:
20071933
lock(&sched.lock)
20081934
mput(_g_.m)
20091935
unlock(&sched.lock)
20101936
notesleep(&_g_.m.park)
20111937
noteclear(&_g_.m.park)
2012-
if _g_.m.helpgc != 0 {
2013-
// helpgc() set _g_.m.p and _g_.m.mcache, so we have a P.
2014-
gchelper()
2015-
// Undo the effects of helpgc().
2016-
_g_.m.helpgc = 0
2017-
_g_.m.mcache = nil
2018-
_g_.m.p = 0
2019-
goto retry
2020-
}
20211938
acquirep(_g_.m.nextp.ptr())
20221939
_g_.m.nextp = 0
20231940
}
@@ -3857,7 +3774,7 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
38573774
pc = funcPC(_ExternalCode) + sys.PCQuantum
38583775
}
38593776
stk[0] = pc
3860-
if mp.preemptoff != "" || mp.helpgc != 0 {
3777+
if mp.preemptoff != "" {
38613778
stk[1] = funcPC(_GC) + sys.PCQuantum
38623779
} else {
38633780
stk[1] = funcPC(_System) + sys.PCQuantum
@@ -4634,7 +4551,7 @@ func schedtrace(detailed bool) {
46344551
if lockedg != nil {
46354552
id3 = lockedg.goid
46364553
}
4637-
print(" M", mp.id, ": p=", id1, " curg=", id2, " mallocing=", mp.mallocing, " throwing=", mp.throwing, " preemptoff=", mp.preemptoff, ""+" locks=", mp.locks, " dying=", mp.dying, " helpgc=", mp.helpgc, " spinning=", mp.spinning, " blocked=", mp.blocked, " lockedg=", id3, "\n")
4554+
print(" M", mp.id, ": p=", id1, " curg=", id2, " mallocing=", mp.mallocing, " throwing=", mp.throwing, " preemptoff=", mp.preemptoff, ""+" locks=", mp.locks, " dying=", mp.dying, " spinning=", mp.spinning, " blocked=", mp.blocked, " lockedg=", id3, "\n")
46384555
}
46394556

46404557
lock(&allglock)

src/runtime/runtime2.go

-1
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,6 @@ type m struct {
424424
locks int32
425425
dying int32
426426
profilehz int32
427-
helpgc int32
428427
spinning bool // m is out of work and is actively looking for work
429428
blocked bool // m is blocked on a note
430429
inwb bool // m is executing a write barrier

src/runtime/stack.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ func stackalloc(n uint32) stack {
350350
}
351351
var x gclinkptr
352352
c := thisg.m.mcache
353-
if stackNoCache != 0 || c == nil || thisg.m.preemptoff != "" || thisg.m.helpgc != 0 {
353+
if stackNoCache != 0 || c == nil || thisg.m.preemptoff != "" {
354354
// c == nil can happen in the guts of exitsyscall or
355355
// procresize. Just get a stack from the global pool.
356356
// Also don't touch stackcache during gc
@@ -445,7 +445,7 @@ func stackfree(stk stack) {
445445
}
446446
x := gclinkptr(v)
447447
c := gp.m.mcache
448-
if stackNoCache != 0 || c == nil || gp.m.preemptoff != "" || gp.m.helpgc != 0 {
448+
if stackNoCache != 0 || c == nil || gp.m.preemptoff != "" {
449449
lock(&stackpoolmu)
450450
stackpoolfree(x, order)
451451
unlock(&stackpoolmu)

0 commit comments

Comments
 (0)