Commit cea46387 authored by Jan Ziak's avatar Jan Ziak

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
parent a85fce28
......@@ -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();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment