diff --git a/src/gc/alloc_resources.c b/src/gc/alloc_resources.c index cd96ffb..6930bb8 100644 --- a/src/gc/alloc_resources.c +++ b/src/gc/alloc_resources.c @@ -321,8 +321,11 @@ mem_allocate(PARROT_INTERP, * TODO pass required allocation size to the GC system, * so that collection can be skipped if needed */ + size_t new_mem = mem_pools->memory_used - + mem_pools->mem_used_last_collect; if (!mem_pools->gc_mark_block_level - && mem_pools->mem_allocs_since_last_collect) { + && new_mem > (mem_pools->mem_used_last_collect >> 1) + && new_mem > GC_SIZE_THRESHOLD) { Parrot_gc_mark_and_sweep(interp, GC_trace_stack_FLAG); if (interp->gc_sys->sys_type != INF) { @@ -360,6 +363,7 @@ mem_allocate(PARROT_INTERP, return_val = pool->top_block->top; pool->top_block->top += size; pool->top_block->free -= size; + mem_pools->memory_used += size; return return_val; } @@ -512,6 +516,7 @@ compact_pool(PARROT_INTERP, /* How much is free. That's the total size minus the amount we used */ new_block->free = new_block->size - (cur_spot - new_block->start); mem_pools->memory_collected += (cur_spot - new_block->start); + mem_pools->memory_used += (cur_spot - new_block->start); free_old_mem_blocks(mem_pools, pool, new_block, total_size); @@ -719,6 +724,8 @@ free_old_mem_blocks( else { /* Note that we don't have it any more */ mem_pools->memory_allocated -= cur_block->size; + mem_pools->memory_used -= + cur_block->size - cur_block->free - cur_block->freed; /* We know the pool body and pool header are a single chunk, so * this is enough to get rid of 'em both */ diff --git a/src/gc/gc_ms.c b/src/gc/gc_ms.c index 523a5ca..9dc50f1 100644 --- a/src/gc/gc_ms.c +++ b/src/gc/gc_ms.c @@ -35,11 +35,13 @@ static int gc_ms_active_sized_buffers(ARGIN(const Memory_Pools *mem_pools)) __attribute__nonnull__(1); static void gc_ms_add_free_object(SHIM_INTERP, - SHIM(Memory_Pools *mem_pools), + ARGMOD(Memory_Pools *mem_pools), ARGMOD(Fixed_Size_Pool *pool), ARGIN(void *to_add)) + __attribute__nonnull__(2) __attribute__nonnull__(3) __attribute__nonnull__(4) + FUNC_MODIFIES(*mem_pools) FUNC_MODIFIES(*pool); static void gc_ms_alloc_objects(PARROT_INTERP, @@ -134,11 +136,12 @@ static void gc_ms_free_string_header(PARROT_INTERP, ARGMOD(STRING *s)) PARROT_CANNOT_RETURN_NULL PARROT_WARN_UNUSED_RESULT static void * gc_ms_get_free_object(PARROT_INTERP, - ARGIN(Memory_Pools *mem_pools), + ARGMOD(Memory_Pools *mem_pools), ARGMOD(Fixed_Size_Pool *pool)) __attribute__nonnull__(1) __attribute__nonnull__(2) __attribute__nonnull__(3) + FUNC_MODIFIES(*mem_pools) FUNC_MODIFIES(*pool); static size_t gc_ms_get_gc_info(PARROT_INTERP, Interpinfo_enum which) @@ -253,7 +256,8 @@ static void Parrot_gc_initialize_fixed_size_pools(SHIM_INTERP, #define ASSERT_ARGS_gc_ms_active_sized_buffers __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(mem_pools)) #define ASSERT_ARGS_gc_ms_add_free_object __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ - PARROT_ASSERT_ARG(pool) \ + PARROT_ASSERT_ARG(mem_pools) \ + , PARROT_ASSERT_ARG(pool) \ , PARROT_ASSERT_ARG(to_add)) #define ASSERT_ARGS_gc_ms_alloc_objects __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ @@ -560,6 +564,7 @@ gc_ms_mark_and_sweep(PARROT_INTERP, UINTVAL flags) ++mem_pools->gc_mark_runs; --mem_pools->gc_mark_block_level; mem_pools->header_allocs_since_last_collect = 0; + mem_pools->mem_used_last_collect = mem_pools->memory_used; return; } @@ -1127,6 +1132,7 @@ gc_ms_reallocate_buffer_storage(PARROT_INTERP, ARGMOD(Buffer *buffer), && (pool->top_block->top == (char *)Buffer_bufstart(buffer) + old_size)) { pool->top_block->free -= needed; pool->top_block->top += needed; + interp->mem_pools->memory_used += needed; Buffer_buflen(buffer) = newsize; return; } @@ -1239,6 +1245,7 @@ gc_ms_reallocate_string_storage(PARROT_INTERP, ARGMOD(STRING *str), && pool->top_block->top == (char *)Buffer_bufstart(str) + old_size) { pool->top_block->free -= needed; pool->top_block->top += needed; + interp->mem_pools->memory_used += needed; Buffer_buflen(str) = new_size - sizeof (void *); return; } @@ -1260,7 +1267,8 @@ gc_ms_reallocate_string_storage(PARROT_INTERP, ARGMOD(STRING *str), /* Decrease usage */ PARROT_ASSERT(Buffer_pool(str)); - Buffer_pool(str)->freed += ALIGNED_STRING_SIZE(Buffer_buflen(str)); + Buffer_pool(str)->freed += old_size; + interp->mem_pools->memory_used -= old_size; /* copy mem from strstart, *not* bufstart */ oldmem = str->strstart; @@ -1523,13 +1531,13 @@ gc_ms_more_traceable_objects(PARROT_INTERP, ARGMOD(Fixed_Size_Pool *pool)) { ASSERT_ARGS(gc_ms_more_traceable_objects) + size_t new_mem = mem_pools->memory_used - + mem_pools->mem_used_last_collect; - if (pool->skip == GC_ONE_SKIP) - pool->skip = GC_NO_SKIP; - else if (pool->skip == GC_NEVER_SKIP - || (pool->skip == GC_NO_SKIP - && mem_pools->header_allocs_since_last_collect >= GC_SIZE_THRESHOLD)) - Parrot_gc_mark_and_sweep(interp, GC_trace_stack_FLAG); + if (new_mem > (mem_pools->mem_used_last_collect >> 1) + && new_mem > GC_SIZE_THRESHOLD) { + Parrot_gc_mark_and_sweep(interp, GC_trace_stack_FLAG); + } /* requires that num_free_objects be updated in Parrot_gc_mark_and_sweep. If gc is disabled, then we must check the free list directly. */ @@ -1557,7 +1565,7 @@ the PObj flags to indicate that the item is free. static void gc_ms_add_free_object(SHIM_INTERP, - SHIM(Memory_Pools *mem_pools), + ARGMOD(Memory_Pools *mem_pools), ARGMOD(Fixed_Size_Pool *pool), ARGIN(void *to_add)) { @@ -1568,6 +1576,7 @@ gc_ms_add_free_object(SHIM_INTERP, object->next_ptr = pool->free_list; pool->free_list = object; + mem_pools->memory_used -= pool->object_size; } /* @@ -1588,7 +1597,7 @@ PARROT_CANNOT_RETURN_NULL PARROT_WARN_UNUSED_RESULT static void * gc_ms_get_free_object(PARROT_INTERP, - ARGIN(Memory_Pools *mem_pools), + ARGMOD(Memory_Pools *mem_pools), ARGMOD(Fixed_Size_Pool *pool)) { ASSERT_ARGS(gc_ms_get_free_object) @@ -1630,6 +1639,7 @@ gc_ms_get_free_object(PARROT_INTERP, #endif --pool->num_free_objects; + mem_pools->memory_used += pool->object_size; return ptr; } @@ -1682,9 +1692,6 @@ gc_ms_alloc_objects(PARROT_INTERP, if (alloc_size > POOL_MAX_BYTES) pool->objects_per_alloc = POOL_MAX_BYTES / pool->object_size; - - if (alloc_size > GC_SIZE_THRESHOLD) - pool->skip = GC_NEVER_SKIP; } diff --git a/src/gc/gc_private.h b/src/gc/gc_private.h index 66ffdb7..02ea617 100644 --- a/src/gc/gc_private.h +++ b/src/gc/gc_private.h @@ -88,14 +88,6 @@ typedef enum _gc_sys_type_enum { INF /*infinite memory core*/ } gc_sys_type_enum; -/* how often to skip a full GC when this pool has nothing free */ -typedef enum _gc_skip_type_enum { - GC_NO_SKIP = 0, - GC_ONE_SKIP, - GC_ALWAYS_SKIP, - GC_NEVER_SKIP -} gc_skip_type_enum; - typedef struct GC_Subsystem { /* Which GC subsystem are we using? See PARROT_GC_DEFAULT_TYPE in * include/parrot/settings.h for possible values */ @@ -237,7 +229,6 @@ typedef struct Fixed_Size_Pool { size_t objects_per_alloc; - int skip; size_t replenish_level; add_free_object_fn_type add_free_object; /* adds a free object to @@ -294,6 +285,12 @@ typedef struct Memory_Pools { * memory for headers or * internal structures or * anything */ + size_t memory_used; /* The total amount of + * memory used for + * buffers and headers */ + size_t mem_used_last_collect; /* The total amount of + * memory used after + * the last GC run */ UINTVAL memory_collected; /* Total amount of memory copied during collection */ UINTVAL num_early_gc_PMCs; /* how many PMCs want immediate destruction */ diff --git a/src/gc/mark_sweep.c b/src/gc/mark_sweep.c index b6baba6..dfa3ae5 100644 --- a/src/gc/mark_sweep.c +++ b/src/gc/mark_sweep.c @@ -32,11 +32,13 @@ throughout the rest of Parrot. /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ static void free_buffer(SHIM_INTERP, - SHIM(Memory_Pools *mem_pools), + ARGMOD(Memory_Pools *mem_pools), ARGMOD(Fixed_Size_Pool *pool), ARGMOD(Buffer *b)) + __attribute__nonnull__(2) __attribute__nonnull__(3) __attribute__nonnull__(4) + FUNC_MODIFIES(*mem_pools) FUNC_MODIFIES(*pool) FUNC_MODIFIES(*b); @@ -78,7 +80,8 @@ static Fixed_Size_Pool * new_string_pool(PARROT_INTERP, FUNC_MODIFIES(*mem_pools); #define ASSERT_ARGS_free_buffer __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ - PARROT_ASSERT_ARG(pool) \ + PARROT_ASSERT_ARG(mem_pools) \ + , PARROT_ASSERT_ARG(pool) \ , PARROT_ASSERT_ARG(b)) #define ASSERT_ARGS_free_pmc_in_pool __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ @@ -665,7 +668,7 @@ reuse later. static void free_buffer(SHIM_INTERP, - SHIM(Memory_Pools *mem_pools), + ARGMOD(Memory_Pools *mem_pools), ARGMOD(Fixed_Size_Pool *pool), ARGMOD(Buffer *b)) { @@ -690,7 +693,9 @@ free_buffer(SHIM_INTERP, /* We can have shared buffers. Don't count them (yet) */ if (!(*buffer_flags & Buffer_shared_FLAG)) { - block->freed += ALIGNED_STRING_SIZE(Buffer_buflen(b)); + size_t size = ALIGNED_STRING_SIZE(Buffer_buflen(b)); + block->freed += size; + mem_pools->memory_used -= size; } } @@ -770,7 +775,6 @@ initialize_fixed_size_pools(PARROT_INTERP, ARGMOD(Memory_Pools *mem_pools)) /* Init the constant string header pool */ mem_pools->constant_string_header_pool = new_string_pool(interp, mem_pools, 1); mem_pools->constant_string_header_pool->name = "constant_string_header"; - mem_pools->constant_string_header_pool->skip = GC_ALWAYS_SKIP; /* Init the buffer header pool * @@ -789,7 +793,6 @@ initialize_fixed_size_pools(PARROT_INTERP, ARGMOD(Memory_Pools *mem_pools)) /* constant PMCs */ mem_pools->constant_pmc_pool = new_pmc_pool(interp); mem_pools->constant_pmc_pool->name = "constant_pmc"; - mem_pools->constant_pmc_pool->skip = GC_ALWAYS_SKIP; mem_pools->constant_pmc_pool->objects_per_alloc = CONSTANT_PMC_HEADERS_PER_ALLOC; }