aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/mgcsweep.go
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2017-04-03 15:22:06 -0400
committerAustin Clements <austin@google.com>2017-04-21 17:41:57 +0000
commita5eb3dceaf8d4e3fafac0d947decae62d3028df1 (patch)
treea71f8db01608d68a32abaf14a26581fae5634234 /src/runtime/mgcsweep.go
parentee175afac237c9fcb54785eec2890dfb0dd6825f (diff)
downloadgo-a5eb3dceaf8d4e3fafac0d947decae62d3028df1.tar.gz
go-a5eb3dceaf8d4e3fafac0d947decae62d3028df1.zip
runtime: drive proportional sweep directly off heap_live
Currently, proportional sweep maintains its own count of how many bytes have been allocated since the beginning of the sweep cycle so it can compute how many pages need to be swept for a given allocation. However, this requires a somewhat complex reimbursement scheme since proportional sweep must be done before a span is allocated, but we don't know how many bytes to charge until we've allocated a span. This means that the allocated byte count used by proportional sweep can go up and down, which has led to underflow bugs in the past (#18043) and is going to interfere with adjusting sweep pacing on-the-fly (for #19076). This approach also means we're maintaining a statistic that is very closely related to heap_live, but has a different 0 value. This is particularly confusing because the sweep ratio is computed based on heap_live, so you have to understand that these two statistics are very closely related. Replace all of this and compute the sweep debt directly from the current value of heap_live. To make this work, we simply save the value of heap_live when the sweep ratio is computed to use as a "basis" for later computing the sweep debt. This eliminates the need for reimbursement as well as the code for maintaining the sweeper's version of the live heap size. For #19076. Coincidentally fixes #18043, since this eliminates sweep reimbursement entirely. Change-Id: I1f931ddd6e90c901a3972c7506874c899251dc2a Reviewed-on: https://go-review.googlesource.com/39832 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rick Hudson <rlh@golang.org>
Diffstat (limited to 'src/runtime/mgcsweep.go')
-rw-r--r--src/runtime/mgcsweep.go29
1 files changed, 5 insertions, 24 deletions
diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go
index dd0682594a..8915b398cd 100644
--- a/src/runtime/mgcsweep.go
+++ b/src/runtime/mgcsweep.go
@@ -123,7 +123,7 @@ func sweepone() uintptr {
// last one print trace information.
if atomic.Xadd(&mheap_.sweepers, -1) == 0 && atomic.Load(&mheap_.sweepdone) != 0 {
if debug.gcpacertrace > 0 {
- print("pacer: sweep done at heap size ", memstats.heap_live>>20, "MB; allocated ", mheap_.spanBytesAlloc>>20, "MB of spans; swept ", mheap_.pagesSwept, " pages at ", sweepRatio, " pages/byte\n")
+ print("pacer: sweep done at heap size ", memstats.heap_live>>20, "MB; allocated ", (memstats.heap_live-mheap_.sweepHeapLiveBasis)>>20, "MB during sweep; swept ", mheap_.pagesSwept, " pages at ", sweepRatio, " pages/byte\n")
}
}
_g_.m.locks--
@@ -379,8 +379,7 @@ func (s *mspan) sweep(preserve bool) bool {
//
// deductSweepCredit makes a worst-case assumption that all spanBytes
// bytes of the ultimately allocated span will be available for object
-// allocation. The caller should call reimburseSweepCredit if that
-// turns out not to be the case once the span is allocated.
+// allocation.
//
// deductSweepCredit is the core of the "proportional sweep" system.
// It uses statistics gathered by the garbage collector to perform
@@ -398,12 +397,10 @@ func deductSweepCredit(spanBytes uintptr, callerSweepPages uintptr) {
traceGCSweepStart()
}
- // Account for this span allocation.
- spanBytesAlloc := atomic.Xadd64(&mheap_.spanBytesAlloc, int64(spanBytes))
-
// Fix debt if necessary.
- pagesOwed := int64(mheap_.sweepPagesPerByte * float64(spanBytesAlloc))
- for pagesOwed-int64(atomic.Load64(&mheap_.pagesSwept)) > int64(callerSweepPages) {
+ newHeapLive := uintptr(atomic.Load64(&memstats.heap_live)-mheap_.sweepHeapLiveBasis) + spanBytes
+ pagesTarget := int64(mheap_.sweepPagesPerByte*float64(newHeapLive)) - int64(callerSweepPages)
+ for pagesTarget > int64(atomic.Load64(&mheap_.pagesSwept)) {
if gosweepone() == ^uintptr(0) {
mheap_.sweepPagesPerByte = 0
break
@@ -414,19 +411,3 @@ func deductSweepCredit(spanBytes uintptr, callerSweepPages uintptr) {
traceGCSweepDone()
}
}
-
-// reimburseSweepCredit records that unusableBytes bytes of a
-// just-allocated span are not available for object allocation. This
-// offsets the worst-case charge performed by deductSweepCredit.
-func reimburseSweepCredit(unusableBytes uintptr) {
- if mheap_.sweepPagesPerByte == 0 {
- // Nobody cares about the credit. Avoid the atomic.
- return
- }
- nval := atomic.Xadd64(&mheap_.spanBytesAlloc, -int64(unusableBytes))
- if int64(nval) < 0 {
- // Debugging for #18043.
- print("runtime: bad spanBytesAlloc=", nval, " (was ", nval+uint64(unusableBytes), ") unusableBytes=", unusableBytes, " sweepPagesPerByte=", mheap_.sweepPagesPerByte, "\n")
- throw("spanBytesAlloc underflow")
- }
-}