Author: Nicolas Truessel <ntrues...@njsm.de> Branch: quad-color-gc Changeset: r87127:a870d33012f1 Date: 2016-09-15 18:45 +0200 http://bitbucket.org/pypy/pypy/changeset/a870d33012f1/
Log: QCGC update diff --git a/rpython/translator/c/src/qcgc/config.h b/rpython/translator/c/src/qcgc/config.h --- a/rpython/translator/c/src/qcgc/config.h +++ b/rpython/translator/c/src/qcgc/config.h @@ -10,8 +10,8 @@ */ #define EVENT_LOG 1 // Enable event log #define LOGFILE "./qcgc_events.log" // Default logfile -#define LOG_ALLOCATION 0 // Enable allocation log (warning: - // significant performance impact) +#define LOG_ALLOCATION 1 // Enable allocation log +#define LOG_DUMP_FREELIST_STATS 1 // Dump freelist stats #define QCGC_SHADOWSTACK_SIZE 163840 // Total shadowstack size #define QCGC_ARENA_BAG_INIT_SIZE 16 // Initial size of the arena bag @@ -31,7 +31,7 @@ /** * Auto Mark/Collect */ -#define QCGC_INCMARK_THRESHOLD (1<<QCGC_ARENA_SIZE_EXP) +#define QCGC_INCMARK_THRESHOLD (1<<(QCGC_ARENA_SIZE_EXP-4)) #define QCGC_INCMARK_TO_SWEEP 5 /** diff --git a/rpython/translator/c/src/qcgc/qcgc.c b/rpython/translator/c/src/qcgc/qcgc.c --- a/rpython/translator/c/src/qcgc/qcgc.c +++ b/rpython/translator/c/src/qcgc/qcgc.c @@ -34,7 +34,8 @@ qcgc_state.gp_gray_stack = qcgc_gray_stack_create(16); // XXX qcgc_state.gray_stack_size = 0; qcgc_state.phase = GC_PAUSE; - qcgc_state.bytes_since_incmark = 0; + qcgc_state.cells_since_incmark = 0; + qcgc_state.cells_since_collect = 0; qcgc_state.incmark_since_sweep = 0; qcgc_state.free_cells = 0; qcgc_state.largest_free_block = 0; @@ -62,12 +63,13 @@ object_t *qcgc_allocate(size_t size) { #if LOG_ALLOCATION - qcgc_event_logger_log(EVENT_ALLOCATE_START, sizeof(size_t), - (uint8_t *) &size); + size_t cells = bytes_to_cells(size); + qcgc_event_logger_log(EVENT_ALLOCATE, sizeof(size_t), + (uint8_t *) &cells); #endif object_t *result; - if (UNLIKELY(qcgc_state.bytes_since_incmark > + if (UNLIKELY(qcgc_state.cells_since_incmark > qcgc_state.incmark_threshold)) { if (qcgc_state.incmark_since_sweep == qcgc_state.incmark_to_sweep) { qcgc_collect(); @@ -75,13 +77,11 @@ qcgc_incmark(); qcgc_state.incmark_since_sweep++; } - } if (LIKELY(size <= 1<<QCGC_LARGE_ALLOC_THRESHOLD_EXP)) { // Use bump / fit allocator - //if (qcgc_allocator_state.use_bump_allocator) { - if (false) { + if (qcgc_allocator_state.use_bump_allocator) { result = bump_allocate(size); } else { result = qcgc_fit_allocate(size); @@ -91,19 +91,13 @@ result = bump_allocate(size); } } + qcgc_state.free_cells -= bytes_to_cells(size); } else { // Use huge block allocator result = qcgc_large_allocate(size); } - - // XXX: Should we use cells instead of bytes? - qcgc_state.bytes_since_incmark += size; - - -#if LOG_ALLOCATION - qcgc_event_logger_log(EVENT_ALLOCATE_DONE, sizeof(object_t *), - (uint8_t *) &result); -#endif + qcgc_state.cells_since_incmark += bytes_to_cells(size); + qcgc_state.cells_since_collect += bytes_to_cells(size); return result; } diff --git a/rpython/translator/c/src/qcgc/src/allocator.c b/rpython/translator/c/src/qcgc/src/allocator.c --- a/rpython/translator/c/src/qcgc/src/allocator.c +++ b/rpython/translator/c/src/qcgc/src/allocator.c @@ -2,9 +2,7 @@ #include <assert.h> #include <stdbool.h> -#include <stdlib.h> - -#include "hugeblocktable.h" +#include "gc_state.h" QCGC_STATIC QCGC_INLINE void bump_allocator_assign(cell_t *ptr, size_t cells); @@ -65,25 +63,6 @@ free(qcgc_allocator_state.free_arenas); } -void qcgc_fit_allocator_add(cell_t *ptr, size_t cells) { -#if CHECKED - assert(cells > 0); -#endif - if (is_small(cells)) { - size_t index = small_index(cells); - qcgc_allocator_state.fit_state.small_free_list[index] = - qcgc_linear_free_list_add( - qcgc_allocator_state.fit_state.small_free_list[index], - ptr); - } else { - size_t index = large_index(cells); - qcgc_allocator_state.fit_state.large_free_list[index] = - qcgc_exp_free_list_add( - qcgc_allocator_state.fit_state.large_free_list[index], - (struct exp_free_list_item_s) {ptr, cells}); - } -} - /******************************************************************************* * Bump Allocator * ******************************************************************************/ @@ -124,6 +103,8 @@ } else { // Grab a new arena arena_t *arena = qcgc_arena_create(); + qcgc_state.free_cells += QCGC_ARENA_CELLS_COUNT - + QCGC_ARENA_FIRST_CELL_INDEX; bump_allocator_assign(&(arena->cells[QCGC_ARENA_FIRST_CELL_INDEX]), QCGC_ARENA_CELLS_COUNT - QCGC_ARENA_FIRST_CELL_INDEX); qcgc_allocator_state.arenas = @@ -163,6 +144,10 @@ qcgc_allocator_state.bump_state.remaining_cells = cells; } +/******************************************************************************* + * Fit Allocator * + ******************************************************************************/ + object_t *qcgc_fit_allocate(size_t bytes) { #if CHECKED //free_list_consistency_check(); @@ -192,23 +177,6 @@ return result; } -/** - * Constraints: - * - Zero initialized - * - Aligned to arena size - * - Multiple of arena size - * - No header, metadata stored in hash-map - */ -object_t *qcgc_large_allocate(size_t bytes) { - object_t *result = aligned_alloc(QCGC_ARENA_SIZE, bytes); -#if QCGC_INIT_ZERO - memset(result, 0, bytes); -#endif - qcgc_hbtable_insert(result); - result->flags = QCGC_GRAY_FLAG; - return result; -} - void qcgc_fit_allocator_empty_lists(void) { for (size_t i = 0; i < QCGC_SMALL_FREE_LISTS; i++) { qcgc_allocator_state.fit_state.small_free_list[i]->count = 0; @@ -219,6 +187,25 @@ } } +void qcgc_fit_allocator_add(cell_t *ptr, size_t cells) { +#if CHECKED + assert(cells > 0); +#endif + if (is_small(cells)) { + size_t index = small_index(cells); + qcgc_allocator_state.fit_state.small_free_list[index] = + qcgc_linear_free_list_add( + qcgc_allocator_state.fit_state.small_free_list[index], + ptr); + } else { + size_t index = large_index(cells); + qcgc_allocator_state.fit_state.large_free_list[index] = + qcgc_exp_free_list_add( + qcgc_allocator_state.fit_state.large_free_list[index], + (struct exp_free_list_item_s) {ptr, cells}); + } +} + QCGC_STATIC cell_t *fit_allocator_small_first_fit(size_t index, size_t cells) { #if CHECKED assert(small_index_to_cells(index) >= cells); @@ -321,18 +308,18 @@ return NULL; } -QCGC_STATIC bool is_small(size_t cells) { +QCGC_STATIC QCGC_INLINE bool is_small(size_t cells) { return cells <= QCGC_SMALL_FREE_LISTS; } -QCGC_STATIC size_t small_index(size_t cells) { +QCGC_STATIC QCGC_INLINE size_t small_index(size_t cells) { #if CHECKED assert(is_small(cells)); #endif return cells - 1; } -QCGC_STATIC size_t large_index(size_t cells) { +QCGC_STATIC QCGC_INLINE size_t large_index(size_t cells) { #if CHECKED assert(!is_small(cells)); #endif @@ -341,10 +328,11 @@ cells = cells >> QCGC_LARGE_FREE_LIST_FIRST_EXP; // calculates floor(log(cells)) - return MIN((8 * sizeof(unsigned long)) - __builtin_clzl(cells) - 1, QCGC_LARGE_FREE_LISTS - 1); + return MIN((8 * sizeof(unsigned long)) - __builtin_clzl(cells) - 1, + QCGC_LARGE_FREE_LISTS - 1); } -QCGC_STATIC size_t small_index_to_cells(size_t index) { +QCGC_STATIC QCGC_INLINE size_t small_index_to_cells(size_t index) { #if CHECKED assert(index < QCGC_SMALL_FREE_LISTS); #endif diff --git a/rpython/translator/c/src/qcgc/src/allocator.h b/rpython/translator/c/src/qcgc/src/allocator.h --- a/rpython/translator/c/src/qcgc/src/allocator.h +++ b/rpython/translator/c/src/qcgc/src/allocator.h @@ -3,9 +3,11 @@ #include "../qcgc.h" #include <string.h> +#include <stdlib.h> #include "arena.h" #include "bag.h" +#include "hugeblocktable.h" /** * Free lists: @@ -71,15 +73,6 @@ object_t *qcgc_fit_allocate(size_t bytes); /** - * Allocate new memory region using huge block allocator - * - * @param bytes Desired size of the memory region in bytes - * @return Pointer to memory large enough to hold size bytes, NULL in case of - * errors, already zero initialized if QCGC_INIT_ZERO is set - */ -object_t *qcgc_large_allocate(size_t bytes); - -/** * Empty all free lists (used before sweep) */ void qcgc_fit_allocator_empty_lists(void); @@ -131,3 +124,20 @@ result->flags = QCGC_GRAY_FLAG; return result; } + +/** + * Allocate new memory region using huge block allocator + * + * @param bytes Desired size of the memory region in bytes + * @return Pointer to memory large enough to hold size bytes, NULL in case of + * errors, already zero initialized if QCGC_INIT_ZERO is set + */ +QCGC_STATIC QCGC_INLINE object_t *qcgc_large_allocate(size_t bytes) { + object_t *result = aligned_alloc(QCGC_ARENA_SIZE, bytes); +#if QCGC_INIT_ZERO + memset(result, 0, bytes); +#endif + qcgc_hbtable_insert(result); + result->flags = QCGC_GRAY_FLAG; + return result; +} diff --git a/rpython/translator/c/src/qcgc/src/collector.c b/rpython/translator/c/src/qcgc/src/collector.c --- a/rpython/translator/c/src/qcgc/src/collector.c +++ b/rpython/translator/c/src/qcgc/src/collector.c @@ -14,7 +14,7 @@ void qcgc_mark(void) { mark_setup(false); - + while (qcgc_state.gray_stack_size > 0) { // General purpose gray stack (prebuilt objects and huge blocks) @@ -94,7 +94,7 @@ (uint8_t *) &log_info); } - qcgc_state.bytes_since_incmark = 0; + qcgc_state.cells_since_incmark = 0; if (qcgc_state.phase == GC_PAUSE) { @@ -186,10 +186,16 @@ assert(qcgc_state.phase == GC_COLLECT); #endif { - unsigned long arena_count; - arena_count = qcgc_allocator_state.arenas->count; - qcgc_event_logger_log(EVENT_SWEEP_START, sizeof(arena_count), - (uint8_t *) &arena_count); + struct log_info_s { + size_t arenas; + size_t free_cells; + }; + struct log_info_s log_info = { + qcgc_allocator_state.arenas->count, + qcgc_state.free_cells, + }; + qcgc_event_logger_log(EVENT_SWEEP_START, sizeof(struct log_info_s), + (uint8_t *) &log_info); } qcgc_hbtable_sweep(); @@ -218,22 +224,75 @@ // Determine whether fragmentation is too high // Fragmenation = 1 - (largest block / total free space) // Use bump allocator when fragmentation < 50% +#if CHECKED + size_t free_cells = 0; + size_t largest_free_block = 0; + for (size_t i = 0; i < QCGC_SMALL_FREE_LISTS; i++) { + if (qcgc_allocator_state.fit_state.small_free_list[i]->count > 0) { + largest_free_block = i + 1; + } + free_cells += qcgc_allocator_state.fit_state.small_free_list[i] + ->count * (i + 1); + } + for (size_t i = 0; i < QCGC_LARGE_FREE_LISTS; i++) { + for (size_t j = 0; j < qcgc_allocator_state.fit_state. + large_free_list[i]->count; j++) { + free_cells += qcgc_allocator_state.fit_state.large_free_list[i] + ->items[j].size; + largest_free_block = MAX(largest_free_block, + qcgc_allocator_state.fit_state.large_free_list[i] + ->items[j].size); + } + } + assert(free_cells == qcgc_state.free_cells); + assert(largest_free_block == qcgc_state.largest_free_block); + assert(free_cells <= qcgc_allocator_state.arenas->count * (QCGC_ARENA_CELLS_COUNT - QCGC_ARENA_FIRST_CELL_INDEX)); + assert(qcgc_allocator_state.arenas->count * + (QCGC_ARENA_CELLS_COUNT - QCGC_ARENA_FIRST_CELL_INDEX) >= + free_cells); +#endif qcgc_allocator_state.use_bump_allocator = qcgc_state.free_cells < 2 * qcgc_state.largest_free_block; update_weakrefs(); + qcgc_state.free_cells += qcgc_allocator_state.bump_state.remaining_cells; { struct log_info_s { + size_t arenas; size_t free_cells; size_t largest_free_block; }; struct log_info_s log_info = { + qcgc_allocator_state.arenas->count, qcgc_state.free_cells, qcgc_state.largest_free_block }; qcgc_event_logger_log(EVENT_SWEEP_DONE, sizeof(struct log_info_s), (uint8_t *) &log_info); } +#if LOG_DUMP_FREELIST_STATS + { + struct log_info_s { + size_t class; + size_t items; + }; + struct log_info_s log_info; + + for (size_t i = 0; i < QCGC_SMALL_FREE_LISTS; i++) { + log_info = (struct log_info_s){ i + 1, + qcgc_allocator_state.fit_state.small_free_list[i]->count}; + qcgc_event_logger_log(EVENT_FREELIST_DUMP, + sizeof(struct log_info_s), (uint8_t *) &log_info); + } + for (size_t i = 0; i < QCGC_LARGE_FREE_LISTS; i++) { + log_info = (struct log_info_s){ + 1<<(QCGC_LARGE_FREE_LIST_FIRST_EXP + i), + qcgc_allocator_state.fit_state.large_free_list[i]->count}; + qcgc_event_logger_log(EVENT_FREELIST_DUMP, + sizeof(struct log_info_s), (uint8_t *) &log_info); + } + } +#endif } diff --git a/rpython/translator/c/src/qcgc/src/event_logger.h b/rpython/translator/c/src/qcgc/src/event_logger.h --- a/rpython/translator/c/src/qcgc/src/event_logger.h +++ b/rpython/translator/c/src/qcgc/src/event_logger.h @@ -15,13 +15,14 @@ EVENT_SWEEP_START, EVENT_SWEEP_DONE, - EVENT_ALLOCATE_START, - EVENT_ALLOCATE_DONE, // = 5 + EVENT_ALLOCATE, - EVENT_NEW_ARENA, + EVENT_NEW_ARENA, // = 5 EVENT_MARK_START, EVENT_MARK_DONE, + + EVENT_FREELIST_DUMP, }; /** diff --git a/rpython/translator/c/src/qcgc/src/gc_state.h b/rpython/translator/c/src/qcgc/src/gc_state.h --- a/rpython/translator/c/src/qcgc/src/gc_state.h +++ b/rpython/translator/c/src/qcgc/src/gc_state.h @@ -33,7 +33,8 @@ size_t gray_stack_size; gc_phase_t phase; - size_t bytes_since_incmark; + size_t cells_since_incmark; + size_t cells_since_collect; size_t incmark_since_sweep; size_t incmark_threshold; size_t incmark_to_sweep; _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit