Skip to content

Commit dac936a

Browse files
committed
runtime: make more page sweeper operations atomic
This change makes it so that allocation and free related page sweeper metadata operations (e.g. pageInUse and pagesInUse) are atomic rather than protected by the heap lock. This will help in reducing the length of the critical path with the heap lock held in future changes. Updates #35112. Change-Id: Ie82bff024204dd17c4c671af63350a7a41add354 Reviewed-on: https://go-review.googlesource.com/c/go/+/196640 Run-TryBot: Michael Knyszek <mknyszek@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com>
1 parent 47232f0 commit dac936a

File tree

2 files changed

+14
-9
lines changed

2 files changed

+14
-9
lines changed

src/runtime/mgc.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,8 @@ func gcSetTriggerRatio(triggerRatio float64) {
865865
heapDistance = _PageSize
866866
}
867867
pagesSwept := atomic.Load64(&mheap_.pagesSwept)
868-
sweepDistancePages := int64(mheap_.pagesInUse) - int64(pagesSwept)
868+
pagesInUse := atomic.Load64(&mheap_.pagesInUse)
869+
sweepDistancePages := int64(pagesInUse) - int64(pagesSwept)
869870
if sweepDistancePages <= 0 {
870871
mheap_.sweepPagesPerByte = 0
871872
} else {

src/runtime/mheap.go

+12-8
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ type mheap struct {
9090
// accounting for current progress. If we could only adjust
9191
// the slope, it would create a discontinuity in debt if any
9292
// progress has already been made.
93-
pagesInUse uint64 // pages of spans in stats mSpanInUse; R/W with mheap.lock
93+
pagesInUse uint64 // pages of spans in stats mSpanInUse; updated atomically
9494
pagesSwept uint64 // pages swept this cycle; updated atomically
9595
pagesSweptBasis uint64 // pagesSwept to use as the origin of the sweep ratio; updated atomically
9696
sweepHeapLiveBasis uint64 // value of heap_live to use as the origin of sweep ratio; written with lock, read without
@@ -238,7 +238,7 @@ type heapArena struct {
238238
// but only the bit corresponding to the first page in each
239239
// span is used.
240240
//
241-
// Writes are protected by mheap_.lock.
241+
// Reads and writes are atomic.
242242
pageInUse [pagesPerArena / 8]uint8
243243

244244
// pageMarks is a bitmap that indicates which spans have any
@@ -812,7 +812,7 @@ func (h *mheap) reclaimChunk(arenas []arenaIdx, pageIdx, n uintptr) uintptr {
812812
// Scan this bitmap chunk for spans that are in-use
813813
// but have no marked objects on them.
814814
for i := range inUse {
815-
inUseUnmarked := inUse[i] &^ marked[i]
815+
inUseUnmarked := atomic.Load8(&inUse[i]) &^ marked[i]
816816
if inUseUnmarked == 0 {
817817
continue
818818
}
@@ -831,7 +831,7 @@ func (h *mheap) reclaimChunk(arenas []arenaIdx, pageIdx, n uintptr) uintptr {
831831
// spans were freed when we dropped the
832832
// lock and we don't want to get stale
833833
// pointers from the spans array.
834-
inUseUnmarked = inUse[i] &^ marked[i]
834+
inUseUnmarked = atomic.Load8(&inUse[i]) &^ marked[i]
835835
}
836836
}
837837
}
@@ -934,11 +934,15 @@ func (h *mheap) alloc_m(npage uintptr, spanclass spanClass) *mspan {
934934
s.state.set(mSpanInUse)
935935

936936
// Mark in-use span in arena page bitmap.
937+
//
938+
// This publishes the span to the page sweeper, so
939+
// it's imperative that the span be completely initialized
940+
// prior to this line.
937941
arena, pageIdx, pageMask := pageIndexOf(s.base())
938-
arena.pageInUse[pageIdx] |= pageMask
942+
atomic.Or8(&arena.pageInUse[pageIdx], pageMask)
939943

940944
// Update related page sweeper stats.
941-
h.pagesInUse += uint64(npage)
945+
atomic.Xadd64(&h.pagesInUse, int64(npage))
942946
}
943947
// heap_scan and heap_live were updated.
944948
if gcBlackenEnabled != 0 {
@@ -1264,11 +1268,11 @@ func (h *mheap) freeSpanLocked(s *mspan, acctinuse, acctidle bool) {
12641268
print("mheap.freeSpanLocked - span ", s, " ptr ", hex(s.base()), " allocCount ", s.allocCount, " sweepgen ", s.sweepgen, "/", h.sweepgen, "\n")
12651269
throw("mheap.freeSpanLocked - invalid free")
12661270
}
1267-
h.pagesInUse -= uint64(s.npages)
1271+
atomic.Xadd64(&h.pagesInUse, -int64(s.npages))
12681272

12691273
// Clear in-use bit in arena page bitmap.
12701274
arena, pageIdx, pageMask := pageIndexOf(s.base())
1271-
arena.pageInUse[pageIdx] &^= pageMask
1275+
atomic.And8(&arena.pageInUse[pageIdx], ^pageMask)
12721276
default:
12731277
throw("mheap.freeSpanLocked - invalid span state")
12741278
}

0 commit comments

Comments
 (0)