Populate huge object heap

This commit is contained in:
Justin Ethier 2016-07-06 23:07:43 -04:00
parent 54f217fd4b
commit f526eeb6f3
3 changed files with 35 additions and 18 deletions

43
gc.c
View file

@ -59,8 +59,8 @@ static int mark_stack_i = 0;
static pthread_mutex_t heap_lock;
// Cached heap statistics
static int cached_heap_free_sizes[3] = { 0, 0, 0 };
static int cached_heap_total_sizes[3] = { 0, 0, 0 };
static int cached_heap_free_sizes[4] = { 0, 0, 0, 0 };
static int cached_heap_total_sizes[4] = { 0, 0, 0, 0 };
// Data for each individual mutator thread
ck_array_t Cyc_mutators, old_mutators;
@ -269,8 +269,8 @@ void gc_print_stats(gc_heap * h)
}
heap_is_empty = gc_is_heap_empty(h);
fprintf(stderr,
"Heap page size=%u, is empty=%d, used=%u, free=%u, free chunks=%u, min=%u, max=%u\n",
h->size, heap_is_empty, h->size - free, free, free_chunks, free_min, free_max);
"Heap type=%d, page size=%u, is empty=%d, used=%u, free=%u, free chunks=%u, min=%u, max=%u\n",
h->type, h->size, heap_is_empty, h->size - free, free, free_chunks, free_min, free_max);
}
}
@ -432,11 +432,10 @@ int gc_grow_heap(gc_heap * h, int heap_type, size_t size, size_t chunk_size)
gc_heap *h_last, *h_new;
pthread_mutex_lock(&heap_lock);
// Compute size of new heap page
// experimental code for growing heap gradually using fibonnaci sequence.
// but with boyer benchmarks there is more thrashing with this method,
// so for now it is not used. If it is used again, the initial heaps will
// need to start at a lower size (EG 1 MB).
{
if (heap_type == HEAP_HUGE) {
new_size = size;
} else {
// Grow heap gradually using fibonnaci sequence.
size_t prev_size = GROW_HEAP_BY_SIZE;
new_size = 0;
h_last = h;
@ -527,6 +526,9 @@ void *gc_alloc(gc_heap_root * hrt, size_t size, char *obj, gc_thread_data * thd,
} else if (size <= 64) {
h = hrt->medium_obj_heap;
heap_type = HEAP_MED;
} else if (size >= MAX_STACK_OBJ) {
h = hrt->huge_obj_heap;
heap_type = HEAP_HUGE;
} else {
h = hrt->heap;
heap_type = HEAP_REST;
@ -661,10 +663,11 @@ size_t gc_sweep(gc_heap * h, int heap_type, size_t * sum_freed_ptr)
//
pthread_mutex_lock(&heap_lock);
// DEBUGGING:
//fprintf(stderr, "\nBefore sweep -------------------------\n");
//fprintf(stderr, "Heap %d diagnostics:\n", heap_type);
//gc_print_stats(orig_heap_ptr);
#if GC_DEBUG_SHOW_SWEEP_DIAG
fprintf(stderr, "\nBefore sweep -------------------------\n");
fprintf(stderr, "Heap %d diagnostics:\n", heap_type);
gc_print_stats(orig_heap_ptr);
#endif
for (; h; prev_h = h, h = h->next) { // All heaps
#if GC_DEBUG_TRACE
@ -765,6 +768,9 @@ size_t gc_sweep(gc_heap * h, int heap_type, size_t * sum_freed_ptr)
}
//h->free_size += heap_freed;
cached_heap_free_sizes[heap_type] += heap_freed;
// TODO: with huge heaps, this becomes more important. one of the huge
// pages only has one object, so it is likely that the page
// will become free at some point and could be reclaimed.
// if (gc_is_heap_empty(h)){
// unsigned int h_size = h->size;
// gc_heap_free(h, prev_h);
@ -775,10 +781,11 @@ size_t gc_sweep(gc_heap * h, int heap_type, size_t * sum_freed_ptr)
heap_freed = 0;
}
// DEBUGGING:
//fprintf(stderr, "\nAfter sweep -------------------------\n");
//fprintf(stderr, "Heap %d diagnostics:\n", heap_type);
//gc_print_stats(orig_heap_ptr);
#if GC_DEBUG_SHOW_SWEEP_DIAG
fprintf(stderr, "\nAfter sweep -------------------------\n");
fprintf(stderr, "Heap %d diagnostics:\n", heap_type);
gc_print_stats(orig_heap_ptr);
#endif
pthread_mutex_unlock(&heap_lock);
if (sum_freed_ptr)
@ -1340,7 +1347,9 @@ void gc_collector()
max_freed = gc_sweep(gc_get_heap()->heap, HEAP_REST, &freed);
max_freed = gc_sweep(gc_get_heap()->small_obj_heap, HEAP_SM, &freed);
max_freed = gc_sweep(gc_get_heap()->medium_obj_heap, HEAP_MED, &freed);
max_freed = gc_sweep(gc_get_heap()->huge_obj_heap, HEAP_HUGE, &freed);
// TODO: this loop only includes smallest 2 heaps, is that sufficient??
for (heap_type = 0; heap_type < 2; heap_type++) {
while (cached_heap_free_sizes[heap_type] <
(cached_heap_total_sizes[heap_type] * GC_FREE_THRESHOLD)) {

View file

@ -28,6 +28,9 @@
// This is used as the first generation of the GC.
#define STACK_SIZE 500000
// Do not allocate objects larger than this on the stack.
#define MAX_STACK_OBJ (STACK_SIZE * 2)
// Parameters for size of a "page" on the heap (the second generation GC), in bytes.
#define GROW_HEAP_BY_SIZE (2 * 1024 * 1024) // Grow first page by adding this amount to it
#define INITIAL_HEAP_SIZE (3 * 1024 * 1024) // Size of the first page
@ -50,6 +53,9 @@
// Show diagnostic information for the GC when program terminates
#define DEBUG_SHOW_DIAG 0
// Show diagnostic information before/after sweeping
#define GC_DEBUG_SHOW_SWEEP_DIAG 1
// GC debugging flags
#define GC_DEBUG_TRACE 0
#define GC_DEBUG_VERBOSE 0
@ -149,8 +155,8 @@ struct gc_thread_data_t {
typedef enum {
HEAP_SM = 0 // 32 byte objects (min gc_heap_align)
, HEAP_MED // 64 byte objects (twice the min)
, HEAP_HUGE // Huge objects, 1 per page
, HEAP_REST // Everything else
, HEAP_HUGE // Huge objects, 1 per page
} gc_heap_type;
typedef struct gc_free_list_t gc_free_list;
@ -175,6 +181,7 @@ typedef struct gc_heap_root_t gc_heap_root;
struct gc_heap_root_t {
gc_heap *small_obj_heap;
gc_heap *medium_obj_heap;
gc_heap *huge_obj_heap;
gc_heap *heap;
};

View file

@ -190,6 +190,7 @@ void gc_init_heap(long heap_size)
Cyc_heap->heap = gc_heap_create(HEAP_REST, initial_heap_size, 0, 0);
Cyc_heap->small_obj_heap = gc_heap_create(HEAP_SM, initial_heap_size, 0, 0);
Cyc_heap->medium_obj_heap = gc_heap_create(HEAP_MED, initial_heap_size, 0, 0);
Cyc_heap->huge_obj_heap = gc_heap_create(HEAP_HUGE, 1024, 0, 0);
if (!ck_hs_init(&symbol_table,
CK_HS_MODE_OBJECT | CK_HS_MODE_SPMC,