From feb92a8e8cadcd79e24d3caeab64149eb096363f Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Thu, 15 Oct 2015 15:44:16 -0400 Subject: [PATCH] runtime: remove work.partial queue This work queue is no longer used (there are many reads of work.partial, but the only write is in putpartial, which is never called). Fixes #11922. Change-Id: I08b76c0c02a0867a9cdcb94783e1f7629d44249a Reviewed-on: https://go-review.googlesource.com/15892 Reviewed-by: Rick Hudson --- src/runtime/mgc.go | 15 ++++------ src/runtime/mgcmark.go | 2 +- src/runtime/mgcwork.go | 66 +++++------------------------------------- 3 files changed, 13 insertions(+), 70 deletions(-) diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index f57e16cdeb..70ceb9bbb7 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -622,7 +622,7 @@ func (c *gcControllerState) findRunnableGCWorker(_p_ *p) *g { // else for a while, so kick everything out of its run // queue. } else { - if _p_.gcw.wbuf == 0 && work.full == 0 && work.partial == 0 { + if _p_.gcw.wbuf == 0 && work.full == 0 { // No work to be done right now. This can // happen at the end of the mark phase when // there are still assists tapering off. Don't @@ -795,10 +795,8 @@ func (s *bgMarkSignal) clear() { } var work struct { - full uint64 // lock-free list of full blocks workbuf - empty uint64 // lock-free list of empty blocks workbuf - // TODO(rlh): partial no longer used, remove. (issue #11922) - partial uint64 // lock-free list of partially filled blocks workbuf + full uint64 // lock-free list of full blocks workbuf + empty uint64 // lock-free list of empty blocks workbuf pad0 [_CacheLineSize]uint8 // prevents false-sharing between full/empty and nproc/nwait nproc uint32 tstart int64 @@ -1400,7 +1398,7 @@ func gcBgMarkWorker(p *p) { "work.nwait=", incnwait, "work.nproc=", work.nproc) throw("work.nwait > work.nproc") } - done = incnwait == work.nproc && work.full == 0 && work.partial == 0 + done = incnwait == work.nproc && work.full == 0 } // If this worker reached a background mark completion @@ -1436,7 +1434,7 @@ func gcMarkWorkAvailable(p *p) bool { if !p.gcw.empty() { return true } - if atomicload64(&work.full) != 0 || atomicload64(&work.partial) != 0 { + if atomicload64(&work.full) != 0 { return true // global work available } return false @@ -1497,9 +1495,6 @@ func gcMark(start_time int64) { if work.full != 0 { throw("work.full != 0") } - if work.partial != 0 { - throw("work.partial != 0") - } if work.nproc > 1 { notesleep(&work.alldone) diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index 95586dc74e..9b20f0aae5 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -300,7 +300,7 @@ retry: throw("work.nwait > work.nproc") } - if incnwait == work.nproc && work.full == 0 && work.partial == 0 { + if incnwait == work.nproc && work.full == 0 { // This has reached a background completion // point. if gcBlackenPromptly { diff --git a/src/runtime/mgcwork.go b/src/runtime/mgcwork.go index ef53087468..4d305e25df 100644 --- a/src/runtime/mgcwork.go +++ b/src/runtime/mgcwork.go @@ -80,7 +80,7 @@ func (ww *gcWork) put(obj uintptr) { wbuf := w.wbuf.ptr() if wbuf == nil { - wbuf = getpartialorempty(42) + wbuf = getempty(42) w.wbuf = wbufptrOf(wbuf) } @@ -204,7 +204,7 @@ func (w *gcWork) empty() bool { type workbufhdr struct { node lfnode // must be first nobj int - inuse bool // This workbuf is in use by some gorotuine and is not on the work.empty/partial/full queues. + inuse bool // This workbuf is in use by some gorotuine and is not on the work.empty/full queues. log [4]int // line numbers forming a history of ownership changes to workbuf } @@ -217,7 +217,7 @@ type workbuf struct { // workbuf factory routines. These funcs are used to manage the // workbufs. // If the GC asks for some work these are the only routines that -// make partially full wbufs available to the GC. +// make wbufs available to the GC. // Each of the gets and puts also take an distinct integer that is used // to record a brief history of changes to ownership of the workbuf. // The convention is to use a unique line number but any encoding @@ -314,54 +314,11 @@ func putfull(b *workbuf, entry int) { lfstackpush(&work.full, &b.node) } -// getpartialorempty tries to return a partially empty -// and if none are available returns an empty one. -// entry is used to provide a brief history of ownership -// using entry + xxx00000 to -// indicating that two line numbers in the call chain. -//go:nowritebarrier -func getpartialorempty(entry int) *workbuf { - b := (*workbuf)(lfstackpop(&work.partial)) - if b != nil { - b.logget(entry) - return b - } - // Let getempty do the logget check but - // use the entry to encode that it passed - // through this routine. - b = getempty(entry + 80700000) - return b -} - -// putpartial puts empty buffers on the work.empty queue, -// full buffers on the work.full queue and -// others on the work.partial queue. -// entry is used to provide a brief history of ownership -// using entry + xxx00000 to -// indicating that two call chain line numbers. -//go:nowritebarrier -func putpartial(b *workbuf, entry int) { - if b.nobj == 0 { - putempty(b, entry+81500000) - } else if b.nobj < len(b.obj) { - b.logput(entry) - lfstackpush(&work.partial, &b.node) - } else if b.nobj == len(b.obj) { - b.logput(entry) - lfstackpush(&work.full, &b.node) - } else { - throw("putpartial: bad Workbuf b.nobj") - } -} - // trygetfull tries to get a full or partially empty workbuffer. // If one is not immediately available return nil //go:nowritebarrier func trygetfull(entry int) *workbuf { b := (*workbuf)(lfstackpop(&work.full)) - if b == nil { - b = (*workbuf)(lfstackpop(&work.partial)) - } if b != nil { b.logget(entry) b.checknonempty() @@ -370,10 +327,9 @@ func trygetfull(entry int) *workbuf { return b } -// Get a full work buffer off the work.full or a partially -// filled one off the work.partial list. If nothing is available -// wait until all the other gc helpers have finished and then -// return nil. +// Get a full work buffer off the work.full list. +// If nothing is available wait until all the other gc helpers have +// finished and then return nil. // getfull acts as a barrier for work.nproc helpers. As long as one // gchelper is actively marking objects it // may create a workbuffer that the other helpers can work on. @@ -390,11 +346,6 @@ func getfull(entry int) *workbuf { b.checknonempty() return b } - b = (*workbuf)(lfstackpop(&work.partial)) - if b != nil { - b.logget(entry) - return b - } incnwait := xadd(&work.nwait, +1) if incnwait > work.nproc { @@ -402,16 +353,13 @@ func getfull(entry int) *workbuf { throw("work.nwait > work.nproc") } for i := 0; ; i++ { - if work.full != 0 || work.partial != 0 { + if work.full != 0 { decnwait := xadd(&work.nwait, -1) if decnwait == work.nproc { println("runtime: work.nwait=", decnwait, "work.nproc=", work.nproc) throw("work.nwait > work.nproc") } b = (*workbuf)(lfstackpop(&work.full)) - if b == nil { - b = (*workbuf)(lfstackpop(&work.partial)) - } if b != nil { b.logget(entry) b.checknonempty()