diff options
| author | Austin Clements <austin@google.com> | 2017-01-03 10:15:55 -0700 |
|---|---|---|
| committer | Austin Clements <austin@google.com> | 2017-03-04 02:56:37 +0000 |
| commit | 4a7cf960c38d72e9f0c6f00e46e013be2a35d56e (patch) | |
| tree | 1e47293cf8e12313d8ea713ed7b35ee8b157a787 /src/runtime/mcentral.go | |
| parent | 3399fd254dcdf4e8a9be8c327076de5f9efe1b3a (diff) | |
| download | go-4a7cf960c38d72e9f0c6f00e46e013be2a35d56e.tar.xz | |
runtime: make ReadMemStats STW for < 25µs
Currently ReadMemStats stops the world for ~1.7 ms/GB of heap because
it collects statistics from every single span. For large heaps, this
can be quite costly. This is particularly unfortunate because many
production infrastructures call this function regularly to collect and
report statistics.
Fix this by tracking the necessary cumulative statistics in the
mcaches. ReadMemStats still has to stop the world to stabilize these
statistics, but there are only O(GOMAXPROCS) mcaches to collect
statistics from, so this pause is only 25µs even at GOMAXPROCS=100.
Fixes #13613.
Change-Id: I3c0a4e14833f4760dab675efc1916e73b4c0032a
Reviewed-on: https://go-review.googlesource.com/34937
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/mcentral.go')
| -rw-r--r-- | src/runtime/mcentral.go | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/src/runtime/mcentral.go b/src/runtime/mcentral.go index ddcf81ebb1..be3820a9a5 100644 --- a/src/runtime/mcentral.go +++ b/src/runtime/mcentral.go @@ -22,6 +22,11 @@ type mcentral struct { sizeclass int32 nonempty mSpanList // list of spans with a free object, ie a nonempty free list empty mSpanList // list of spans with no free objects (or cached in an mcache) + + // nmalloc is the cumulative count of objects allocated from + // this mcentral, assuming all spans in mcaches are + // fully-allocated. Written atomically, read under STW. + nmalloc uint64 } // Initialize a single central free list. @@ -106,6 +111,9 @@ havespan: if n == 0 || s.freeindex == s.nelems || uintptr(s.allocCount) == s.nelems { throw("span has no free objects") } + // Assume all objects from this span will be allocated in the + // mcache. If it gets uncached, we'll adjust this. + atomic.Xadd64(&c.nmalloc, int64(n)) usedBytes := uintptr(s.allocCount) * s.elemsize if usedBytes > 0 { reimburseSweepCredit(usedBytes) @@ -150,6 +158,10 @@ func (c *mcentral) uncacheSpan(s *mspan) { // mCentral_CacheSpan conservatively counted // unallocated slots in heap_live. Undo this. atomic.Xadd64(&memstats.heap_live, -int64(n)*int64(s.elemsize)) + // cacheSpan updated alloc assuming all objects on s + // were going to be allocated. Adjust for any that + // weren't. + atomic.Xadd64(&c.nmalloc, -int64(n)) } unlock(&c.lock) } |
