]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: add garbage collector statistics
authorJan Ziak <0xe2.0x9a.0x9b@gmail.com>
Mon, 4 Mar 2013 15:54:37 +0000 (16:54 +0100)
committerJan Ziak <0xe2.0x9a.0x9b@gmail.com>
Mon, 4 Mar 2013 15:54:37 +0000 (16:54 +0100)
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

src/pkg/runtime/mgc0.c

index 7b83600e8c2b7c9960777614d9c495e4bc736e73..010f9cd9615795497c5061b152c9fb37a6475d2a 100644 (file)
@@ -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<nelem(gcstats.instr); i++) {
+                               runtime·printf("\t%d:\t%D\n", i, gcstats.instr[i]);
+                               ninstr += gcstats.instr[i];
+                       }
+                       runtime·printf("\ttotal:\t%D\n", ninstr);
+
+                       runtime·printf("putempty: %D, getfull: %D\n", gcstats.putempty, gcstats.getfull);
+               }
        }
 
        runtime·MProf_GC();