# New Ticket Created by Steve Fink # Please include the string: [netlabs #570] # in the subject line of all future correspondence about this issue. # <URL: http://bugs6.perl.org/rt2/Ticket/Display.html?id=570 >
This is a first in a series of patches implementing hashtables. This patch allows the creation of variable-sized Buffer subclasses via new_tracked_header(). It automatically creates a new Resource_Pool for each size requested. For fast access and easy implementation, the resource pools are kept in an array that is resized as needed. This patch also adds mark_used() to the resources.h interface (it is needed for custom mark routines), and adds a new flag BUFFER_report_FLAG that may be set on a buffer to generate a debugging printout whenever the buffer is encountered during compaction. They're not related to the rest of the patch, but they were in the same file and were pretty small, so I slipped them in. Note that this patch aims at minimal invasiveness. If the idea is accepted, then probably all Buffer subclasses (including non-constant STRINGs) that are subject to collection should be placed into the sized pools, and arena_base->*_header_pool should just be cached aliases of the appropriate pool. That would eliminate a bunch of duplicated code in resources.c. It's a trivial change; I'll send a revised patch if people like the idea. All tests still pass with this applied. Unsurprising, since nothing calls the code at this point. Index: resources.c =================================================================== RCS file: /home/perlcvs/parrot/resources.c,v retrieving revision 1.53 diff -p -u -b -r1.53 resources.c --- resources.c 6 May 2002 04:18:00 -0000 1.53 +++ resources.c 14 May 2002 21:47:03 -0000 @@ -12,6 +12,7 @@ * References: */ +#include <assert.h> #include "parrot/parrot.h" #define BUFFER_ALIGNMENT 16 @@ -177,14 +178,6 @@ free_pmc(PMC *pmc) } } -Buffer * -new_tracked_header(struct Parrot_Interp *interpreter, size_t size) -{ - UNUSED(interpreter); - return (Buffer *)mem_sys_allocate(size); -} - - /* We have no more headers on the free header pool. Go allocate more * and put them on */ static void @@ -637,6 +630,58 @@ Parrot_initialize_resource_pools(struct alloc_more_buffer_headers); } +INLINE static UINTVAL +sized_index(size_t unit_size) +{ + return (unit_size - sizeof(Buffer)) / sizeof(void*); +} + +/* unit_size must be a multiple of sizeof(void*), for no particular reason + * other than to shrink the size of the array of pools. */ +static struct Resource_Pool * +new_sized_resource_pool(struct Parrot_Interp *interpreter, + size_t unit_size) +{ + UINTVAL idx = sized_index(unit_size); + UINTVAL num_old = interpreter->arena_base->num_sized; + struct Resource_Pool** sized_pools = + interpreter->arena_base->sized_header_pools; + assert(unit_size % sizeof(void*) == 0); + + /* Expand the array of sized resource pools, if necessary */ + if (num_old <= idx) { + UINTVAL num_new = idx + 1; + sized_pools = mem_sys_realloc(sized_pools, num_new * sizeof(void*)); + memset(sized_pools + num_old, 0, sizeof(void*) * (num_new - num_old)); + interpreter->arena_base->sized_header_pools = sized_pools; + interpreter->arena_base->num_sized = num_new; + } + + if (sized_pools[idx] == NULL) + sized_pools[idx] = new_resource_pool(interpreter, 256, unit_size, + SIZED_HEADERS_PER_ALLOC, + alloc_more_buffer_headers); + + return sized_pools[idx]; + /* FIXME! Sized buffer headers are currently not collected! */ +} + +Buffer * +new_tracked_header(struct Parrot_Interp *interpreter, size_t size) +{ + struct Resource_Pool* pool; + Buffer * buffer; + size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); + pool = new_sized_resource_pool(interpreter, size); + + buffer = get_from_free_pool(interpreter, pool); + interpreter->active_Buffers++; + buffer->flags = BUFFER_live_FLAG; + buffer->bufstart = NULL; + buffer->buflen = 0; + return buffer; +} + /* Figure out how much memory's been allocated total for buffered * things */ static UINTVAL @@ -662,6 +707,7 @@ compact_buffer_pool(struct Parrot_Interp struct Buffer_Arena *cur_buffer_arena; struct Resource_Pool *header_pool; Buffer *b; /* temporary tidy-up for free pool collection */ + INTVAL j; /* Bail if we're blocked */ if (interpreter->GC_block_level) { @@ -715,24 +761,54 @@ compact_buffer_pool(struct Parrot_Interp cur_size = (cur_size + pool->align_1) & ~pool->align_1; cur_spot += cur_size; + /* And finally the sized buffer header pools */ + for (j = 0; j < (INTVAL) interpreter->arena_base->num_sized; j++) { + struct Resource_Pool* sized_pool; + sized_pool = interpreter->arena_base->sized_header_pools[j]; + if (sized_pool == NULL) continue; + + b = &sized_pool->free_pool_buffer; + memcpy(cur_spot, b->bufstart, b->buflen); + b->bufstart = cur_spot; + cur_size = b->buflen; + cur_size = (cur_size + pool->align_1) & ~pool->align_1; + cur_spot += cur_size; + } + /* Run through all the Buffer header pools and copy */ - header_pool = interpreter->arena_base->buffer_header_pool; + for (j = -1; j < (INTVAL) interpreter->arena_base->num_sized; j++) { + if (j == -1) header_pool = interpreter->arena_base->buffer_header_pool; + else header_pool = interpreter->arena_base->sized_header_pools[j]; + if (header_pool == NULL) continue; + for (cur_buffer_arena = header_pool->last_Arena; NULL != cur_buffer_arena; - cur_buffer_arena = cur_buffer_arena->prev) { - UINTVAL i; + cur_buffer_arena = cur_buffer_arena->prev) + { Buffer *buffer_array = cur_buffer_arena->start_Buffer; + UINTVAL i; for (i = 0; i < cur_buffer_arena->used; i++) { + Buffer *buffer = (Buffer*)((char*)cur_buffer_arena->start_Buffer + i +* header_pool->unit_size); + /* Is the string live, and can we move it? */ - if (buffer_array[i].flags & BUFFER_live_FLAG - && !(buffer_array[i].flags & BUFFER_immobile_FLAG) - && buffer_array[i].bufstart) { - memcpy(cur_spot, buffer_array[i].bufstart, - buffer_array[i].buflen); - buffer_array[i].bufstart = cur_spot; - cur_size = buffer_array[i].buflen; + if (buffer->flags & BUFFER_live_FLAG + && !(buffer->flags & BUFFER_immobile_FLAG) + && buffer->bufstart) + { + if (buffer->flags & BUFFER_report_FLAG) { + fprintf(stderr, " copying buffer %p+%ld -> %p\n", + buffer->bufstart, buffer->buflen, cur_spot); + } + memcpy(cur_spot, buffer->bufstart, buffer->buflen); + buffer->bufstart = cur_spot; + cur_size = buffer->buflen; cur_size = (cur_size + pool->align_1) & ~pool->align_1; cur_spot += cur_size; + } else if (buffer->flags & BUFFER_report_FLAG) { + if (buffer->bufstart != NULL) + fprintf(stderr, " not copying buffer %p+%ld\n", + buffer->bufstart, buffer->buflen); + } } } } Index: include/parrot/resources.h =================================================================== RCS file: /home/perlcvs/parrot/include/parrot/resources.h,v retrieving revision 1.29 diff -p -u -b -r1.29 resources.h --- include/parrot/resources.h 4 May 2002 22:27:45 -0000 1.29 +++ include/parrot/resources.h 14 May 2002 21:47:03 -0000 @@ -54,6 +54,8 @@ void Parrot_go_collect(struct Parrot_Int void *Parrot_reallocate(struct Parrot_Interp *interpreter, void *from, size_t tosize); void *Parrot_reallocate_string(struct Parrot_Interp *interpreter, STRING *, size_t tosize); +/* Functions needed for custom DOD routines */ +PMC * mark_used(PMC *used_pmc, PMC *current_end_of_list); void buffer_lives(Buffer *); void Parrot_initialize_resource_pools(struct Parrot_Interp *); @@ -62,6 +64,7 @@ void Parrot_initialize_memory_pools(stru #define STRING_HEADERS_PER_ALLOC 128 #define PMC_HEADERS_PER_ALLOC 128 #define BUFFER_HEADERS_PER_ALLOC 128 +#define SIZED_HEADERS_PER_ALLOC 128 struct PMC_Arena { size_t used; /* Count of PMCs in this arena */ @@ -96,6 +99,8 @@ struct Arenas { struct Resource_Pool *pmc_pool; struct Resource_Pool *buffer_header_pool; struct Resource_Pool *constant_string_header_pool; + struct Resource_Pool **sized_header_pools; + size_t num_sized; }; struct Stash { Index: include/parrot/string.h =================================================================== RCS file: /home/perlcvs/parrot/include/parrot/string.h,v retrieving revision 1.37 diff -p -u -b -r1.37 string.h --- include/parrot/string.h 5 May 2002 04:03:08 -0000 1.37 +++ include/parrot/string.h 14 May 2002 21:47:03 -0000 @@ -70,7 +70,9 @@ typedef enum BUFFER_flag { /* Mark the buffer as on the free list */ BUFFER_on_free_list_FLAG = 1 << 14, /* This is a constant--don't kill it! */ - BUFFER_constant_FLAG = 1 << 15 + BUFFER_constant_FLAG = 1 << 15, + /* For debugging, report when this buffer gets moved around */ + BUFFER_report_FLAG = 1 << 16 } BUFFER_flags; /* stringinfo parameters */