static NOINLINE void * slow_alloc(size_t obj_size) { void *obj; GCSTAT_TRIGGER(obj_size); do_gc(); if (HEAP_REST(sml_heap_from_space) >= obj_size) { obj = sml_heap_from_space.free; sml_heap_from_space.free += obj_size; #ifdef GC_STAT sml_heap_alloced(obj_size); #endif /* GC_STAT */ } else { #ifdef GCSTAT stat_notice("---"); stat_notice("event: error"); stat_notice("heap exceeded: intented to allocate %lu bytes.", (unsigned long)obj_size); if (gcstat.file) fclose(gcstat.file); #endif /* GCSTAT */ sml_fatal(0, "heap exceeded: intended to allocate %lu bytes.", (unsigned long)obj_size); } GIANT_UNLOCK(); #ifndef FAIR_COMPARISON sml_run_finalizer(); #endif /* FAIR_COMPARISON */ return obj; }
static void print_heap_occupancy() { unsigned int i; if (gcstat.verbose < GCSTAT_VERBOSE_HEAP) return; stat_notice("heap:"); for (i = 0; i < THE_NUMBER_OF_FIXED_BLOCK; i++) { unsigned int count = 0; unsigned long filled = 0; struct bitmap_info_space *b_info = &bitmap_info[i]; char *end = (char*)bitmap_info[i].obj_base + (heap_layout[i].block_counts << bitmap_info[i].block_size_log); char *p = b_info->obj_base; bitptr b, b_end = b_info->bitmap; if (b_end.mask == 0) b_end.mask = ~0U; CLEAR_BITPTR(b, b_info->base); while (p < end) { if (b.cur < b_end.cur || (b.cur == b_end.cur && b.mask < b_end.mask) || TEST_BITPTR(b)) count++, filled += OBJ_TOTAL_SIZE(p); SUCC_BITPTR(b); p += b_info->block_size_bytes; } stat_notice(" %lu:", (unsigned long)b_info->block_size_bytes); stat_notice(" - {filled: %lu, count: %u, used: %u}", filled, count, count << bitmap_info[i].block_size_log); } }
static void print_alloc_count() { if (gcstat.verbose < GCSTAT_VERBOSE_COUNT) return; stat_notice("count:"); if (gcstat.last.alloc_count != 0 || gcstat.last.alloc_bytes != 0) stat_notice(" from: {alloc: %u}", gcstat.last.alloc_count); }
void sml_heap_init(size_t size, size_t max_size ATTR_UNUSED) { size_t space_size; #ifdef GCSTAT const char *env; env = getenv("SMLSHARP_GCSTAT_FILE"); if (env) { gcstat.file = fopen(env, "w"); if (gcstat.file == NULL) { perror("sml_heap_init"); abort(); } stat_notice = gcstat_print; } env = getenv("SMLSHARP_GCSTAT_VERBOSE"); if (env) gcstat.verbose = strtol(env, NULL, 10); else gcstat.verbose = GCSTAT_VERBOSE_MAX; env = getenv("SMLSHARP_GCSTAT_PROBE"); if (env) { gcstat.probe_threshold = strtol(env, NULL, 10); if (gcstat.probe_threshold == 0) gcstat.probe_threshold = size; } else { gcstat.probe_threshold = 2 * 1024 * 1024; } #endif /* GCSTAT */ #ifdef GCTIME sml_timer_now(gcstat.exec_begin); #endif /* GCTIME */ space_size = size / 2; heap_space_init(&sml_heap_from_space, space_size); heap_space_init(&sml_heap_to_space, space_size); #ifdef GCSTAT stat_notice("---"); stat_notice("event: init"); stat_notice("time: 0.0"); stat_notice("heap_size: %lu", (unsigned long)size); stat_notice("config:"); stat_notice(" from: {size: %lu}", (unsigned long)HEAP_TOTAL(sml_heap_from_space)); stat_notice(" to: {size: %lu}", (unsigned long)HEAP_TOTAL(sml_heap_to_space)); stat_notice("counters:"); stat_notice(" heap: [alloc]"); print_heap_occupancy(); #endif /* GCSTAT */ }
static void sml_heap_alloced(size_t size) { sml_timer_t b; sml_time_t t; gcstat.last.alloc_bytes += size; if (gcstat.last.alloc_bytes > gcstat.probe_threshold && gcstat.verbose >= GCSTAT_VERBOSE_PROBE) { sml_timer_now(b); sml_timer_dif(gcstat.exec_begin, b, t); stat_notice("---"); stat_notice("event: probe"); stat_notice("time: "TIMEFMT, TIMEARG(t)); print_alloc_count(); print_heap_occupancy(); clear_last_counts(); } gcstat.last.alloc_count++; }
static void print_alloc_count() { unsigned int i; if (gcstat.verbose < GCSTAT_VERBOSE_COUNT) return; stat_notice("count:"); for (i = 0; i < THE_NUMBER_OF_FIXED_BLOCK; i++) { if (gcstat.last.alloc_count.fast[i] != 0 || gcstat.last.alloc_count.find[i] != 0) stat_notice(" %lu: {fast: %u, find: %u}", (unsigned long)bitmap_info[i].block_size_bytes, gcstat.last.alloc_count.fast[i], gcstat.last.alloc_count.find[i]); } if (gcstat.last.alloc_count.malloc > 0) stat_notice(" other: {malloc: %u}", gcstat.last.alloc_count.malloc); }
static void print_heap_occupancy() { size_t count, filled; if (gcstat.verbose < GCSTAT_VERBOSE_HEAP) return; stat_notice("heap:"); count = heap_filled(&sml_heap_to_space, &filled); stat_notice(" to:"); stat_notice(" - {filled: %lu, count: %lu, used: %lu}", (unsigned long)filled, (unsigned long)count, (unsigned long)HEAP_USED(sml_heap_to_space)); count = heap_filled(&sml_heap_from_space, &filled); stat_notice(" from:"); stat_notice(" - {filled: %lu, count: %lu, used: %lu}", (unsigned long)filled, (unsigned long)count, (unsigned long)HEAP_USED(sml_heap_from_space)); stat_notice(" # using %lu blocks, %lu / %lu bytes, occ %.2f %%", (unsigned long)count, (unsigned long)filled, (unsigned long) (sml_heap_to_space.limit - sml_heap_to_space.base) + (sml_heap_from_space.limit - sml_heap_from_space.base), (double)filled / ((sml_heap_to_space.limit - sml_heap_to_space.base) + (sml_heap_from_space.limit - sml_heap_from_space.base)) * 100.0); }
void sml_heap_free() { heap_space_free(&sml_heap_from_space); heap_space_free(&sml_heap_to_space); #ifdef GCTIME sml_timer_now(gcstat.exec_end); sml_timer_dif(gcstat.exec_begin, gcstat.exec_end, gcstat.exec_time); #endif /* GCTIME */ #if defined GCSTAT || defined GCTIME #ifdef GCSTAT stat_notice("---"); stat_notice("event: finish"); stat_notice("time: "TIMEFMT, TIMEARG(gcstat.exec_time)); print_alloc_count(); #endif /* GCSTAT */ stat_notice("exec time : "TIMEFMT" #sec", TIMEARG(gcstat.exec_time)); stat_notice("gc count : %u #times", gcstat.gc.count); stat_notice("gc time : "TIMEFMT" #sec (%4.2f%%), avg: %.6f sec", TIMEARG(gcstat.gc.total_time), TIMEFLOAT(gcstat.gc.total_time) / TIMEFLOAT(gcstat.exec_time) * 100.0f, TIMEFLOAT(gcstat.gc.total_time) / (double)gcstat.gc.count); #ifdef GCSTAT stat_notice("total copy bytes :%10lu #bytes, avg:%8.2f bytes", gcstat.gc.total_copy_bytes, (double)gcstat.gc.total_copy_bytes / (double)gcstat.gc.count); stat_notice("total copy count :%10lu #times, avg:%8.2f times", gcstat.gc.total_copy_count, (double)gcstat.gc.total_copy_count / (double)gcstat.gc.count); stat_notice("total forward count :%10lu #times, avg:%8.2f times", gcstat.gc.total_forward_count, (double)gcstat.gc.total_forward_count / (double)gcstat.gc.count); if (gcstat.file) fclose(gcstat.file); #endif /* GCSTAT */ #endif /* GCSTAT || GCTIME */ }
void sml_heap_free() { #ifdef PRINT_ALLOC_TIME print_and_close_file(); #endif /* PRINT_ALLOC_TIME */ free(major_heap.base); #ifdef GCTIME sml_timer_now(gcstat.exec_end); sml_timer_dif(gcstat.exec_begin, gcstat.exec_end, gcstat.exec_time); #endif /* GCTIME */ #if defined GCSTAT || defined GCTIME #ifdef GCSTAT stat_notice("---"); stat_notice("event: finish"); stat_notice("time: "TIMEFMT, TIMEARG(gcstat.exec_time)); print_alloc_count(); #endif /* GCSTAT */ stat_notice("exec time : "TIMEFMT" #sec", TIMEARG(gcstat.exec_time)); stat_notice("gc count : %u #times", gcstat.gc.count); stat_notice("gc time : "TIMEFMT" #sec (%4.2f%%)", TIMEARG(gcstat.gc.total_time), TIMEFLOAT(gcstat.gc.total_time) / TIMEFLOAT(gcstat.exec_time) * 100.0f); stat_notice("avg gc time : %.6f #sec", TIMEFLOAT(gcstat.gc.total_time) / (double)gcstat.gc.count); //#ifdef GCSTAT stat_notice("clear time : "TIMEFMT" #sec (%4.2f%%)", TIMEARG(gcstat.gc.clear_time), TIMEFLOAT(gcstat.gc.clear_time) / TIMEFLOAT(gcstat.gc.total_time) * 100.0f); stat_notice("avg clear time : %.6f #sec", TIMEFLOAT(gcstat.gc.clear_time) / (double)gcstat.gc.count); #ifdef GCSTAT if (gcstat.file) fclose(gcstat.file); #endif /* GCSTAT */ #endif /* GCSTAT || GCTIME */ }
static void do_gc(void) { #ifdef GCTIME sml_timer_t b_start, b_end; sml_time_t gctime; #endif /* GCTIME */ #ifdef GCSTAT sml_time_t t; #endif /* GCSTAT */ STOP_THE_WORLD(); #ifdef GCSTAT if (gcstat.verbose >= GCSTAT_VERBOSE_COUNT) { stat_notice("---"); stat_notice("event: start gc"); stat_notice("trigger: %u", gcstat.last.trigger); print_alloc_count(); print_heap_occupancy(); } clear_last_counts(); #endif /* GCSTAT */ #ifdef GCTIME gcstat.gc.count++; sml_timer_now(b_start); #endif /* GCTIME */ heap_space_unprotect(&sml_heap_to_space); DBG(("start gc (%lu/%lu used) %p -> %p", (unsigned long)HEAP_USED(sml_heap_from_space), (unsigned long)HEAP_TOTAL(sml_heap_from_space), sml_heap_from_space.base, sml_heap_to_space.base)); sml_rootset_enum_ptr(forward, MAJOR); DBG(("copying root completed")); /* forward objects which are reachable from live objects. */ forward_region(HEAP_START(sml_heap_to_space)); sml_malloc_pop_and_mark(forward_deep, MAJOR); #ifndef FAIR_COMPARISON /* check finalization */ sml_check_finalizer(forward_deep, MAJOR); #endif /* FAIR_COMPARISON */ /* clear from-space, and swap two spaces. */ heap_space_clear(&sml_heap_from_space); heap_space_swap(); heap_space_protect(&sml_heap_to_space); /* sweep malloc heap */ sml_malloc_sweep(MAJOR); DBG(("gc finished. remain %lu bytes", (unsigned long)HEAP_USED(sml_heap_from_space))); #ifdef GCTIME sml_timer_now(b_end); #endif /* GCTIME */ #ifdef GCTIME sml_timer_dif(b_start, b_end, gctime); sml_time_accum(gctime, gcstat.gc.total_time); #endif /* GCTIME */ #ifdef GCSTAT gcstat.gc.total_copy_bytes += gcstat.last.copy_bytes; gcstat.gc.total_copy_count += gcstat.last.copy_count; gcstat.gc.total_forward_count += gcstat.last.forward_count; if (gcstat.verbose >= GCSTAT_VERBOSE_GC) { sml_timer_dif(gcstat.exec_begin, b_start, t); stat_notice("time: "TIMEFMT, TIMEARG(t)); stat_notice("---"); stat_notice("event: end gc"); sml_timer_dif(gcstat.exec_begin, b_end, t); stat_notice("time: "TIMEFMT, TIMEARG(t)); stat_notice("duration: "TIMEFMT, TIMEARG(gctime)); stat_notice("copy: %u", gcstat.last.copy_count); stat_notice("forward: %u", gcstat.last.forward_count); stat_notice("copy_bytes: %lu", (unsigned long)gcstat.last.copy_bytes); print_heap_occupancy(); } #endif /* GCSTAT */ RUN_THE_WORLD(); }
void sml_heap_gc(void) { #ifdef GCTIME sml_timer_t b_start, b_end; sml_time_t gctime; //#endif /* GCTIME */ //#ifdef GCSTAT sml_time_t cleartime,t; sml_timer_t b_cleared; #endif /* GCSTAT */ #ifdef GCSTAT if (gcstat.verbose >= GCSTAT_VERBOSE_COUNT) { stat_notice("---"); stat_notice("event: start gc"); if (gcstat.last.trigger) stat_notice("trigger: %u", gcstat.last.trigger); print_alloc_count(); print_heap_occupancy(); } clear_last_counts(); #endif /* GCSTAT */ DBG(("start gc")); #ifdef GCTIME gcstat.gc.count++; sml_timer_now(b_start); #endif /* GCTIME */ #ifdef PRINT_ALLOC_TIME live_tmp = 0; count_gc++; double st; getRusage(st); #endif /* PRINT_ALLOC_TIME */ all_bitmaps_space_clear(); #ifdef GCTIME//GCSTAT sml_timer_now(b_cleared); #endif /* GCSTAT */ #ifdef PRINT_ALLOC_TIME double en; getRusage(en); all_time_bit_clear += (en - st); #endif /* PRINT_ALLOC_TIME */ /* mark root objects */ sml_rootset_enum_ptr(mark, MAJOR); DBG(("marking root objects completed")); /* STACK POP */ while (marking_stack.bottom != marking_stack.top) { marking_stack.top--; mark_children((*(marking_stack.top))); } sml_malloc_pop_and_mark(mark_all, MAJOR); DBG(("marking completed")); #ifdef CHECK clear_heap(); #endif /* CHECK */ /* check finalization */ sml_check_finalizer(mark_all, MAJOR); /* sweep malloc heap */ sml_malloc_sweep(MAJOR); #ifdef GCTIME sml_timer_now(b_end); #endif /* GCTIME */ DBG(("gc finished.")); #ifdef GCTIME sml_timer_dif(b_start, b_end, gctime); sml_time_accum(gctime, gcstat.gc.total_time); sml_timer_dif(b_start, b_cleared, cleartime); sml_time_accum(cleartime, gcstat.gc.clear_time); #endif #ifdef GCSTAT if (gcstat.verbose >= GCSTAT_VERBOSE_GC) { sml_timer_dif(gcstat.exec_begin, b_start, t); stat_notice("time: "TIMEFMT, TIMEARG(t)); stat_notice("---"); stat_notice("event: end gc"); sml_timer_dif(gcstat.exec_begin, b_end, t); stat_notice("time: "TIMEFMT, TIMEARG(t)); stat_notice("duration: "TIMEFMT, TIMEARG(gctime)); stat_notice("clear_time: "TIMEFMT, TIMEARG(cleartime)); stat_notice("clear_bytes: %lu", gcstat.last.clear_bytes); stat_notice("push: %u", gcstat.last.push_count); stat_notice("trace: %u", gcstat.last.trace_count); print_heap_occupancy(); } #endif /* GCSTAT */ #ifdef PRINT_ALLOC_TIME if(live_tmp > live_max) live_max = live_tmp; if(live_tmp < live_min) live_min = live_tmp; live_all += live_tmp; unsigned int i; for(i=0; i<THE_NUMBER_OF_FIXED_BLOCK; i++) { if(((print_info[i].count_mark - print_info[i].tmp_mark) * print_info[i].block_size) > print_info[i].max_live) print_info[i].max_live = ((print_info[i].count_mark - print_info[i].tmp_mark) * print_info[i].block_size); print_info[i].tmp_mark=print_info[i].count_mark; } #endif /* PRINT_ALLOC_TIME */ /* start finalizers */ sml_run_finalizer(NULL); }
void sml_heap_init(size_t size, size_t max_size ATTR_UNUSED) { #ifdef PRINT_ALLOC_TIME arranged = size; double st; getRusage(st); #endif /* PRINT_ALLOC_TIME */ void *stack_bottom; #ifdef GCSTAT { const char *env; env = getenv("SMLSHARP_GCSTAT_FILE"); if (env) { gcstat.file = fopen(env, "w"); if (gcstat.file == NULL) { perror("sml_heap_init"); abort(); } stat_notice = gcstat_print; } env = getenv("SMLSHARP_GCSTAT_VERBOSE"); if (env) gcstat.verbose = strtol(env, NULL, 10); else gcstat.verbose = GCSTAT_VERBOSE_MAX; env = getenv("SMLSHARP_GCSTAT_PROBE"); if (env) { gcstat.probe_threshold = strtol(env, NULL, 10); if (gcstat.probe_threshold == 0) gcstat.probe_threshold = size; } else { gcstat.probe_threshold = 2 * 1024 * 1024; } } #endif /* GCSTAT */ #ifdef GCTIME sml_timer_now(gcstat.exec_begin); #endif /* GCTIME */ major_heap.base = xmalloc(size); major_heap.size = size; heap_space_clear(); stack_bottom = make_bitmap_information(size); if((char *)marking_stack_init(stack_bottom) >= (char *)major_heap.limit) sml_fatal(0,"heap size over"); DBG(("heap space init %p %p %u",major_heap.base,major_heap.limit,major_heap.size)); #ifdef PRINT_ALLOC_TIME double en; getRusage(en); init_time = (en - st); fp_at = stderr; if(fp_at == NULL) sml_fatal(0,"can not open print alloc file"); print_info_init(); #endif /* PRINT_ALLOC_TIME */ #ifdef GCSTAT { unsigned int i; stat_notice("---"); stat_notice("event: init"); stat_notice("time: 0.0"); stat_notice("heap_size: %lu", (unsigned long)size); stat_notice("config:"); for (i = 0; i < THE_NUMBER_OF_FIXED_BLOCK; i++) stat_notice(" %lu: {size: %lu, num_slots: %lu, bitmap_size: %lu}", (unsigned long)bitmap_info[i].block_size_bytes, (unsigned long)heap_layout[i].total_size, (unsigned long)heap_layout[i].block_counts, (unsigned long)heap_layout[i].bitmap_and_tree_size); stat_notice("stack_size: %lu", (unsigned long)marking_stack.size); stat_notice("counters:"); stat_notice(" heap: [fast, find, next, new]"); stat_notice(" other: [malloc]"); print_heap_occupancy(); } #endif /* GCSTAT */ }
void * sml_heap_slow_alloc(size_t alloc_size) { void *obj; #ifdef PRINT_ALLOC_TIME int i; for(i=0; i<THE_NUMBER_OF_FIXED_BLOCK; i++) { if(print_info[i].block_size >= alloc_size) { print_info[i].count_gc++; break; } } #ifdef GC_TIME tmp_mark = count_call_mark - count_not_mark - count_outside; #endif /* GC_TIME */ double st; getRusage(st); #endif /* PRINT_ALLOC_TIME */ #ifdef GCSTAT { struct bitmap_info_space *b_info = MAPPING_HEAP_ALLOC(alloc_size); gcstat.last.trigger = b_info->block_size_bytes; } #endif /* GCSTAT */ sml_heap_gc(); #ifdef PRINT_ALLOC_TIME double en; getRusage(en); all_time_gc += (en - st); #ifdef GC_TIME fprintf(fp_at,"gc %f mark %u live %u alloc %u invoke_size %u\n", (en - st), (count_call_mark - count_not_mark - count_outside)-tmp_mark, live_tmp,count_alloc - tmp_alloc, alloc_size); tmp_alloc = count_alloc; #endif /* GC_TIME */ #endif /* PRINT_ALLOC_TIME */ #ifndef UPPER obj = heap_alloc(alloc_size); #else /* UPPER */ obj = heap_alloc_with_upper(alloc_size); #endif /* UPPER */ if (obj == NULL) { DBG(("alloc failed")); #ifdef GCSTAT stat_notice("---"); stat_notice("event: error"); stat_notice("heap exceeded: intented to allocate %lu bytes.", (unsigned long)alloc_size); if (gcstat.file) fclose(gcstat.file); #endif /* GCSTAT */ sml_fatal(0, "heap exceeded: intended to allocate %"PRIuMAX" bytes", (intmax_t)alloc_size); } return obj; }