# New Ticket Created by Mike Lambert # Please include the string: [netlabs #634] # in the subject line of all future correspondence about this issue. # <URL: http://bugs6.perl.org/rt2/Ticket/Display.html?id=634 >
Peter recently submitted a patch to RT that uses a linked-list for free headers. Here are before and after results: before after gc_alloc_new 4.155999 4.016 gc_alloc_reuse 16.574 12.648002 gc_generations 4.025 3.975001 gc_header_new 3.686 3.986 gc_header_reuse 5.577999 4.175998 gc_waves_headers 3.815002 3.595999 gc_waves_sizeable_data 8.383002 8.381999 gc_waves_sizeable_hdrs 5.668 5.396999 We win on the header-intensive stuff. Not sure why it would be slower on the gc_header_new tests. My best guess is that we know are touching the contents of the buffer header, which we weren't doing before. And when we allocate a bunch of new headers, we have to explcitly free them all, which involves touching the first pointer of every buffer in that memory, as opposed to one pointer in the Parrot_allocated memory we used before. IMO, the gc_alloc_reuse and gc_header_reuse benchmarks more than outweigh gc_header_new. The portion of Peter's patch to do just this change is included below. Mike Lambert Index: resources.c =================================================================== RCS file: /cvs/public/parrot/resources.c,v retrieving revision 1.60 diff -u -r1.60 resources.c --- resources.c 26 May 2002 20:20:08 -0000 1.60 +++ resources.c 29 May 2002 07:08:26 -0000 @@ -41,28 +41,15 @@ /* Create a new tracked resource pool */ static struct Resource_Pool * -new_resource_pool(struct Parrot_Interp *interpreter, size_t free_pool_size, +new_resource_pool(struct Parrot_Interp *interpreter, size_t unit_size, size_t units_per_alloc, void (*replenish)(struct Parrot_Interp *, struct Resource_Pool *), struct Memory_Pool *mem_pool) { struct Resource_Pool *pool; - size_t temp_len; pool = mem_sys_allocate(sizeof(struct Resource_Pool)); - temp_len = free_pool_size * sizeof(void *); - if (interpreter->arena_base->buffer_header_pool) { - pool->free_pool_buffer = new_buffer_header(interpreter); - } - else { - pool->free_pool_buffer = mem_sys_allocate(sizeof(Buffer)); - } - pool->free_pool_buffer->bufstart = - mem_allocate(interpreter, &temp_len, - interpreter->arena_base->memory_pool); - pool->free_pool_buffer->buflen = temp_len; - pool->free_pool_buffer->flags = BUFFER_immune_FLAG; - pool->free_pool_size = temp_len / sizeof(void *); + pool->free_list = NULL; pool->free_entries = 0; pool->unit_size = unit_size; pool->units_per_alloc = units_per_alloc; @@ -72,28 +59,6 @@ return pool; } -/* Expand free pool to accomdate at least n additional entries - * Currently, the minimum expansion is 20% of the current size -*/ -static void -expand_free_pool(struct Parrot_Interp *interpreter, - struct Resource_Pool *pool, size_t n) -{ - size_t growth; - - if (pool->free_pool_size - pool->free_entries < n) { - growth = (n - (pool->free_pool_size - pool->free_entries)) * - sizeof(void *); - if (growth < pool->free_pool_buffer->buflen / 5) { - growth = pool->free_pool_buffer->buflen / 5; - } - Parrot_reallocate(interpreter, pool->free_pool_buffer, - pool->free_pool_buffer->buflen + growth); - pool->free_pool_size += (growth / sizeof(void *)); - } -} - - /* Add entry to free pool * Requires that any object-specific processing (eg flag setting, statistics) * has already been done by the caller @@ -102,20 +67,8 @@ add_to_free_pool(struct Parrot_Interp *interpreter, struct Resource_Pool *pool, void *to_add) { - void **temp_ptr; - - if (pool->free_pool_size == pool->free_entries) { - expand_free_pool(interpreter, pool, 1); - } - -#ifdef GC_DEBUG - Parrot_go_collect(interpreter); -#endif - - /* Okay, so there's space. Add the header on */ - temp_ptr = pool->free_pool_buffer->bufstart; - temp_ptr += pool->free_entries; - *temp_ptr = to_add; + *(void **)to_add = pool->free_list; + pool->free_list = to_add; pool->free_entries++; } @@ -127,7 +80,7 @@ get_from_free_pool(struct Parrot_Interp *interpreter, struct Resource_Pool *pool) { - void ** ptr; + void *ptr; if (!pool->free_entries) { Parrot_do_dod_run(interpreter); @@ -140,9 +93,10 @@ return NULL; } - ptr = pool->free_pool_buffer->bufstart; - ptr += --pool->free_entries; - return *ptr; + ptr = pool->free_list; + pool->free_list = *(void **)ptr; + pool->free_entries--; + return ptr; } /* We have no more headers on the free header pool. Go allocate more @@ -175,7 +129,6 @@ /* Note it in our stats */ interpreter->total_PMCs += pool->units_per_alloc; - expand_free_pool(interpreter, pool, pool->units_per_alloc); cur_pmc = new_arena->start_PMC; for (i = 0; i < pool->units_per_alloc; i++) { cur_pmc->flags = PMC_on_free_list_FLAG; @@ -253,7 +206,6 @@ /* Note it in our stats */ interpreter->total_Buffers += pool->units_per_alloc; - expand_free_pool(interpreter, pool, pool->units_per_alloc); cur_buffer = new_arena->start_Buffer; for (i = 0; i < pool->units_per_alloc; i++) { cur_buffer->flags = BUFFER_on_free_list_FLAG; @@ -625,34 +577,28 @@ /* Init the buffer header pool - this must be the first pool created! */ interpreter->arena_base->buffer_header_pool = - new_resource_pool(interpreter, 256, sizeof(Buffer), + new_resource_pool(interpreter, sizeof(Buffer), BUFFER_HEADERS_PER_ALLOC, alloc_more_buffer_headers, interpreter->arena_base->memory_pool); - /* Re-allocate the temporary buffer header from the new pool */ - old_b = interpreter->arena_base->buffer_header_pool->free_pool_buffer; - new_b = new_buffer_header(interpreter); - mem_sys_memcopy(new_b, old_b, sizeof(Buffer)); - interpreter->arena_base->buffer_header_pool->free_pool_buffer = new_b; - mem_sys_free(old_b); - + /* Init the string header pool */ interpreter->arena_base->string_header_pool = - new_resource_pool(interpreter, 256, sizeof(STRING), + new_resource_pool(interpreter, sizeof(STRING), STRING_HEADERS_PER_ALLOC, alloc_more_buffer_headers, interpreter->arena_base->string_pool); /* Init the PMC header pool */ interpreter->arena_base->pmc_pool = - new_resource_pool(interpreter, 256, sizeof(PMC), + new_resource_pool(interpreter, sizeof(PMC), PMC_HEADERS_PER_ALLOC, alloc_more_pmc_headers, NULL); /* Init the constant string header pool */ interpreter->arena_base->constant_string_header_pool = - new_resource_pool(interpreter, 256, sizeof(STRING), + new_resource_pool(interpreter, sizeof(STRING), STRING_HEADERS_PER_ALLOC, alloc_more_buffer_headers, interpreter->arena_base->constant_string_pool); @@ -687,7 +633,7 @@ if (sized_pools[idx] == NULL) sized_pools[idx] = - new_resource_pool(interpreter, 256, unit_size, + new_resource_pool(interpreter, unit_size, SIZED_HEADERS_PER_ALLOC, alloc_more_buffer_headers, interpreter->arena_base->memory_pool); Index: include/parrot/resources.h =================================================================== RCS file: /cvs/public/parrot/include/parrot/resources.h,v retrieving revision 1.32 diff -u -r1.32 resources.h --- include/parrot/resources.h 24 May 2002 16:11:10 -0000 1.32 +++ include/parrot/resources.h 29 May 2002 07:08:27 -0000 @@ -81,11 +81,10 @@ /* Tracked resource pool */ struct Resource_Pool { void *last_Arena; - Buffer *free_pool_buffer; + void *free_list; size_t unit_size; /* size in bytes of an individual pool item */ size_t units_per_alloc; size_t free_entries; /* number of resources in the free pool */ - size_t free_pool_size; /* total number of slots in the free pool */ size_t replenish_level; /* minimum free entries before replenishing */ void (*replenish)(struct Parrot_Interp *, struct Resource_Pool *); struct Memory_Pool *mem_pool;