aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/mgc.go
diff options
context:
space:
mode:
authorMichael Anthony Knyszek <mknyszek@google.com>2019-06-17 19:03:09 +0000
committerMichael Knyszek <mknyszek@google.com>2020-03-18 19:13:50 +0000
commitf1f947af28d1de655fe7eb845a053753d10845aa (patch)
treeda21cfdda764c275ea54da54e09a8953952ab641 /src/runtime/mgc.go
parente39de05186af24cec8a5f98258086e9899153e29 (diff)
downloadgo-f1f947af28d1de655fe7eb845a053753d10845aa.tar.gz
go-f1f947af28d1de655fe7eb845a053753d10845aa.zip
runtime: don't hold worldsema across mark phase
This change makes it so that worldsema isn't held across the mark phase. This means that various operations like ReadMemStats may now stop the world during the mark phase, reducing latency on such operations. Only three such operations are still no longer allowed to occur during marking: GOMAXPROCS, StartTrace, and StopTrace. For the former it's because any change to GOMAXPROCS impacts GC mark background worker scheduling and the details there are tricky. For the latter two it's because tracing needs to observe consistent GC start and GC end events, and if StartTrace or StopTrace may stop the world during marking, then it's possible for it to see a GC end event without a start or GC start event without an end, respectively. To ensure that GOMAXPROCS and StartTrace/StopTrace cannot proceed until marking is complete, the runtime now holds a new semaphore, gcsema, across the mark phase just like it used to with worldsema. This change is being landed once more after being reverted in the Go 1.14 release cycle, since CL 215157 allows it to have a positive effect on system performance. For the benchmark BenchmarkReadMemStatsLatency in the runtime, which measures ReadMemStats latencies while the GC is exercised, the tail of these latencies reduced dramatically on an 8-core machine: name old 50%tile-ns new 50%tile-ns delta ReadMemStatsLatency-8 4.40M ±74% 0.12M ± 2% -97.35% (p=0.008 n=5+5) name old 90%tile-ns new 90%tile-ns delta ReadMemStatsLatency-8 102M ± 6% 0M ±14% -99.79% (p=0.008 n=5+5) name old 99%tile-ns new 99%tile-ns delta ReadMemStatsLatency-8 147M ±18% 4M ±57% -97.43% (p=0.008 n=5+5) Fixes #19812. Change-Id: If66c3c97d171524ae29f0e7af4bd33509d9fd0bb Reviewed-on: https://go-review.googlesource.com/c/go/+/216557 Run-TryBot: Michael Knyszek <mknyszek@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
Diffstat (limited to 'src/runtime/mgc.go')
-rw-r--r--src/runtime/mgc.go15
1 files changed, 15 insertions, 0 deletions
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
index 604d7d09b4..bda8eadc9d 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -1269,6 +1269,7 @@ func gcStart(trigger gcTrigger) {
}
// Ok, we're doing it! Stop everybody else
+ semacquire(&gcsema)
semacquire(&worldsema)
if trace.enabled {
@@ -1367,6 +1368,13 @@ func gcStart(trigger gcTrigger) {
work.pauseNS += now - work.pauseStart
work.tMark = now
})
+
+ // Release the world sema before Gosched() in STW mode
+ // because we will need to reacquire it later but before
+ // this goroutine becomes runnable again, and we could
+ // self-deadlock otherwise.
+ semrelease(&worldsema)
+
// In STW mode, we could block the instant systemstack
// returns, so don't do anything important here. Make sure we
// block rather than returning to user code.
@@ -1436,6 +1444,10 @@ top:
return
}
+ // forEachP needs worldsema to execute, and we'll need it to
+ // stop the world later, so acquire worldsema now.
+ semacquire(&worldsema)
+
// Flush all local buffers and collect flushedWork flags.
gcMarkDoneFlushed = 0
systemstack(func() {
@@ -1496,6 +1508,7 @@ top:
// work to do. Keep going. It's possible the
// transition condition became true again during the
// ragged barrier, so re-check it.
+ semrelease(&worldsema)
goto top
}
@@ -1572,6 +1585,7 @@ top:
now := startTheWorldWithSema(true)
work.pauseNS += now - work.pauseStart
})
+ semrelease(&worldsema)
goto top
}
}
@@ -1789,6 +1803,7 @@ func gcMarkTermination(nextTriggerRatio float64) {
}
semrelease(&worldsema)
+ semrelease(&gcsema)
// Careful: another GC cycle may start now.
releasem(mp)