From: Austin Clements Date: Wed, 26 Sep 2018 20:32:52 +0000 (-0400) Subject: runtime: record in-use spans in a page-indexed bitmap X-Git-Tag: go1.12beta1~345 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=69e666e4f758cb5431e94aa90dc01a72ab806080;p=gostls13.git runtime: record in-use spans in a page-indexed bitmap This adds a bitmap indexed by page number that marks the starts of in-use spans. This will be used to quickly find in-use spans with no marked objects for sweeping. For #18155. Change-Id: Icee56f029cde502447193e136fa54a74c74326dd Reviewed-on: https://go-review.googlesource.com/c/138957 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Rick Hudson Reviewed-by: Michael Knyszek --- diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go index c8b2b6524f..12868075d4 100644 --- a/src/runtime/mheap.go +++ b/src/runtime/mheap.go @@ -193,6 +193,14 @@ type heapArena struct { // must not be a safe-point between establishing that an // address is live and looking it up in the spans array. spans [pagesPerArena]*mspan + + // pageInUse is a bitmap that indicates which spans are in + // state mSpanInUse. This bitmap is indexed by page number, + // but only the bit corresponding to the first page in each + // span is used. + // + // Writes are protected by mheap_.lock. + pageInUse [pagesPerArena / 8]uint8 } // arenaHint is a hint for where to grow the heap arenas. See @@ -600,6 +608,16 @@ func spanOfHeap(p uintptr) *mspan { return s } +// pageIndexOf returns the arena, page index, and page mask for pointer p. +// The caller must ensure p is in the heap. +func pageIndexOf(p uintptr) (arena *heapArena, pageIdx uintptr, pageMask uint8) { + ai := arenaIndex(p) + arena = mheap_.arenas[ai.l1()][ai.l2()] + pageIdx = ((p / pageSize) / 8) % uintptr(len(arena.pageInUse)) + pageMask = byte(1 << ((p / pageSize) % 8)) + return +} + // Initialize the heap. func (h *mheap) init() { h.treapalloc.init(unsafe.Sizeof(treapNode{}), nil, nil, &memstats.other_sys) @@ -741,6 +759,10 @@ func (h *mheap) alloc_m(npage uintptr, spanclass spanClass, large bool) *mspan { s.baseMask = m.baseMask } + // Mark in-use span in arena page bitmap. + arena, pageIdx, pageMask := pageIndexOf(s.base()) + arena.pageInUse[pageIdx] |= pageMask + // update stats, sweep lists h.pagesInUse += uint64(npage) if large { @@ -1039,6 +1061,10 @@ func (h *mheap) freeSpanLocked(s *mspan, acctinuse, acctidle bool, unusedsince i throw("mheap.freeSpanLocked - invalid free") } h.pagesInUse -= uint64(s.npages) + + // Clear in-use bit in arena page bitmap. + arena, pageIdx, pageMask := pageIndexOf(s.base()) + arena.pageInUse[pageIdx] &^= pageMask default: throw("mheap.freeSpanLocked - invalid span state") }