Skip to content

Commit e900e27

Browse files
committed
runtime: clean up loops over allp
allp now has length gomaxprocs, which means none of allp[i] are nil or in state _Pdead. This lets replace several different styles of loops over allp with normal range loops. for i := 0; i < gomaxprocs; i++ { ... } loops can simply range over allp. Likewise, range loops over allp[:gomaxprocs] can just range over allp. Loops that check for p == nil || p.state == _Pdead don't need to check this any more. Loops that check for p == nil don't have to check this *if* dead Ps don't affect them. I checked that all such loops are, in fact, unaffected by dead Ps. One loop was potentially affected, which this fixes by zeroing p.gcAssistTime in procresize. Updates #15131. Change-Id: Ifa1c2a86ed59892eca0610360a75bb613bc6dcee Reviewed-on: https://go-review.googlesource.com/45575 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rick Hudson <rlh@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
1 parent ee55000 commit e900e27

File tree

5 files changed

+19
-47
lines changed

5 files changed

+19
-47
lines changed

src/runtime/mgc.go

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -466,9 +466,6 @@ func (c *gcControllerState) startCycle() {
466466

467467
// Clear per-P state
468468
for _, p := range allp {
469-
if p == nil {
470-
break
471-
}
472469
p.gcAssistTime = 0
473470
}
474471

@@ -1663,9 +1660,6 @@ func gcBgMarkStartWorkers() {
16631660
// Background marking is performed by per-P G's. Ensure that
16641661
// each P has a background GC G.
16651662
for _, p := range allp {
1666-
if p == nil || p.status == _Pdead {
1667-
break
1668-
}
16691663
if p.gcBgMarkWorker == 0 {
16701664
go gcBgMarkWorker(p)
16711665
notetsleepg(&work.bgMarkReady, -1)
@@ -1962,8 +1956,8 @@ func gcMark(start_time int64) {
19621956

19631957
// Double-check that all gcWork caches are empty. This should
19641958
// be ensured by mark 2 before we enter mark termination.
1965-
for i := 0; i < int(gomaxprocs); i++ {
1966-
gcw := &allp[i].gcw
1959+
for _, p := range allp {
1960+
gcw := &p.gcw
19671961
if !gcw.empty() {
19681962
throw("P has cached GC work at end of mark termination")
19691963
}

src/runtime/mgcmark.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1357,9 +1357,6 @@ func gcmarknewobject(obj, size, scanSize uintptr) {
13571357
// The world must be stopped.
13581358
func gcMarkTinyAllocs() {
13591359
for _, p := range allp {
1360-
if p == nil || p.status == _Pdead {
1361-
break
1362-
}
13631360
c := p.mcache
13641361
if c == nil || c.tiny == 0 {
13651362
continue

src/runtime/mstats.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -596,9 +596,6 @@ func updatememstats() {
596596
//go:nowritebarrier
597597
func cachestats() {
598598
for _, p := range allp {
599-
if p == nil {
600-
break
601-
}
602599
c := p.mcache
603600
if c == nil {
604601
continue
@@ -614,9 +611,6 @@ func cachestats() {
614611
//go:nowritebarrier
615612
func flushmcache(i int) {
616613
p := allp[i]
617-
if p == nil {
618-
return
619-
}
620614
c := p.mcache
621615
if c == nil {
622616
return

src/runtime/proc.go

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -997,8 +997,7 @@ func stopTheWorldWithSema() {
997997
_g_.m.p.ptr().status = _Pgcstop // Pgcstop is only diagnostic.
998998
sched.stopwait--
999999
// try to retake all P's in Psyscall status
1000-
for i := 0; i < int(gomaxprocs); i++ {
1001-
p := allp[i]
1000+
for _, p := range allp {
10021001
s := p.status
10031002
if s == _Psyscall && atomic.Cas(&p.status, s, _Pgcstop) {
10041003
if trace.enabled {
@@ -1038,8 +1037,7 @@ func stopTheWorldWithSema() {
10381037
if sched.stopwait != 0 {
10391038
bad = "stopTheWorld: not stopped (stopwait != 0)"
10401039
} else {
1041-
for i := 0; i < int(gomaxprocs); i++ {
1042-
p := allp[i]
1040+
for _, p := range allp {
10431041
if p.status != _Pgcstop {
10441042
bad = "stopTheWorld: not stopped (status != _Pgcstop)"
10451043
}
@@ -1219,7 +1217,7 @@ func forEachP(fn func(*p)) {
12191217
sched.safePointFn = fn
12201218

12211219
// Ask all Ps to run the safe point function.
1222-
for _, p := range allp[:gomaxprocs] {
1220+
for _, p := range allp {
12231221
if p != _p_ {
12241222
atomic.Store(&p.runSafePointFn, 1)
12251223
}
@@ -1247,8 +1245,7 @@ func forEachP(fn func(*p)) {
12471245

12481246
// Force Ps currently in _Psyscall into _Pidle and hand them
12491247
// off to induce safe point function execution.
1250-
for i := 0; i < int(gomaxprocs); i++ {
1251-
p := allp[i]
1248+
for _, p := range allp {
12521249
s := p.status
12531250
if s == _Psyscall && p.runSafePointFn == 1 && atomic.Cas(&p.status, s, _Pidle) {
12541251
if trace.enabled {
@@ -1277,8 +1274,7 @@ func forEachP(fn func(*p)) {
12771274
if sched.safePointWait != 0 {
12781275
throw("forEachP: not done")
12791276
}
1280-
for i := 0; i < int(gomaxprocs); i++ {
1281-
p := allp[i]
1277+
for _, p := range allp {
12821278
if p.runSafePointFn != 0 {
12831279
throw("forEachP: P did not run fn")
12841280
}
@@ -2072,9 +2068,8 @@ stop:
20722068
}
20732069

20742070
// check all runqueues once again
2075-
for i := 0; i < int(gomaxprocs); i++ {
2076-
_p_ := allp[i]
2077-
if _p_ != nil && !runqempty(_p_) {
2071+
for _, _p_ := range allp {
2072+
if !runqempty(_p_) {
20782073
lock(&sched.lock)
20792074
_p_ = pidleget()
20802075
unlock(&sched.lock)
@@ -3229,9 +3224,6 @@ func badunlockosthread() {
32293224
func gcount() int32 {
32303225
n := int32(allglen) - sched.ngfree - int32(atomic.Load(&sched.ngsys))
32313226
for _, _p_ := range allp {
3232-
if _p_ == nil {
3233-
break
3234-
}
32353227
n -= _p_.gfreecnt
32363228
}
32373229

@@ -3641,6 +3633,7 @@ func procresize(nprocs int32) *p {
36413633
raceprocdestroy(p.racectx)
36423634
p.racectx = 0
36433635
}
3636+
p.gcAssistTime = 0
36443637
p.status = _Pdead
36453638
// can't free P itself because it can be referenced by an M in syscall
36463639
}
@@ -3980,9 +3973,14 @@ func retake(now int64) uint32 {
39803973
// Prevent allp slice changes. This lock will be completely
39813974
// uncontended unless we're already stopping the world.
39823975
lock(&allpLock)
3976+
// We can't use a range loop over allp because we may
3977+
// temporarily drop the allpLock. Hence, we need to re-fetch
3978+
// allp each time around the loop.
39833979
for i := 0; i < len(allp); i++ {
39843980
_p_ := allp[i]
39853981
if _p_ == nil {
3982+
// This can happen if procresize has grown
3983+
// allp but not yet created new Ps.
39863984
continue
39873985
}
39883986
pd := &_p_.sysmontick
@@ -4044,9 +4042,8 @@ func retake(now int64) uint32 {
40444042
// Returns true if preemption request was issued to at least one goroutine.
40454043
func preemptall() bool {
40464044
res := false
4047-
for i := int32(0); i < gomaxprocs; i++ {
4048-
_p_ := allp[i]
4049-
if _p_ == nil || _p_.status != _Prunning {
4045+
for _, _p_ := range allp {
4046+
if _p_.status != _Prunning {
40504047
continue
40514048
}
40524049
if preemptone(_p_) {
@@ -4102,11 +4099,7 @@ func schedtrace(detailed bool) {
41024099
// We must be careful while reading data from P's, M's and G's.
41034100
// Even if we hold schedlock, most data can be changed concurrently.
41044101
// E.g. (p->m ? p->m->id : -1) can crash if p->m changes from non-nil to nil.
4105-
for i := int32(0); i < gomaxprocs; i++ {
4106-
_p_ := allp[i]
4107-
if _p_ == nil {
4108-
continue
4109-
}
4102+
for i, _p_ := range allp {
41104103
mp := _p_.m.ptr()
41114104
h := atomic.Load(&_p_.runqhead)
41124105
t := atomic.Load(&_p_.runqtail)
@@ -4124,7 +4117,7 @@ func schedtrace(detailed bool) {
41244117
print("[")
41254118
}
41264119
print(t - h)
4127-
if i == gomaxprocs-1 {
4120+
if i == len(allp)-1 {
41284121
print("]\n")
41294122
}
41304123
}

src/runtime/trace.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -280,9 +280,6 @@ func StopTrace() {
280280
// Loop over all allocated Ps because dead Ps may still have
281281
// trace buffers.
282282
for _, p := range allp[:cap(allp)] {
283-
if p == nil {
284-
break
285-
}
286283
buf := p.tracebuf
287284
if buf != 0 {
288285
traceFullQueue(buf)
@@ -323,9 +320,6 @@ func StopTrace() {
323320
// The lock protects us from races with StartTrace/StopTrace because they do stop-the-world.
324321
lock(&trace.lock)
325322
for _, p := range allp[:cap(allp)] {
326-
if p == nil {
327-
break
328-
}
329323
if p.tracebuf != 0 {
330324
throw("trace: non-empty trace buffer in proc")
331325
}

0 commit comments

Comments
 (0)