From b3d791c7bb89acc5bc77c4ba55f173a4d2c732c4 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 24 Feb 2015 22:20:38 -0500 Subject: [PATCH] runtime: consolidate gcworkdone/gcscanvalid clearing loops Previously, we had three loops in the garbage collector that all cleared the per-G GC flags. Consolidate these into one function. This one function is designed to work in a concurrent setting. As a result, it's slightly more expensive than the loops it replaces during STW phases, but these happen at most twice per GC. Change-Id: Id1ec0074fd58865eb0112b8a0547b267802d0df1 Reviewed-on: https://go-review.googlesource.com/5881 Reviewed-by: Russ Cox Reviewed-by: Rick Hudson --- src/runtime/mgc.go | 30 +++++++++++++++++++----------- src/runtime/mgcmark.go | 11 ++--------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index 88d44b2b75..e87d80618a 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -339,13 +339,9 @@ func gc(mode int) { }) } else { // For non-concurrent GC (mode != gcBackgroundMode) - // The g stacks have not been scanned so set gcscanvalid + // The g stacks have not been scanned so clear g state // such that mark termination scans all stacks. - // No races here since we are in a STW phase. - for _, gp := range allgs { - gp.gcworkdone = false // set to true in gcphasework - gp.gcscanvalid = false // stack has not been scanned - } + gcResetGState() } startTime := nanotime() @@ -384,11 +380,7 @@ func gc(mode int) { // The g stacks have been scanned so // they have gcscanvalid==true and gcworkdone==true. // Reset these so that all stacks will be rescanned. - // No races here since we are in a STW phase. - for _, gp := range allgs { - gp.gcworkdone = false // set to true in gcphasework - gp.gcscanvalid = false // stack has not been scanned - } + gcResetGState() finishsweep_m() gcMark(startTime) gcSweep(mode) @@ -606,6 +598,22 @@ func gcCopySpans() { unlock(&mheap_.lock) } +// gcResetGState resets the GC state of all G's and returns the length +// of allgs. +func gcResetGState() int { + // This may be called during a concurrent phase, so make sure + // allgs doesn't change. + lock(&allglock) + local_allglen := allglen + for i := uintptr(0); i < local_allglen; i++ { + gp := allgs[i] + gp.gcworkdone = false // set to true in gcphasework + gp.gcscanvalid = false // stack has not been scanned + } + unlock(&allglock) + return int(local_allglen) +} + // Hooks for other packages var poolcleanup func() diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index 1d6c1e8e22..50e125dc27 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -27,14 +27,7 @@ func gcscan_m() { // At the bottom we will want to return this p back to the scheduler. // Prepare flag indicating that the scan has not been completed. - lock(&allglock) - local_allglen := allglen - for i := uintptr(0); i < local_allglen; i++ { - gp := allgs[i] - gp.gcworkdone = false // set to true in gcphasework - gp.gcscanvalid = false // stack has not been scanned - } - unlock(&allglock) + local_allglen := gcResetGState() work.nwait = 0 work.ndone = 0 @@ -45,7 +38,7 @@ func gcscan_m() { lock(&allglock) // Check that gc work is done. - for i := uintptr(0); i < local_allglen; i++ { + for i := 0; i < local_allglen; i++ { gp := allgs[i] if !gp.gcworkdone { throw("scan missed a g") -- 2.48.1