runtime: fix memstats

Newly allocated memory is subtracted from inuse, while it was never added to inuse.
Span leftovers are subtracted from both inuse and idle,
while they were never added.
Fixes #8544.
Fixes #8430.

LGTM=khr, cookieo9
R=golang-codereviews, khr, cookieo9
CC=golang-codereviews, rlh, rsc
https://golang.org/cl/130200044
This commit is contained in:
Dmitriy Vyukov 2014-08-19 11:46:05 +04:00
parent 2de65cad54
commit 30ef2c7deb
3 changed files with 34 additions and 13 deletions

View file

@ -283,6 +283,7 @@ struct MStats
#define mstats runtime·memstats #define mstats runtime·memstats
extern MStats mstats; extern MStats mstats;
void runtime·updatememstats(GCStats *stats); void runtime·updatememstats(GCStats *stats);
void runtime·ReadMemStats(MStats *stats);
// Size classes. Computed and initialized by InitSizes. // Size classes. Computed and initialized by InitSizes.
// //

View file

@ -16,10 +16,26 @@ func TestMemStats(t *testing.T) {
// Test that MemStats has sane values. // Test that MemStats has sane values.
st := new(MemStats) st := new(MemStats)
ReadMemStats(st) ReadMemStats(st)
if st.HeapSys == 0 || st.StackSys == 0 || st.MSpanSys == 0 || st.MCacheSys == 0 ||
st.BuckHashSys == 0 || st.GCSys == 0 || st.OtherSys == 0 { // Everything except HeapReleased, because it indeed can be 0.
t.Fatalf("Zero sys value: %+v", *st) if st.Alloc == 0 || st.TotalAlloc == 0 || st.Sys == 0 || st.Lookups == 0 ||
st.Mallocs == 0 || st.Frees == 0 || st.HeapAlloc == 0 || st.HeapSys == 0 ||
st.HeapIdle == 0 || st.HeapInuse == 0 || st.HeapObjects == 0 || st.StackInuse == 0 ||
st.StackSys == 0 || st.MSpanInuse == 0 || st.MSpanSys == 0 || st.MCacheInuse == 0 ||
st.MCacheSys == 0 || st.BuckHashSys == 0 || st.GCSys == 0 || st.OtherSys == 0 ||
st.NextGC == 0 || st.NumGC == 0 {
t.Fatalf("Zero value: %+v", *st)
} }
if st.Alloc > 1e10 || st.TotalAlloc > 1e11 || st.Sys > 1e10 || st.Lookups > 1e10 ||
st.Mallocs > 1e10 || st.Frees > 1e10 || st.HeapAlloc > 1e10 || st.HeapSys > 1e10 ||
st.HeapIdle > 1e10 || st.HeapInuse > 1e10 || st.HeapObjects > 1e10 || st.StackInuse > 1e10 ||
st.StackSys > 1e10 || st.MSpanInuse > 1e10 || st.MSpanSys > 1e10 || st.MCacheInuse > 1e10 ||
st.MCacheSys > 1e10 || st.BuckHashSys > 1e10 || st.GCSys > 1e10 || st.OtherSys > 1e10 ||
st.NextGC > 1e10 || st.NumGC > 1e9 {
t.Fatalf("Insanely high value (overflow?): %+v", *st)
}
if st.Sys != st.HeapSys+st.StackSys+st.MSpanSys+st.MCacheSys+ if st.Sys != st.HeapSys+st.StackSys+st.MSpanSys+st.MCacheSys+
st.BuckHashSys+st.GCSys+st.OtherSys { st.BuckHashSys+st.GCSys+st.OtherSys {
t.Fatalf("Bad sys value: %+v", *st) t.Fatalf("Bad sys value: %+v", *st)

View file

@ -17,7 +17,7 @@
#include "malloc.h" #include "malloc.h"
static MSpan *MHeap_AllocSpanLocked(MHeap*, uintptr); static MSpan *MHeap_AllocSpanLocked(MHeap*, uintptr);
static void MHeap_FreeSpanLocked(MHeap*, MSpan*); static void MHeap_FreeSpanLocked(MHeap*, MSpan*, bool, bool);
static bool MHeap_Grow(MHeap*, uintptr); static bool MHeap_Grow(MHeap*, uintptr);
static MSpan *MHeap_AllocLarge(MHeap*, uintptr); static MSpan *MHeap_AllocLarge(MHeap*, uintptr);
static MSpan *BestFit(MSpan*, uintptr, MSpan*); static MSpan *BestFit(MSpan*, uintptr, MSpan*);
@ -326,7 +326,7 @@ HaveSpan:
t->needzero = s->needzero; t->needzero = s->needzero;
s->state = MSpanStack; // prevent coalescing with s s->state = MSpanStack; // prevent coalescing with s
t->state = MSpanStack; t->state = MSpanStack;
MHeap_FreeSpanLocked(h, t); MHeap_FreeSpanLocked(h, t, false, false);
t->unusedsince = s->unusedsince; // preserve age (TODO: wrong: t is possibly merged and/or deallocated at this point) t->unusedsince = s->unusedsince; // preserve age (TODO: wrong: t is possibly merged and/or deallocated at this point)
s->state = MSpanFree; s->state = MSpanFree;
} }
@ -413,7 +413,7 @@ MHeap_Grow(MHeap *h, uintptr npage)
h->spans[p + s->npages - 1] = s; h->spans[p + s->npages - 1] = s;
runtime·atomicstore(&s->sweepgen, h->sweepgen); runtime·atomicstore(&s->sweepgen, h->sweepgen);
s->state = MSpanInUse; s->state = MSpanInUse;
MHeap_FreeSpanLocked(h, s); MHeap_FreeSpanLocked(h, s, false, true);
return true; return true;
} }
@ -467,7 +467,7 @@ mheap_free(MHeap *h, MSpan *s, int32 acct)
mstats.heap_alloc -= s->npages<<PageShift; mstats.heap_alloc -= s->npages<<PageShift;
mstats.heap_objects--; mstats.heap_objects--;
} }
MHeap_FreeSpanLocked(h, s); MHeap_FreeSpanLocked(h, s, true, true);
runtime·unlock(&h->lock); runtime·unlock(&h->lock);
} }
@ -506,12 +506,12 @@ runtime·MHeap_FreeStack(MHeap *h, MSpan *s)
s->needzero = 1; s->needzero = 1;
runtime·lock(&h->lock); runtime·lock(&h->lock);
mstats.stacks_inuse -= s->npages<<PageShift; mstats.stacks_inuse -= s->npages<<PageShift;
MHeap_FreeSpanLocked(h, s); MHeap_FreeSpanLocked(h, s, true, true);
runtime·unlock(&h->lock); runtime·unlock(&h->lock);
} }
static void static void
MHeap_FreeSpanLocked(MHeap *h, MSpan *s) MHeap_FreeSpanLocked(MHeap *h, MSpan *s, bool acctinuse, bool acctidle)
{ {
MSpan *t; MSpan *t;
PageID p; PageID p;
@ -532,8 +532,10 @@ MHeap_FreeSpanLocked(MHeap *h, MSpan *s)
runtime·throw("MHeap_FreeSpanLocked - invalid span state"); runtime·throw("MHeap_FreeSpanLocked - invalid span state");
break; break;
} }
mstats.heap_inuse -= s->npages<<PageShift; if(acctinuse)
mstats.heap_idle += s->npages<<PageShift; mstats.heap_inuse -= s->npages<<PageShift;
if(acctidle)
mstats.heap_idle += s->npages<<PageShift;
s->state = MSpanFree; s->state = MSpanFree;
runtime·MSpanList_Remove(s); runtime·MSpanList_Remove(s);
// Stamp newly unused spans. The scavenger will use that // Stamp newly unused spans. The scavenger will use that
@ -606,6 +608,7 @@ scavenge(int32 k, uint64 now, uint64 limit)
{ {
uint32 i; uint32 i;
uintptr sumreleased; uintptr sumreleased;
MStats stats;
MHeap *h; MHeap *h;
h = &runtime·mheap; h = &runtime·mheap;
@ -615,11 +618,12 @@ scavenge(int32 k, uint64 now, uint64 limit)
sumreleased += scavengelist(&h->freelarge, now, limit); sumreleased += scavengelist(&h->freelarge, now, limit);
if(runtime·debug.gctrace > 0) { if(runtime·debug.gctrace > 0) {
runtime·ReadMemStats(&stats);
if(sumreleased > 0) if(sumreleased > 0)
runtime·printf("scvg%d: %D MB released\n", k, (uint64)sumreleased>>20); runtime·printf("scvg%d: %D MB released\n", k, (uint64)sumreleased>>20);
runtime·printf("scvg%d: inuse: %D, idle: %D, sys: %D, released: %D, consumed: %D (MB)\n", runtime·printf("scvg%d: inuse: %D, idle: %D, sys: %D, released: %D, consumed: %D (MB)\n",
k, mstats.heap_inuse>>20, mstats.heap_idle>>20, mstats.heap_sys>>20, k, stats.heap_inuse>>20, stats.heap_idle>>20, stats.heap_sys>>20,
mstats.heap_released>>20, (mstats.heap_sys - mstats.heap_released)>>20); stats.heap_released>>20, (stats.heap_sys - stats.heap_released)>>20);
} }
} }