From: Jan Ziak <0xe2.0x9a.0x9b@gmail.com> Date: Mon, 4 Mar 2013 15:54:37 +0000 (+0100) Subject: runtime: add garbage collector statistics X-Git-Tag: go1.1rc2~702 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=cea46387b9c042ea19d0b30c7accf0f9a45d8e11;p=gostls13.git runtime: add garbage collector statistics If the constant CollectStats is non-zero and GOGCTRACE=1 the garbage collector will print basic statistics about executed GC instructions. R=golang-dev, dvyukov CC=golang-dev, rsc https://golang.org/cl/7413049 --- diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c index 7b83600e8c..010f9cd961 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -17,6 +17,7 @@ enum { Debug = 0, DebugMark = 0, // run second pass to check mark + CollectStats = 0, // Four bits per word (see #defines below). wordsPerBitmapWord = sizeof(void*)*8/4, @@ -165,8 +166,29 @@ enum { GC_DEFAULT_PTR = GC_NUM_INSTR, GC_MAP_NEXT, GC_CHAN, + + GC_NUM_INSTR2 }; +static struct { + struct { + uint64 sum; + uint64 cnt; + } ptr; + uint64 nbytes; + struct { + uint64 sum; + uint64 cnt; + uint64 notype; + uint64 typelookup; + } obj; + uint64 rescan; + uint64 rescanbytes; + uint64 instr[GC_NUM_INSTR2]; + uint64 putempty; + uint64 getfull; +} gcstats; + // markonly marks an object. It returns true if the object // has been marked by this function, false otherwise. // This function isn't thread-safe and doesn't append the object to any buffer. @@ -315,6 +337,11 @@ flushptrbuf(PtrTarget *ptrbuf, PtrTarget **ptrbufpos, Obj **_wp, Workbuf **_wbuf n = ptrbuf_end - ptrbuf; *ptrbufpos = ptrbuf; + if(CollectStats) { + runtime·xadd64(&gcstats.ptr.sum, n); + runtime·xadd64(&gcstats.ptr.cnt, 1); + } + // If buffer is nearly full, get a new one. if(wbuf == nil || nobj+n >= nelem(wbuf->obj)) { if(wbuf != nil) @@ -621,6 +648,12 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking) runtime·printf("scanblock %p %D\n", b, (int64)n); } + if(CollectStats) { + runtime·xadd64(&gcstats.nbytes, n); + runtime·xadd64(&gcstats.obj.sum, nobj); + runtime·xadd64(&gcstats.obj.cnt, 1); + } + if(ti != 0) { pc = (uintptr*)(ti & ~(uintptr)PC_BITS); precise_type = (ti & PRECISE); @@ -634,8 +667,14 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking) stack_top.count = 1; } } else if(UseSpanType) { + if(CollectStats) + runtime·xadd64(&gcstats.obj.notype, 1); + type = runtime·gettype(b); if(type != 0) { + if(CollectStats) + runtime·xadd64(&gcstats.obj.typelookup, 1); + t = (Type*)(type & ~(uintptr)(PtrSize-1)); switch(type & (PtrSize-1)) { case TypeInfo_SingleObject: @@ -692,6 +731,9 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking) end_b = (uintptr)b + n - PtrSize; for(;;) { + if(CollectStats) + runtime·xadd64(&gcstats.instr[pc[0]], 1); + obj = nil; objti = 0; switch(pc[0]) { @@ -807,6 +849,10 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking) // Found a value that may be a pointer. // Do a rescan of the entire block. enqueue((Obj){b, n, 0}, &wbuf, &wp, &nobj); + if(CollectStats) { + runtime·xadd64(&gcstats.rescan, 1); + runtime·xadd64(&gcstats.rescanbytes, n); + } break; } } @@ -1164,6 +1210,9 @@ getempty(Workbuf *b) static void putempty(Workbuf *b) { + if(CollectStats) + runtime·xadd64(&gcstats.putempty, 1); + runtime·lfstackpush(&work.empty, &b->node); } @@ -1173,6 +1222,9 @@ getfull(Workbuf *b) { int32 i; + if(CollectStats) + runtime·xadd64(&gcstats.getfull, 1); + if(b != nil) runtime·lfstackpush(&work.empty, &b->node); b = (Workbuf*)runtime·lfstackpop(&work.full); @@ -1747,7 +1799,7 @@ static void gc(struct gc_args *args) { int64 t0, t1, t2, t3, t4; - uint64 heap0, heap1, obj0, obj1; + uint64 heap0, heap1, obj0, obj1, ninstr; GCStats stats; M *mp; uint32 i; @@ -1764,6 +1816,9 @@ gc(struct gc_args *args) m->gcing = 1; runtime·stoptheworld(); + if(CollectStats) + runtime·memclr((byte*)&gcstats, sizeof(gcstats)); + for(mp=runtime·allm; mp; mp=mp->alllink) runtime·settype_flush(mp, false); @@ -1859,6 +1914,27 @@ gc(struct gc_args *args) stats.nhandoff, stats.nhandoffcnt, work.sweepfor->nsteal, work.sweepfor->nstealcnt, stats.nprocyield, stats.nosyield, stats.nsleep); + if(CollectStats) { + runtime·printf("scan: %D bytes, %D objects, %D untyped, %D types from MSpan\n", + gcstats.nbytes, gcstats.obj.cnt, gcstats.obj.notype, gcstats.obj.typelookup); + if(gcstats.ptr.cnt != 0) + runtime·printf("avg ptrbufsize: %D (%D/%D)\n", + gcstats.ptr.sum/gcstats.ptr.cnt, gcstats.ptr.sum, gcstats.ptr.cnt); + if(gcstats.obj.cnt != 0) + runtime·printf("avg nobj: %D (%D/%D)\n", + gcstats.obj.sum/gcstats.obj.cnt, gcstats.obj.sum, gcstats.obj.cnt); + runtime·printf("rescans: %D, %D bytes\n", gcstats.rescan, gcstats.rescanbytes); + + runtime·printf("instruction counts:\n"); + ninstr = 0; + for(i=0; i