mirror of
https://github.com/justinethier/cyclone.git
synced 2025-05-19 05:39:17 +02:00
WIP
This commit is contained in:
parent
0d651d4ff7
commit
ce0bffb31a
4 changed files with 144 additions and 129 deletions
130
gc.c
130
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));
|
||||
|
|
|
@ -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 */
|
||||
|
|
38
runtime.c
38
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue