This commit is contained in:
Justin Ethier 2017-01-26 23:45:46 -05:00
parent 0d651d4ff7
commit ce0bffb31a
4 changed files with 144 additions and 129 deletions

130
gc.c
View file

@ -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));

View file

@ -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 */

View file

@ -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);
}

View file

@ -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);