/*{{{ includes */ #include #include #include #include #include #ifndef WIN32 #include #include #endif #include "_aterm.h" #include "afun.h" #include "memory.h" #include "util.h" #include "gc.h" #include "debug.h" /*}}} */ /*{{{ globals */ char gc_id[] = "$Id: gc.c,v 1.34 1999/07/21 15:45:00 js Exp $"; static ATerm *stackBot = NULL; #define PRINT_GC_TIME 1 #define PRINT_GC_STATS 2 static int flags = 0; static int gc_count = 0; static clock_t sweep_time[3] = { 0, MYMAXINT, 0 }; static clock_t mark_time[3] = { 0, MYMAXINT, 0 }; static int stack_depth[3] = { 0, MYMAXINT, 0 }; static int stack_terms[3] = { 0, MYMAXINT, 0 }; static int stack_symbols[3] = { 0, MYMAXINT, 0 }; static int register_terms[3] = { 0, MYMAXINT, 0 }; static int register_symbols[3] = { 0, MYMAXINT, 0 }; static int reclaim_perc[3] = { 0, MYMAXINT, 0 }; extern int mark_stats[3]; extern int nr_marks; /*}}} */ /*{{{ void AT_initGC(int argc, char *argv[], ATerm *bottomOfStack) */ /** * Initialize the garbage collector. */ void AT_initGC(int argc, char *argv[], ATerm *bottomOfStack) { int i; stackBot = bottomOfStack; for(i=1; iterm) AT_markTerm(*cur->term); cur = cur->next; } } /* Traverse protected arrays */ for(i=0; isize == size); for(idx=0; idxdata[idx]); if(IS_MARKED(t->header)) CLR_MARK(t->header); else { switch(ATgetType(t)) { case AT_FREE: break; case AT_INT: case AT_REAL: case AT_APPL: case AT_LIST: case AT_PLACEHOLDER: case AT_BLOB: AT_freeTerm(size, t); reclaiming++; break; case AT_SYMBOL: AT_freeSymbol((SymEntry)t); break; default: ATabort("panic in sweep phase\n"); } } } block = block->next_by_size; } total += at_nrblocks[size]*(BLOCK_SIZE/size); } perc = (100*reclaiming)/total; STATS(reclaim_perc, perc); } /*}}} */ /*{{{ void AT_collect() */ /** * Collect all garbage */ #ifdef WIN32 void AT_collect(int size) /* The timing/STATS parts haven't been tested yet (on NT) but without the info things seem to work fine */ { clock_t start, mark, sweep; clock_t user; gc_count++; if (!silent) { fprintf(stderr, "collecting garbage.."); fflush(stderr); } start = clock(); mark_phase(); mark = clock(); user = mark - start; STATS(mark_time, user); sweep_phase(); sweep = clock(); user = sweep - mark; STATS(sweep_time, user); if (!silent) fprintf(stderr, "..\n"); } #else void AT_collect(int size) { struct tms start, mark, sweep; clock_t user; gc_count++; if (!silent) { fprintf(stderr, "collecting garbage.."); fflush(stderr); } times(&start); mark_phase(); times(&mark); user = mark.tms_utime - start.tms_utime; STATS(mark_time, user); sweep_phase(); times(&sweep); user = sweep.tms_utime - mark.tms_utime; STATS(sweep_time, user); if (!silent) fprintf(stderr, "..\n"); } #endif /*}}} */ /*{{{ void AT_cleanupGC() */ /** * Print garbage collection information */ void AT_cleanupGC() { #ifdef WIN32 if(flags & PRINT_GC_TIME) { fprintf(stderr, "%d garbage collects,\n", gc_count); fprintf(stderr, "(all statistics are printed min/avg/max)\n"); if(gc_count > 0) { if(nr_marks > 0) { fprintf(stderr, " mark stack needed: %d/%d/%d (%d marks)\n", mark_stats[IDX_MIN], mark_stats[IDX_TOTAL]/nr_marks, mark_stats[IDX_MAX], nr_marks); } fprintf(stderr, " marking took %.2f/%.2f/%.2f seconds, total: %.2f\n", ((double)mark_time[IDX_MIN])/(double)CLOCKS_PER_SEC, (((double)mark_time[IDX_TOTAL])/(double)gc_count)/(double)CLOCKS_PER_SEC, ((double)mark_time[IDX_MAX])/(double)CLOCKS_PER_SEC, ((double)mark_time[IDX_TOTAL])/(double)CLOCKS_PER_SEC); fprintf(stderr, " sweeping took %.2f/%.2f/%.2f total: %.2f\n", ((double)sweep_time[IDX_MIN])/(double)CLOCKS_PER_SEC, (((double)sweep_time[IDX_TOTAL])/(double)gc_count)/(double)CLOCKS_PER_SEC, ((double)sweep_time[IDX_MAX])/(double)CLOCKS_PER_SEC, ((double)sweep_time[IDX_TOTAL])/(double)CLOCKS_PER_SEC); } fprintf(stderr, "Note: WinNT times are absolute, and might be influenced by other processes.\n"); } #else if(flags & PRINT_GC_TIME) { fprintf(stderr, "%d garbage collects,\n", gc_count); fprintf(stderr, "(all statistics are printed min/avg/max)\n"); if(gc_count > 0) { if(nr_marks > 0) { fprintf(stderr, " mark stack needed: %d/%d/%d (%d marks)\n", mark_stats[IDX_MIN], mark_stats[IDX_TOTAL]/nr_marks, mark_stats[IDX_MAX], nr_marks); } fprintf(stderr, " marking took %.2f/%.2f/%.2f seconds, total: %.2f\n", ((double)mark_time[IDX_MIN])/(double)CLK_TCK, (((double)mark_time[IDX_TOTAL])/(double)gc_count)/(double)CLK_TCK, ((double)mark_time[IDX_MAX])/(double)CLK_TCK, ((double)mark_time[IDX_TOTAL])/(double)CLK_TCK); fprintf(stderr, " sweeping took %.2f/%.2f/%.2f seconds, total: %.2f\n", ((double)sweep_time[IDX_MIN])/(double)CLK_TCK, (((double)sweep_time[IDX_TOTAL])/(double)gc_count)/(double)CLK_TCK, ((double)sweep_time[IDX_MAX])/(double)CLK_TCK, ((double)sweep_time[IDX_TOTAL])/(double)CLK_TCK); } } #endif if(flags & PRINT_GC_STATS) { if(gc_count > 0) { fprintf(stderr, "\n stack depth: %d/%d/%d words\n", stack_depth[IDX_MIN], stack_depth[IDX_TOTAL]/gc_count, stack_depth[IDX_MAX]); fprintf(stderr, " term roots on stack: %d/%d/%d\n", stack_terms[IDX_MIN], stack_terms[IDX_TOTAL]/gc_count, stack_terms[IDX_MAX]); fprintf(stderr, " symbol roots on stack: %d/%d/%d\n", stack_symbols[IDX_MIN], stack_symbols[IDX_TOTAL]/gc_count, stack_symbols[IDX_MAX]); fprintf(stderr, " term roots in registers: %d/%d/%d\n", register_terms[IDX_MIN], register_terms[IDX_TOTAL]/gc_count, register_terms[IDX_MAX]); fprintf(stderr, " symbol roots in registers: %d/%d/%d\n", register_symbols[IDX_MIN], register_symbols[IDX_TOTAL]/gc_count, register_symbols[IDX_MAX]); fprintf(stderr, "\n reclamation percentage: %d/%d/%d\n", reclaim_perc[IDX_MIN], reclaim_perc[IDX_TOTAL]/gc_count, reclaim_perc[IDX_MAX]); } } } /*}}} */