diff --git a/gc.c b/gc.c index a092f387..a01b8ac8 100644 --- a/gc.c +++ b/gc.c @@ -55,12 +55,14 @@ static void **mark_stack = NULL; static int mark_stack_len = 0; static int mark_stack_i = 0; -// Lock to protect the heap from concurrent modifications -static pthread_mutex_t heap_lock; - -// Cached heap statistics -static uint64_t cached_heap_free_sizes[7] = { 0, 0, 0, 0, 0, 0, 0 }; -static uint64_t cached_heap_total_sizes[7] = { 0, 0, 0, 0, 0, 0, 0 }; +// OBSOLETE: +//// Lock to protect the heap from concurrent modifications +//static pthread_mutex_t heap_lock; +// +//// Cached heap statistics +//static uint64_t cached_heap_free_sizes[7] = { 0, 0, 0, 0, 0, 0, 0 }; +//static uint64_t cached_heap_total_sizes[7] = { 0, 0, 0, 0, 0, 0, 0 }; +//// END OBSOLETE // Data for each individual mutator thread ck_array_t Cyc_mutators, old_mutators; @@ -721,6 +723,70 @@ size_t gc_heap_total_size(gc_heap * h) // return total_size; //} +// A convenient front-end to the actual gc_sweep function. +void gc_collector_sweep() +{ + ck_array_iterator_t iterator; + gc_thread_data *m; + gc_heap *h; + int heap_type; + size_t freed_tmp = 0, freed = 0; +#if GC_DEBUG_TRACE + size_t total_size; + size_t total_free; + time_t gc_collector_start = time(NULL); +#endif + + CK_ARRAY_FOREACH(&Cyc_mutators, &iterator, &m) { + for (heap_type = 0; heap_type < NUM_HEAP_TYPES; heap_type++) { + h = m->heap->heap[heap_type]; + if (h) { + gc_sweep(h, heap_type, &freed_tmp); + freed += freed_tmp; + } + } + + // TODO: this loop only includes smallest 2 heaps, is that sufficient?? + for (heap_type = 0; heap_type < 2; heap_type++) { + while ( ck_pr_load_64(&(m->cached_heap_free_sizes[heap_type])) < + (ck_pr_load_64(&(m->cached_heap_total_sizes[heap_type])) * GC_FREE_THRESHOLD)) { +#if GC_DEBUG_TRACE + fprintf(stderr, "Less than %f%% of the heap %d is free, growing it\n", + 100.0 * GC_FREE_THRESHOLD, heap_type); +#endif + if (heap_type == HEAP_SM) { + gc_grow_heap(m->heap->heap[heap_type], heap_type, 0, 0); + } else if (heap_type == HEAP_64) { + gc_grow_heap(m->heap->heap[heap_type], heap_type, 0, 0); + } else if (heap_type == HEAP_REST) { + gc_grow_heap(m->heap->heap[heap_type], heap_type, 0, 0); + } + } + } +#if GC_DEBUG_TRACE + total_size = ck_pr_load_64(&(m->cached_heap_total_sizes[HEAP_SM])) + + ck_pr_load_64(&(m->cached_heap_total_sizes[HEAP_64])) + +#if INTPTR_MAX == INT64_MAX + ck_pr_load_64(&(m->cached_heap_total_sizes[HEAP_96])) + +#endif + ck_pr_load_64(&(m->cached_heap_total_sizes[HEAP_REST])); + total_free = ck_pr_load_64(&(m->cached_heap_free_sizes[HEAP_SM])) + + ck_pr_load_64(&(m->cached_heap_free_sizes[HEAP_64])) + +#if INTPTR_MAX == INT64_MAX + ck_pr_load_64(&(m->cached_heap_free_sizes[HEAP_96])) + +#endif + ck_pr_load_64(&(m->cached_heap_free_sizes[HEAP_REST])); + fprintf(stderr, + "sweep done, total_size = %zu, total_free = %zu, freed = %zu, elapsed = %ld\n", + total_size, total_free, freed, + (time(NULL) - gc_collector_start)); +#endif + } +#if GC_DEBUG_TRACE + fprintf(stderr, "all thread heap sweeps done\n"); +#endif +} + size_t gc_sweep(gc_heap * h, int heap_type, size_t * sum_freed_ptr) { size_t freed, max_freed = 0, heap_freed = 0, sum_freed = 0, size; @@ -1432,12 +1498,8 @@ void debug_dump_globals(); // Main collector function void gc_collector() { - int old_clear, old_mark, heap_type; - size_t freed_tmp = 0, freed = 0; + int old_clear, old_mark; #if GC_DEBUG_TRACE - size_t total_size; - size_t total_free; - time_t gc_collector_start = time(NULL); print_allocated_obj_counts(); print_current_time(); fprintf(stderr, " - Starting gc_collector\n"); @@ -1483,50 +1545,8 @@ void gc_collector() ck_pr_cas_int(&gc_stage, STAGE_TRACING, STAGE_SWEEPING); // //sweep : + gc_collector_sweep(); - for (heap_type = 0; heap_type < NUM_HEAP_TYPES; heap_type++) { - gc_heap *h = gc_get_heap()->heap[heap_type]; - if (h) { - gc_sweep(h, heap_type, &freed_tmp); - freed += freed_tmp; - } - } - - // TODO: this loop only includes smallest 2 heaps, is that sufficient?? - for (heap_type = 0; heap_type < 2; heap_type++) { - while ( ck_pr_load_64(&(cached_heap_free_sizes[heap_type])) < - (ck_pr_load_64(&(cached_heap_total_sizes[heap_type])) * GC_FREE_THRESHOLD)) { -#if GC_DEBUG_TRACE - fprintf(stderr, "Less than %f%% of the heap %d is free, growing it\n", - 100.0 * GC_FREE_THRESHOLD, heap_type); -#endif - if (heap_type == HEAP_SM) { - gc_grow_heap(gc_get_heap()->heap[heap_type], heap_type, 0, 0); - } else if (heap_type == HEAP_64) { - gc_grow_heap(gc_get_heap()->heap[heap_type], heap_type, 0, 0); - } else if (heap_type == HEAP_REST) { - gc_grow_heap(gc_get_heap()->heap[heap_type], heap_type, 0, 0); - } - } - } -#if GC_DEBUG_TRACE - total_size = ck_pr_load_64(&(cached_heap_total_sizes[HEAP_SM])) + - ck_pr_load_64(&(cached_heap_total_sizes[HEAP_64])) + -#if INTPTR_MAX == INT64_MAX - ck_pr_load_64(&(cached_heap_total_sizes[HEAP_96])) + -#endif - ck_pr_load_64(&(cached_heap_total_sizes[HEAP_REST])); - total_free = ck_pr_load_64(&(cached_heap_free_sizes[HEAP_SM])) + - ck_pr_load_64(&(cached_heap_free_sizes[HEAP_64])) + -#if INTPTR_MAX == INT64_MAX - ck_pr_load_64(&(cached_heap_free_sizes[HEAP_96])) + -#endif - ck_pr_load_64(&(cached_heap_free_sizes[HEAP_REST])); - fprintf(stderr, - "sweep done, total_size = %zu, total_free = %zu, freed = %zu, elapsed = %ld\n", - total_size, total_free, freed, - (time(NULL) - gc_collector_start)); -#endif #if GC_DEBUG_TRACE fprintf(stderr, "cleaning up any old thread data\n"); #endif @@ -1654,7 +1674,7 @@ void gc_thread_data_init(gc_thread_data * thd, int mut_num, char *stack_base, thd->heap->heap[HEAP_SM] = gc_heap_create(HEAP_SM, INITIAL_HEAP_SIZE, 0, 0); thd->heap->heap[HEAP_64] = gc_heap_create(HEAP_64, INITIAL_HEAP_SIZE, 0, 0); if (sizeof(void *) == 8) { // Only use this heap on 64-bit platforms - thd->heap[HEAP_96] = gc_heap_create(HEAP_96, INITIAL_HEAP_SIZE, 0, 0); + thd->heap->heap[HEAP_96] = gc_heap_create(HEAP_96, INITIAL_HEAP_SIZE, 0, 0); } thd->heap->heap[HEAP_HUGE] = gc_heap_create(HEAP_HUGE, 1024, 0, 0); thd->cached_heap_free_sizes = calloc(5, sizeof(uint64_t)); diff --git a/include/cyclone/types.h b/include/cyclone/types.h index af6e6090..e7e5530c 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -103,56 +103,6 @@ enum object_tag { // Define the size of object tags typedef unsigned char tag_type; -/* Threading */ -typedef enum { CYC_THREAD_STATE_NEW, CYC_THREAD_STATE_RUNNABLE, - CYC_THREAD_STATE_BLOCKED, CYC_THREAD_STATE_BLOCKED_COOPERATING, - CYC_THREAD_STATE_TERMINATED -} cyc_thread_state_type; - -/* Thread data structures */ -typedef struct gc_thread_data_t gc_thread_data; -struct gc_thread_data_t { - // Thread object, if applicable - object scm_thread_obj; - cyc_thread_state_type thread_state; - // Data needed to initiate stack-based minor GC - char *stack_start; - char *stack_limit; - // Minor GC write barrier - void **mutations; - int mutation_buflen; - int mutation_count; - // List of objects moved to heap during minor GC - void **moveBuf; - int moveBufLen; - // Need the following to perform longjmp's - //int mutator_num; - jmp_buf *jmp_start; - // After longjmp, pick up execution using continuation/arguments - object gc_cont; - object *gc_args; - short gc_num_args; - // Data needed for heap GC - int gc_alloc_color; - int gc_status; - int last_write; - int last_read; - int pending_writes; - void **mark_buffer; - int mark_buffer_len; - pthread_mutex_t lock; - pthread_t thread_id; - gc_heap_root *heap; - uint64_t *cached_heap_free_sizes; - uint64_t *cached_heap_total_sizes; - // Data needed for call history - char **stack_traces; - int stack_trace_idx; - char *stack_prev_frame; - // Exception handler stack - object exception_handler_stack; -}; - /* GC data structures */ /** @@ -233,6 +183,56 @@ typedef enum { STAGE_CLEAR_OR_MARKING, STAGE_TRACING #define gc_color_red 0 // Memory not to be GC'd, such as on the stack #define gc_color_blue 2 // Unallocated memory +/* Threading */ +typedef enum { CYC_THREAD_STATE_NEW, CYC_THREAD_STATE_RUNNABLE, + CYC_THREAD_STATE_BLOCKED, CYC_THREAD_STATE_BLOCKED_COOPERATING, + CYC_THREAD_STATE_TERMINATED +} cyc_thread_state_type; + +/* Thread data structures */ +typedef struct gc_thread_data_t gc_thread_data; +struct gc_thread_data_t { + // Thread object, if applicable + object scm_thread_obj; + cyc_thread_state_type thread_state; + // Data needed to initiate stack-based minor GC + char *stack_start; + char *stack_limit; + // Minor GC write barrier + void **mutations; + int mutation_buflen; + int mutation_count; + // List of objects moved to heap during minor GC + void **moveBuf; + int moveBufLen; + // Need the following to perform longjmp's + //int mutator_num; + jmp_buf *jmp_start; + // After longjmp, pick up execution using continuation/arguments + object gc_cont; + object *gc_args; + short gc_num_args; + // Data needed for heap GC + int gc_alloc_color; + int gc_status; + int last_write; + int last_read; + int pending_writes; + void **mark_buffer; + int mark_buffer_len; + pthread_mutex_t lock; + pthread_t thread_id; + gc_heap_root *heap; + uint64_t *cached_heap_free_sizes; + uint64_t *cached_heap_total_sizes; + // Data needed for call history + char **stack_traces; + int stack_trace_idx; + char *stack_prev_frame; + // Exception handler stack + object exception_handler_stack; +}; + // Determine if stack has overflowed #if STACK_GROWTH_IS_DOWNWARD #define stack_overflow(x,y) ((x) < (y)) @@ -707,7 +707,6 @@ void gc_mutator_thread_runnable(gc_thread_data * thd, object result); // body \ // return_thread_runnable((data), (result)); */ -gc_heap_root *gc_get_heap(); int gc_minor(void *data, object low_limit, object high_limit, closure cont, object * args, int num_args); /* Mutation table to support minor GC write barrier */ diff --git a/runtime.c b/runtime.c index 55d15ad4..32770271 100644 --- a/runtime.c +++ b/runtime.c @@ -273,11 +273,6 @@ void gc_init_heap(long heap_size) } } -gc_heap_root *gc_get_heap() -{ - return Cyc_heap; -} - object cell_get(object cell) { // FUTURE: always use unsafe car here, since computed by compiler @@ -1059,7 +1054,7 @@ object Cyc_heap_alloc_port(void *data, port_type *stack_p) { object p = NULL; int heap_grown; - p = gc_alloc(Cyc_heap, + p = gc_alloc(((gc_thread_data *)data)->heap, sizeof(port_type), (char *)stack_p, (gc_thread_data *)data, @@ -2007,7 +2002,7 @@ object Cyc_make_vector(void *data, object cont, int argc, object len, ...) // TODO: mark this thread as potentially blocking before doing // the allocation???? int heap_grown; - v = gc_alloc(Cyc_heap, + v = gc_alloc(((gc_thread_data *)data)->heap, sizeof(vector_type) + element_vec_size, boolean_f, // OK to populate manually over here (gc_thread_data *)data, @@ -4027,30 +4022,31 @@ char *gc_fixup_moved_obj(gc_thread_data * thd, int *alloci, char *obj, char *gc_move(char *obj, gc_thread_data * thd, int *alloci, int *heap_grown) { + gc_heap_root *heap = thd->heap; if (!is_object_type(obj)) return obj; switch (type_of(obj)) { case pair_tag:{ - list hp = gc_alloc(Cyc_heap, sizeof(pair_type), obj, thd, heap_grown); + list hp = gc_alloc(heap, sizeof(pair_type), obj, thd, heap_grown); return gc_fixup_moved_obj(thd, alloci, obj, hp); } case macro_tag:{ macro_type *hp = - gc_alloc(Cyc_heap, sizeof(macro_type), obj, thd, heap_grown); + gc_alloc(heap, sizeof(macro_type), obj, thd, heap_grown); return gc_fixup_moved_obj(thd, alloci, obj, hp); } case closure0_tag:{ closure0_type *hp = - gc_alloc(Cyc_heap, sizeof(closure0_type), obj, thd, heap_grown); + gc_alloc(heap, sizeof(closure0_type), obj, thd, heap_grown); return gc_fixup_moved_obj(thd, alloci, obj, hp); } case closure1_tag:{ closure1_type *hp = - gc_alloc(Cyc_heap, sizeof(closure1_type), obj, thd, heap_grown); + gc_alloc(heap, sizeof(closure1_type), obj, thd, heap_grown); return gc_fixup_moved_obj(thd, alloci, obj, hp); } case closureN_tag:{ - closureN_type *hp = gc_alloc(Cyc_heap, + closureN_type *hp = gc_alloc(heap, sizeof(closureN_type) + sizeof(object) * (((closureN) obj)->num_elements), @@ -4058,7 +4054,7 @@ char *gc_move(char *obj, gc_thread_data * thd, int *alloci, int *heap_grown) return gc_fixup_moved_obj(thd, alloci, obj, hp); } case vector_tag:{ - vector_type *hp = gc_alloc(Cyc_heap, + vector_type *hp = gc_alloc(heap, sizeof(vector_type) + sizeof(object) * (((vector) obj)->num_elements), @@ -4066,41 +4062,41 @@ char *gc_move(char *obj, gc_thread_data * thd, int *alloci, int *heap_grown) return gc_fixup_moved_obj(thd, alloci, obj, hp); } case bytevector_tag:{ - bytevector_type *hp = gc_alloc(Cyc_heap, + bytevector_type *hp = gc_alloc(heap, sizeof(bytevector_type) + sizeof(char) * (((bytevector) obj)->len), obj, thd, heap_grown); return gc_fixup_moved_obj(thd, alloci, obj, hp); } case string_tag:{ - string_type *hp = gc_alloc(Cyc_heap, + string_type *hp = gc_alloc(heap, sizeof(string_type) + ((string_len(obj) + 1)), obj, thd, heap_grown); return gc_fixup_moved_obj(thd, alloci, obj, hp); } case integer_tag:{ integer_type *hp = - gc_alloc(Cyc_heap, sizeof(integer_type), obj, thd, heap_grown); + gc_alloc(heap, sizeof(integer_type), obj, thd, heap_grown); return gc_fixup_moved_obj(thd, alloci, obj, hp); } case double_tag:{ double_type *hp = - gc_alloc(Cyc_heap, sizeof(double_type), obj, thd, heap_grown); + gc_alloc(heap, sizeof(double_type), obj, thd, heap_grown); return gc_fixup_moved_obj(thd, alloci, obj, hp); } case port_tag:{ port_type *hp = - gc_alloc(Cyc_heap, sizeof(port_type), obj, thd, heap_grown); + gc_alloc(heap, sizeof(port_type), obj, thd, heap_grown); return gc_fixup_moved_obj(thd, alloci, obj, hp); } case cvar_tag:{ cvar_type *hp = - gc_alloc(Cyc_heap, sizeof(cvar_type), obj, thd, heap_grown); + gc_alloc(heap, sizeof(cvar_type), obj, thd, heap_grown); return gc_fixup_moved_obj(thd, alloci, obj, hp); } case c_opaque_tag:{ c_opaque_type *hp = - gc_alloc(Cyc_heap, sizeof(c_opaque_type), obj, thd, heap_grown); + gc_alloc(heap, sizeof(c_opaque_type), obj, thd, heap_grown); return gc_fixup_moved_obj(thd, alloci, obj, hp); } case forward_tag: @@ -4820,7 +4816,7 @@ object copy2heap(void *data, object obj) return obj; } - return gc_alloc(Cyc_heap, gc_allocated_bytes(obj, NULL, NULL), obj, data, + return gc_alloc(((gc_thread_data *)data)->heap, gc_allocated_bytes(obj, NULL, NULL), obj, data, &on_stack); } diff --git a/srfi/18.sld b/srfi/18.sld index 94387ddc..7353a0c9 100644 --- a/srfi/18.sld +++ b/srfi/18.sld @@ -161,7 +161,7 @@ tmp.hdr.mark = gc_color_red; tmp.hdr.grayed = 0; tmp.tag = mutex_tag; - lock = gc_alloc(gc_get_heap(), sizeof(mutex_type), (char *)(&tmp), (gc_thread_data *)data, &heap_grown); + lock = gc_alloc(((gc_thread_data *)data)->heap, sizeof(mutex_type), (char *)(&tmp), (gc_thread_data *)data, &heap_grown); if (pthread_mutex_init(&(lock->lock), NULL) != 0) { fprintf(stderr, \"Unable to make mutex\\n\"); exit(1); @@ -214,7 +214,7 @@ tmp.hdr.mark = gc_color_red; tmp.hdr.grayed = 0; tmp.tag = cond_var_tag; - cond = gc_alloc(gc_get_heap(), sizeof(cond_var_type), (char *)(&tmp), (gc_thread_data *)data, &heap_grown); + cond = gc_alloc(((gc_thread_data *)data)->heap, sizeof(cond_var_type), (char *)(&tmp), (gc_thread_data *)data, &heap_grown); if (pthread_cond_init(&(cond->cond), NULL) != 0) { fprintf(stderr, \"Unable to make condition variable\\n\"); exit(1);