Cut over to new mark buffer data structure

This commit is contained in:
Justin Ethier 2018-06-11 13:30:02 -04:00
parent b4f4c9a182
commit 9e94d4ee46
2 changed files with 73 additions and 15 deletions

78
gc.c
View file

@ -97,6 +97,64 @@ static struct ck_malloc my_allocator = {
.realloc = my_realloc
};
/** Mark buffers
*
* For these, we need a buffer than can grow as needed but that can also be
* used concurrently by both a mutator thread and a collector thread.
*/
static mark_buffer *mark_buffer_init(unsigned initial_size)
{
mark_buffer *mb = malloc(sizeof(mark_buffer));
mb->buf = malloc(sizeof(void *) * initial_size);
mb->buf_len = initial_size;
mb->next = NULL;
return mb;
}
static void *mark_buffer_get(mark_buffer *mb, unsigned i) // TODO: macro?
{
while (i >= mb->buf_len) {
// Not on this page, try the next one
i -= mb->buf_len;
mb = mb->next;
if (mb == NULL) { // Safety check
// For now this is a fatal error, could return NULL instead
fprintf(stderr, "mark_buffer_get ran out of mark buffers, exiting\n");
exit(1);
}
}
return mb->buf[i];
}
static void mark_buffer_set(mark_buffer *mb, unsigned i, void *obj)
{
// Find index i
while (i >= mb->buf_len) {
// Not on this page, try the next one
i -= mb->buf_len;
if (mb->next == NULL) {
// If it does not exist, allocate a new buffer
mb->next = mark_buffer_init(mb->buf_len * 2);
}
mb = mb->next;
}
mb->buf[i] = obj;
}
static void mark_buffer_free(mark_buffer *mb)
{
mark_buffer *next;
while (mb) {
next = mb->next;
free(mb->buf);
free(mb);
mb = next;
}
}
// END mark buffer
#if GC_DEBUG_TRACE
const int NUM_ALLOC_SIZES = 10;
static double allocated_size_counts[10] = {
@ -1605,9 +1663,7 @@ void gc_mark_gray(gc_thread_data * thd, object obj)
// Note that ideally this should be a lock-free data structure to make the
// algorithm more efficient. So this code (and the corresponding collector
// trace code) should be converted at some point.
thd->mark_buffer = vpbuffer_add(thd->mark_buffer,
&(thd->mark_buffer_len),
thd->last_write, obj);
mark_buffer_set(thd->mark_buffer, thd->last_write, obj);
(thd->last_write)++; // Already locked, just do it...
}
}
@ -1626,10 +1682,7 @@ void gc_mark_gray(gc_thread_data * thd, object obj)
void gc_mark_gray2(gc_thread_data * thd, object obj)
{
if (is_object_type(obj) && mark(obj) == gc_color_clear) {
thd->mark_buffer = vpbuffer_add(thd->mark_buffer,
&(thd->mark_buffer_len),
(thd->last_write + thd->pending_writes),
obj);
mark_buffer_set(thd->mark_buffer, thd->last_write + thd->pending_writes, obj);
thd->pending_writes++;
}
}
@ -1789,9 +1842,9 @@ void gc_collector_trace()
#if GC_DEBUG_VERBOSE
fprintf(stderr,
"gc_mark_black mark buffer %p, last_read = %d last_write = %d\n",
(m->mark_buffer)[m->last_read], m->last_read, m->last_write);
mark_buffer_get(m->mark_buffer, m->last_read), m->last_read, m->last_write);
#endif
gc_mark_black((m->mark_buffer)[m->last_read]);
gc_mark_black(mark_buffer_get(m->mark_buffer, m->last_read));
gc_empty_collector_stack();
(m->last_read)++; // Inc here to prevent off-by-one error
}
@ -2151,10 +2204,7 @@ void gc_thread_data_init(gc_thread_data * thd, int mut_num, char *stack_base,
thd->pending_writes = 0;
thd->last_write = 0;
thd->last_read = 0;
thd->mark_buffer = NULL;
thd->mark_buffer_len = 128;
thd->mark_buffer =
vpbuffer_realloc(thd->mark_buffer, &(thd->mark_buffer_len));
thd->mark_buffer = mark_buffer_init(128);
if (pthread_mutex_init(&(thd->heap_lock), NULL) != 0) {
fprintf(stderr, "Unable to initialize thread mutex\n");
exit(1);
@ -2215,7 +2265,7 @@ void gc_thread_data_free(gc_thread_data * thd)
if (thd->moveBuf)
free(thd->moveBuf);
if (thd->mark_buffer)
free(thd->mark_buffer);
mark_buffer_free(thd->mark_buffer);
if (thd->stack_traces)
free(thd->stack_traces);
if (thd->mutations) {

View file

@ -246,6 +246,14 @@ typedef enum { STAGE_CLEAR_OR_MARKING, STAGE_TRACING
/** Unallocated memory */
#define gc_color_blue 2
/** Mark buffers */
typedef struct mark_buffer_t mark_buffer;
struct mark_buffer_t {
void **buf;
unsigned buf_len;
mark_buffer *next;
};
/** Threading */
typedef enum { CYC_THREAD_STATE_NEW, CYC_THREAD_STATE_RUNNABLE,
CYC_THREAD_STATE_BLOCKED, CYC_THREAD_STATE_BLOCKED_COOPERATING,
@ -287,7 +295,7 @@ struct gc_thread_data_t {
int last_write;
int last_read;
int pending_writes;
void **mark_buffer;
mark_buffer *mark_buffer;
int mark_buffer_len;
pthread_mutex_t lock;
pthread_mutex_t heap_lock;