Skip to content

Commit db4fd32

Browse files
committed
Switched markrootNext and markrootJobs to atomic.Uint32. Added GCDEBUG flag that makes the GC continuously run leak detection.
1 parent bb2514d commit db4fd32

File tree

3 files changed

+24
-32
lines changed

3 files changed

+24
-32
lines changed

src/runtime/mgc.go

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -364,8 +364,8 @@ type workType struct {
364364
// (and thus 8-byte alignment even on 32-bit architectures).
365365
bytesMarked uint64
366366

367-
markrootNext uint32 // next markroot job
368-
markrootJobs uint32 // number of markroot jobs
367+
markrootNext atomic.Uint32 // next markroot job
368+
markrootJobs atomic.Uint32 // number of markroot jobs
369369

370370
nproc uint32
371371
tstart int64
@@ -734,7 +734,8 @@ func gcStart(trigger gcTrigger) {
734734
} else if debug.gcstoptheworld == 2 {
735735
mode = gcForceBlockMode
736736
} else if goexperiment.GoroutineLeakFinderGC {
737-
if work.goroutineLeakFinder.pending.Load() {
737+
if work.goroutineLeakFinder.pending.Load() ||
738+
debug.gcgoroutineleaks > 0 {
738739
// Fully stop the world if running deadlock detection.
739740
mode = gcForceBlockMode
740741
}
@@ -816,7 +817,8 @@ func gcStart(trigger gcTrigger) {
816817
schedEnableUser(false)
817818
}
818819

819-
if work.goroutineLeakFinder.pending.Load() {
820+
if work.goroutineLeakFinder.pending.Load() ||
821+
debug.gcgoroutineleaks > 0 {
820822
work.goroutineLeakFinder.enabled = true
821823
work.goroutineLeakFinder.pending.Store(false)
822824
gcUntrackSyncObjects()
@@ -1170,13 +1172,11 @@ func gcDiscoverMoreStackRoots() {
11701172
}
11711173
}
11721174

1173-
var oldRootJobs int32 = int32(atomic.Load(&work.markrootJobs))
11741175
var newRootJobs int32 = int32(work.baseStacks) + int32(vIndex)
1175-
1176-
if newRootJobs > oldRootJobs {
1176+
if newRootJobs > int32(work.markrootJobs.Load()) {
11771177
// reset markrootNext as it could have been incremented past markrootJobs
11781178
work.nLiveStackRoots = vIndex
1179-
atomic.Store(&work.markrootJobs, uint32(newRootJobs))
1179+
work.markrootJobs.Store(uint32(newRootJobs))
11801180
}
11811181
}
11821182

@@ -1237,7 +1237,7 @@ func findGoleaks() bool {
12371237
work.stackRoots[work.nLiveStackRoots] = gp
12381238
work.nLiveStackRoots += 1
12391239
// We now have one more markroot job.
1240-
work.markrootJobs += 1
1240+
work.markrootJobs.Add(1)
12411241
// We might still have some work to do.
12421242
// Make sure in the next iteration we will check re-check for new runnable goroutines.
12431243
foundMoreWork = true
@@ -1261,7 +1261,7 @@ func findGoleaks() bool {
12611261
println()
12621262
}
12631263
// Put the remaining roots as ready for marking and drain them.
1264-
work.markrootJobs += uint32(work.nStackRoots - work.nLiveStackRoots)
1264+
work.markrootJobs.Add(int32(work.nStackRoots - work.nLiveStackRoots))
12651265
work.nLiveStackRoots = work.nStackRoots
12661266
return true
12671267
}
@@ -1854,9 +1854,7 @@ func gcMarkWorkAvailable(p *p) bool {
18541854
if !work.full.empty() || !work.spanq.empty() {
18551855
return true // global work available
18561856
}
1857-
rootNext := atomic.Load(&work.markrootNext)
1858-
rootJobs := atomic.Load(&work.markrootJobs)
1859-
if rootNext < rootJobs {
1857+
if work.markrootNext.Load() < work.markrootJobs.Load() {
18601858
return true // root scan work available
18611859
}
18621860
return false
@@ -1872,10 +1870,8 @@ func gcMark(startTime int64) {
18721870
work.tstart = startTime
18731871

18741872
// Check that there's no marking work remaining.
1875-
rootNext := atomic.Load(&work.markrootNext)
1876-
rootJobs := atomic.Load(&work.markrootJobs)
1877-
if work.full != 0 || rootNext < rootJobs {
1878-
print("runtime: full=", hex(work.full), " next=", rootNext, " jobs=", rootJobs, " nDataRoots=", work.nDataRoots, " nBSSRoots=", work.nBSSRoots, " nSpanRoots=", work.nSpanRoots, " nStackRoots=", work.nStackRoots, "\n")
1873+
if work.full != 0 || work.markrootNext.Load() < work.markrootJobs.Load() {
1874+
print("runtime: full=", hex(work.full), " next=", work.markrootNext.Load(), " jobs=", work.markrootJobs.Load(), " nDataRoots=", work.nDataRoots, " nBSSRoots=", work.nBSSRoots, " nSpanRoots=", work.nSpanRoots, " nStackRoots=", work.nStackRoots, "\n")
18791875
panic("non-empty mark queue after concurrent mark")
18801876
}
18811877

src/runtime/mgcmark.go

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,8 @@ func gcPrepareMarkRoots() {
162162

163163
work.nStackRoots = len(work.stackRoots)
164164

165-
work.markrootNext = 0
166-
work.markrootJobs = uint32(fixedRootCount + work.nDataRoots + work.nBSSRoots + work.nSpanRoots + work.nLiveStackRoots)
165+
work.markrootNext.Store(0)
166+
work.markrootJobs.Store(uint32(fixedRootCount + work.nDataRoots + work.nBSSRoots + work.nSpanRoots + work.nLiveStackRoots))
167167

168168
// Calculate base indexes of each root type
169169
work.baseData = uint32(fixedRootCount)
@@ -176,10 +176,8 @@ func gcPrepareMarkRoots() {
176176
// gcMarkRootCheck checks that all roots have been scanned. It is
177177
// purely for debugging.
178178
func gcMarkRootCheck() {
179-
rootNext := atomic.Load(&work.markrootNext)
180-
rootJobs := atomic.Load(&work.markrootJobs)
181-
if rootNext < rootJobs {
182-
print(rootNext, " of ", rootJobs, " markroot jobs done\n")
179+
if work.markrootNext.Load() < work.markrootJobs.Load() {
180+
print(work.markrootNext.Load(), " of ", work.markrootJobs.Load(), " markroot jobs done\n")
183181
throw("left over markroot jobs")
184182
}
185183

@@ -1197,21 +1195,19 @@ func gcDrainMarkWorkerFractional(gcw *gcWork) {
11971195

11981196
func gcUpdateMarkrootNext() (uint32, bool) {
11991197
var success bool
1200-
var next uint32 = atomic.Load(&work.markrootNext)
1201-
var jobs uint32 = atomic.Load(&work.markrootJobs)
1198+
next, jobs := work.markrootNext.Load(), work.markrootJobs.Load()
12021199

12031200
if next < jobs {
12041201
// still work available at the moment
12051202
for !success {
1206-
success = atomic.Cas(&work.markrootNext, next, next+1)
1203+
success = work.markrootNext.CompareAndSwap(next, next+1)
12071204
// We manage to snatch a root job. Return the root index.
12081205
if success {
12091206
return next, true
12101207
}
12111208

12121209
// Get the latest value of markrootNext.
1213-
next = atomic.Load(&work.markrootNext)
1214-
jobs := atomic.Load(&work.markrootJobs)
1210+
next = work.markrootNext.Load()
12151211
// We are out of markroot jobs.
12161212
if next >= jobs {
12171213
break
@@ -1279,9 +1275,7 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) {
12791275
}
12801276
}
12811277

1282-
rootNext := atomic.Load(&work.markrootNext)
1283-
rootJobs := atomic.Load(&work.markrootJobs)
1284-
if rootNext < rootJobs {
1278+
if work.markrootNext.Load() < work.markrootJobs.Load() {
12851279
// Stop if we're preemptible, if someone wants to STW, or if
12861280
// someone is calling forEachP.
12871281
for !(gp.preempt && (preemptible || sched.gcwaiting.Load() || pp.runSafePointFn != 0)) {
@@ -1432,7 +1426,7 @@ func gcDrainN(gcw *gcWork, scanWork int64) int64 {
14321426
wbBufFlush()
14331427
if b = gcw.tryGetObj(); b == 0 {
14341428
// Try to do a root job.
1435-
if atomic.Load(&work.markrootNext) < atomic.Load(&work.markrootJobs) {
1429+
if work.markrootNext.Load() < work.markrootJobs.Load() {
14361430
job, success := gcUpdateMarkrootNext()
14371431
if success {
14381432
workFlushed += markroot(gcw, job, false)

src/runtime/runtime1.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ var debug struct {
316316
dontfreezetheworld int32
317317
efence int32
318318
gccheckmark int32
319+
gcgoroutineleaks int32
319320
gcpacertrace int32
320321
gcshrinkstackoff int32
321322
gcstoptheworld int32
@@ -381,6 +382,7 @@ var dbgvars = []*dbgVar{
381382
{name: "efence", value: &debug.efence},
382383
{name: "gccheckmark", value: &debug.gccheckmark},
383384
{name: "gcpacertrace", value: &debug.gcpacertrace},
385+
{name: "gcgoroutineleaks", value: &debug.gcgoroutineleaks},
384386
{name: "gcshrinkstackoff", value: &debug.gcshrinkstackoff},
385387
{name: "gcstoptheworld", value: &debug.gcstoptheworld},
386388
{name: "gctrace", value: &debug.gctrace},

0 commit comments

Comments
 (0)