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,
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.
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)
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);
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:
end_b = (uintptr)b + n - PtrSize;
for(;;) {
+ if(CollectStats)
+ runtime·xadd64(&gcstats.instr[pc[0]], 1);
+
obj = nil;
objti = 0;
switch(pc[0]) {
// 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;
}
}
static void
putempty(Workbuf *b)
{
+ if(CollectStats)
+ runtime·xadd64(&gcstats.putempty, 1);
+
runtime·lfstackpush(&work.empty, &b->node);
}
{
int32 i;
+ if(CollectStats)
+ runtime·xadd64(&gcstats.getfull, 1);
+
if(b != nil)
runtime·lfstackpush(&work.empty, &b->node);
b = (Workbuf*)runtime·lfstackpop(&work.full);
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;
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);
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();