mirror of
https://github.com/justinethier/cyclone.git
synced 2025-05-24 20:45:06 +02:00
Populate huge object heap
This commit is contained in:
parent
54f217fd4b
commit
f526eeb6f3
3 changed files with 35 additions and 18 deletions
43
gc.c
43
gc.c
|
@ -59,8 +59,8 @@ static int mark_stack_i = 0;
|
||||||
static pthread_mutex_t heap_lock;
|
static pthread_mutex_t heap_lock;
|
||||||
|
|
||||||
// Cached heap statistics
|
// Cached heap statistics
|
||||||
static int cached_heap_free_sizes[3] = { 0, 0, 0 };
|
static int cached_heap_free_sizes[4] = { 0, 0, 0, 0 };
|
||||||
static int cached_heap_total_sizes[3] = { 0, 0, 0 };
|
static int cached_heap_total_sizes[4] = { 0, 0, 0, 0 };
|
||||||
|
|
||||||
// Data for each individual mutator thread
|
// Data for each individual mutator thread
|
||||||
ck_array_t Cyc_mutators, old_mutators;
|
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);
|
heap_is_empty = gc_is_heap_empty(h);
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Heap page size=%u, is empty=%d, used=%u, free=%u, free chunks=%u, min=%u, max=%u\n",
|
"Heap type=%d, 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);
|
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;
|
gc_heap *h_last, *h_new;
|
||||||
pthread_mutex_lock(&heap_lock);
|
pthread_mutex_lock(&heap_lock);
|
||||||
// Compute size of new heap page
|
// Compute size of new heap page
|
||||||
// experimental code for growing heap gradually using fibonnaci sequence.
|
if (heap_type == HEAP_HUGE) {
|
||||||
// but with boyer benchmarks there is more thrashing with this method,
|
new_size = size;
|
||||||
// so for now it is not used. If it is used again, the initial heaps will
|
} else {
|
||||||
// need to start at a lower size (EG 1 MB).
|
// Grow heap gradually using fibonnaci sequence.
|
||||||
{
|
|
||||||
size_t prev_size = GROW_HEAP_BY_SIZE;
|
size_t prev_size = GROW_HEAP_BY_SIZE;
|
||||||
new_size = 0;
|
new_size = 0;
|
||||||
h_last = h;
|
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) {
|
} else if (size <= 64) {
|
||||||
h = hrt->medium_obj_heap;
|
h = hrt->medium_obj_heap;
|
||||||
heap_type = HEAP_MED;
|
heap_type = HEAP_MED;
|
||||||
|
} else if (size >= MAX_STACK_OBJ) {
|
||||||
|
h = hrt->huge_obj_heap;
|
||||||
|
heap_type = HEAP_HUGE;
|
||||||
} else {
|
} else {
|
||||||
h = hrt->heap;
|
h = hrt->heap;
|
||||||
heap_type = HEAP_REST;
|
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);
|
pthread_mutex_lock(&heap_lock);
|
||||||
|
|
||||||
// DEBUGGING:
|
#if GC_DEBUG_SHOW_SWEEP_DIAG
|
||||||
//fprintf(stderr, "\nBefore sweep -------------------------\n");
|
fprintf(stderr, "\nBefore sweep -------------------------\n");
|
||||||
//fprintf(stderr, "Heap %d diagnostics:\n", heap_type);
|
fprintf(stderr, "Heap %d diagnostics:\n", heap_type);
|
||||||
//gc_print_stats(orig_heap_ptr);
|
gc_print_stats(orig_heap_ptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
for (; h; prev_h = h, h = h->next) { // All heaps
|
for (; h; prev_h = h, h = h->next) { // All heaps
|
||||||
#if GC_DEBUG_TRACE
|
#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;
|
//h->free_size += heap_freed;
|
||||||
cached_heap_free_sizes[heap_type] += 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)){
|
// if (gc_is_heap_empty(h)){
|
||||||
// unsigned int h_size = h->size;
|
// unsigned int h_size = h->size;
|
||||||
// gc_heap_free(h, prev_h);
|
// 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;
|
heap_freed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEBUGGING:
|
#if GC_DEBUG_SHOW_SWEEP_DIAG
|
||||||
//fprintf(stderr, "\nAfter sweep -------------------------\n");
|
fprintf(stderr, "\nAfter sweep -------------------------\n");
|
||||||
//fprintf(stderr, "Heap %d diagnostics:\n", heap_type);
|
fprintf(stderr, "Heap %d diagnostics:\n", heap_type);
|
||||||
//gc_print_stats(orig_heap_ptr);
|
gc_print_stats(orig_heap_ptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
pthread_mutex_unlock(&heap_lock);
|
pthread_mutex_unlock(&heap_lock);
|
||||||
if (sum_freed_ptr)
|
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()->heap, HEAP_REST, &freed);
|
||||||
max_freed = gc_sweep(gc_get_heap()->small_obj_heap, HEAP_SM, &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()->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++) {
|
for (heap_type = 0; heap_type < 2; heap_type++) {
|
||||||
while (cached_heap_free_sizes[heap_type] <
|
while (cached_heap_free_sizes[heap_type] <
|
||||||
(cached_heap_total_sizes[heap_type] * GC_FREE_THRESHOLD)) {
|
(cached_heap_total_sizes[heap_type] * GC_FREE_THRESHOLD)) {
|
||||||
|
|
|
@ -28,6 +28,9 @@
|
||||||
// This is used as the first generation of the GC.
|
// This is used as the first generation of the GC.
|
||||||
#define STACK_SIZE 500000
|
#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.
|
// 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 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
|
#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
|
// Show diagnostic information for the GC when program terminates
|
||||||
#define DEBUG_SHOW_DIAG 0
|
#define DEBUG_SHOW_DIAG 0
|
||||||
|
|
||||||
|
// Show diagnostic information before/after sweeping
|
||||||
|
#define GC_DEBUG_SHOW_SWEEP_DIAG 1
|
||||||
|
|
||||||
// GC debugging flags
|
// GC debugging flags
|
||||||
#define GC_DEBUG_TRACE 0
|
#define GC_DEBUG_TRACE 0
|
||||||
#define GC_DEBUG_VERBOSE 0
|
#define GC_DEBUG_VERBOSE 0
|
||||||
|
@ -149,8 +155,8 @@ struct gc_thread_data_t {
|
||||||
typedef enum {
|
typedef enum {
|
||||||
HEAP_SM = 0 // 32 byte objects (min gc_heap_align)
|
HEAP_SM = 0 // 32 byte objects (min gc_heap_align)
|
||||||
, HEAP_MED // 64 byte objects (twice the min)
|
, HEAP_MED // 64 byte objects (twice the min)
|
||||||
, HEAP_HUGE // Huge objects, 1 per page
|
|
||||||
, HEAP_REST // Everything else
|
, HEAP_REST // Everything else
|
||||||
|
, HEAP_HUGE // Huge objects, 1 per page
|
||||||
} gc_heap_type;
|
} gc_heap_type;
|
||||||
|
|
||||||
typedef struct gc_free_list_t gc_free_list;
|
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 {
|
struct gc_heap_root_t {
|
||||||
gc_heap *small_obj_heap;
|
gc_heap *small_obj_heap;
|
||||||
gc_heap *medium_obj_heap;
|
gc_heap *medium_obj_heap;
|
||||||
|
gc_heap *huge_obj_heap;
|
||||||
gc_heap *heap;
|
gc_heap *heap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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->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->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->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,
|
if (!ck_hs_init(&symbol_table,
|
||||||
CK_HS_MODE_OBJECT | CK_HS_MODE_SPMC,
|
CK_HS_MODE_OBJECT | CK_HS_MODE_SPMC,
|
||||||
|
|
Loading…
Add table
Reference in a new issue