/* gc-stats.c * * COPYRIGHT (c) 1993 by AT&T Bell Laboratories. * * Support routines for gathering GC statistics. */ #include "ml-osdep.h" #include #include #include #include "ml-base.h" #include "ml-limits.h" #include "ml-state.h" #include "heap.h" #include "cntr.h" #include "gc-stats.h" FILE *DebugF; FILE *StatsF; /** Virtual memory statistics **/ #ifdef VM_STATS #define ROUND1K(X) (((X)+512)/1024) /* ReportVM: * */ void ReportVM (ml_state_t *msp, int maxCollectedGen) { heap_t *heap = msp->ml_heap; int kbytesPerPage = GETPAGESIZE()/1024; FILE *f = (StatsF == NULL) ? DebugF : StatsF; struct rusage ru; Addr_t bytesAllocated, oldBytes, vmAlloc; int i, j; getrusage(RUSAGE_SELF, &ru); #ifdef XXX bytesAllocated = ((Addr_t)(msp->ml_allocPtr) - (Addr_t)(heap->allocBase)); #else bytesAllocated = 0; #endif /* count size of older generations */ oldBytes = 0; for (i = 0; i < heap->numGens; i++) { for (j = 0; j < NUM_ARENAS; j++) { arena_t *ap = heap->gen[i]->arena[j]; if (i < maxCollectedGen) { if (ap->frspSizeB > 0) oldBytes += ((Addr_t)(ap->frspTop) - (Addr_t)(ap->frspBase)); } else { if (isACTIVE(ap)) oldBytes += ((Addr_t)(ap->nextw) - (Addr_t)(ap->tospBase)); } } /* count code objects too! */ for (j = 0; j < NUM_BIGOBJ_KINDS; j++) { bigobj_desc_t *dp = heap->gen[i]->bigObjs[j]; for (; dp != NIL(bigobj_desc_t *); dp = dp->next) { oldBytes += dp->sizeB; } } } /* get amount of allocated VM (in Kb) */ vmAlloc = MEM_GetVMSize(); fprintf (f, "VM{alloc="); CNTR_FPRINTF (f, &(heap->numAlloc), 10); fprintf (f, ", new=%dk, old=%dk, tot=%dk, max_rss=%d}\n", ROUND1K(bytesAllocated), ROUND1K(oldBytes), vmAlloc, ru.ru_maxrss*kbytesPerPage); fflush (f); } /* end of ReportVM */ #endif /** Pause time statistics **/ #ifdef PAUSE_STATS pause_info_t PauseTbl[MAX_NGENS+1]; /* InitPauseTbl: */ void InitPauseTbl () { int i; for (i = 0; i <= MAX_NGENS; i++) { PauseTbl[i].numGCs = 0; PauseTbl[i].maxPause = 0; PauseTbl[i].buckets = NIL(short *); } GrowPauseTbl (0, MS_TO_BUCKET(500)); GrowPauseTbl (1, MS_TO_BUCKET(1000)); GrowPauseTbl (2, MS_TO_BUCKET(2000)); GrowPauseTbl (3, MS_TO_BUCKET(3000)); GrowPauseTbl (4, MS_TO_BUCKET(3000)); GrowPauseTbl (5, MS_TO_BUCKET(4000)); GrowPauseTbl (6, MS_TO_BUCKET(4000)); } /* end of InitPauseTbl */ /* GrowPauseTbl: * */ void GrowPauseTbl (int gen, int pause) { pause_info_t *p = &(PauseTbl[gen]); short *buckets = p->buckets, *new; int sz, i; for (sz = (p->maxPause ? p->maxPause : 16); sz < pause; sz = sz+sz) continue; new = NEW_VEC(short, sz); if (buckets != NIL(short *)) { for (i = 0; i < p->maxPause; i++) new[i] = buckets[i]; for (; i < sz; i++) new[i] = 0; FREE (buckets); } else { for (i = 0; i < sz; i++) new[i] = 0; } p->buckets = new; p->maxPause = sz; } /* end of GrowPauseTbl */ /* ReportPauses: * */ void ReportPauses (FILE *f) { pause_info_t *infop; int i, j, k, n, maxPause; /* compute the largest maxPause time */ maxPause = 100; /* one second */ for (i = MAX_NGENS; i > 0; i--) { infop = &(PauseTbl[i]); if ((infop->numGCs > 0) && (infop->maxPause > maxPause)) { for (j = infop->maxPause-1; (j > maxPause) && (infop->buckets[j] == 0); j--) continue; if (j > maxPause) maxPause = ((j+99)/100)*100; } } fprintf(f, "newgraph\n"); fprintf(f, " xaxis\n"); fprintf(f, " label : GC Pause Times (ms)\n"); fprintf(f, " no_auto_hash_marks\n"); fprintf(f, " size 4.5\n"); fprintf(f, " min -10 max %d\n", maxPause); for (i = 0; i <= maxPause; i += 50) fprintf(f, " hash_at %4d hash_label at %4d : %4d\n", i, i, i*10); fprintf(f, " yaxis\n"); fprintf(f, " label : Number of pauses\n"); fprintf(f, " min 0\n"); for (i = MAX_NGENS; i > 0; i--) { infop = &(PauseTbl[i]); if (infop->numGCs == 0) continue; fprintf(f, " (* generation %d pause times *)\n", i); fprintf(f, " newcurve\n"); fprintf(f, " label : Generation %d\n", i); fprintf(f, " marktype xbar\n"); fprintf(f, " pts\n"); for (j = 0; j < infop->maxPause; j++) { if (infop->buckets[j] == 0) continue; for (k = 1, n = 0; k <= i; k++) { if (PauseTbl[k].maxPause >= j) n += PauseTbl[k].buckets[j]; } fprintf(f, " %4d %3d\n", j*10, n); } } fflush (f); } /* end of ReportPauses */ #endif