# New Ticket Created by Mike Lambert # Please include the string: [perl #809] # in the subject line of all future correspondence about this issue. # <URL: http://bugs6.perl.org/rt2/Ticket/Display.html?id=809 >
Okay, patch is included below. Here are the relevant times from the gc bench suite: gc_alloc_reuse.pbc 12.058001 12.056999 gc_generations.pbc 3.964999 5.769 gc_header_new.pbc 3.924999 3.924999 gc_waves_headers.pbc 0.871997 0.871999 gc_waves_sizeable_data.pbc 7.059 7.140001 gc_waves_sizeable_headers.pbc 5.316999 5.358 I believe gc_generations is slower due to the many DOD calls that are performed (and each DOD requires a stack walk). In general, the stack-walk makes the new version a little bit slower, or perhaps the same, in all cases. Note that the patch implementation is a bit ugly because of the seperation of pmc and header pools. I have another GC refactoring patch in the wings which should remedy this situation. Also note the problem I mentioned earlier, which may very well crop it's head up with this patch under 'real-world' conditions. See below sig. Mike Lambert > Also, I think I've discovered a situation which might not be > resolvable. How do we determine id a given buffer is alive? We walk the > stack and check for potential pointers into buffer memory. If the stack > contains garbage pointers, we might have bad references into buffer > memory. I can check for alignment within the buffer pool, and so it should > be safe to set the BUFFER_live_FLAG on them. > > However, when we perform a collection, that means that we could be taking > a garbage pointer in the buffer, and attempting to copy the memory it > pointed to, into new memory. > > This could give us GPFs if we access bad memory, I think. Even if we check > to ensure the buffer points into valid collectable memory (making it > slower), we still have the issue of buflen being set to MAX_INT or > something, and killing the system. :| > > The same caveats apply to pmc headers which happen to have > PMC_buffer_ptr_FLAG set. > > How should we get around this particular problem, or is it spelling the > doom of this particular solution? > > Thanks, > Mike Lambert -- attachment 1 ------------------------------------------------------ url: http://bugs6.perl.org/rt2/attach/3798/3520/778163/diff.txt
? vc60.pdb ? parrot.pdb ? classes/vc60.pdb ? lib/Parrot/PakFile2.def Index: interpreter.c =================================================================== RCS file: /cvs/public/parrot/interpreter.c,v retrieving revision 1.91 diff -u -r1.91 interpreter.c --- interpreter.c 4 Jul 2002 20:39:44 -0000 1.91 +++ interpreter.c 13 Jul 2002 09:10:52 -0000 @@ -404,6 +404,8 @@ runops(struct Parrot_Interp *interpreter, struct PackFile *code, size_t offset) { opcode_t *(*core) (struct Parrot_Interp *, opcode_t *); + void *dummy_ptr; + interpreter->lo_var_ptr = &dummy_ptr; interpreter->code = code; interpreter->resume_offset = offset; Index: resources.c =================================================================== RCS file: /cvs/public/parrot/resources.c,v retrieving revision 1.72 diff -u -r1.72 resources.c --- resources.c 4 Jul 2002 20:39:44 -0000 1.72 +++ resources.c 13 Jul 2002 09:10:56 -0000 @@ -123,6 +123,7 @@ mem_sys_allocate(sizeof(PMC) * pool->units_per_alloc); memset(new_arena->start_PMC, 0, sizeof(PMC) * pool->units_per_alloc); new_arena->used = pool->units_per_alloc; + new_arena->total = pool->units_per_alloc; new_arena->next = NULL; new_arena->prev = pool->last_Arena; /* Is there a previous arena */ @@ -132,6 +133,12 @@ pool->last_Arena = new_arena; + if (pool->start_arena_memory > new_arena->start_PMC) + pool->start_arena_memory = new_arena->start_PMC; + + if (pool->end_arena_memory < new_arena->start_PMC + sizeof(PMC) * +pool->units_per_alloc) + pool->end_arena_memory = new_arena->start_PMC + sizeof(PMC) * +pool->units_per_alloc; + /* Note it in our stats */ interpreter->total_PMCs += pool->units_per_alloc; @@ -200,6 +207,7 @@ memset(new_arena->start_Buffer, 0, pool->unit_size * pool->units_per_alloc); new_arena->used = pool->units_per_alloc; + new_arena->total = pool->units_per_alloc; new_arena->next = NULL; new_arena->prev = pool->last_Arena; /* Is there a previous arena */ @@ -209,6 +217,12 @@ pool->last_Arena = new_arena; + if (pool->start_arena_memory > new_arena->start_Buffer) + pool->start_arena_memory = new_arena->start_Buffer; + + if (pool->end_arena_memory < new_arena->start_Buffer + sizeof(Buffer) * +pool->units_per_alloc) + pool->end_arena_memory = new_arena->start_Buffer + sizeof(Buffer) * +pool->units_per_alloc; + /* Note it in our stats */ interpreter->total_Buffers += pool->units_per_alloc; @@ -298,6 +312,92 @@ buffer->flags |= BUFFER_live_FLAG; } +size_t +get_max_buffer_address(struct Parrot_Interp *interpreter) +{ + UINTVAL i; + size_t max = interpreter->arena_base->string_header_pool->end_arena_memory; + + if (max < interpreter->arena_base->buffer_header_pool->end_arena_memory) + max = interpreter->arena_base->buffer_header_pool->end_arena_memory; + + if (max < interpreter->arena_base->constant_string_header_pool->end_arena_memory) + + max = interpreter->arena_base->constant_string_header_pool->end_arena_memory; + + + for(i = 0; i<interpreter->arena_base->num_sized; i++) { + if (interpreter->arena_base->sized_header_pools[i]) { + if (max < +interpreter->arena_base->sized_header_pools[i]->end_arena_memory) + max = +interpreter->arena_base->sized_header_pools[i]->end_arena_memory; + } + } + + return max; +} +size_t +get_min_buffer_address(struct Parrot_Interp *interpreter) +{ + UINTVAL i; + size_t min = interpreter->arena_base->string_header_pool->end_arena_memory; + + if (min > interpreter->arena_base->buffer_header_pool->end_arena_memory) + min = interpreter->arena_base->buffer_header_pool->end_arena_memory; + + if (min > interpreter->arena_base->constant_string_header_pool->end_arena_memory) + + min = interpreter->arena_base->constant_string_header_pool->end_arena_memory; + + + for(i = 0; i<interpreter->arena_base->num_sized; i++) { + if (interpreter->arena_base->sized_header_pools[i]) { + if (min > +interpreter->arena_base->sized_header_pools[i]->end_arena_memory) + min = +interpreter->arena_base->sized_header_pools[i]->end_arena_memory; + } + } + + return min; +} + +size_t +get_max_pmc_address(struct Parrot_Interp *interpreter) +{ + return interpreter->arena_base->pmc_pool->end_arena_memory; +} +size_t +get_min_pmc_address(struct Parrot_Interp *interpreter) +{ + return interpreter->arena_base->pmc_pool->start_arena_memory; +} + +#ifndef PLATFORM_STACK_WALK +PMC* +trace_system_stack(struct Parrot_Interp *interpreter, PMC *last) +{ + size_t lo_var_ptr = (size_t)interpreter->lo_var_ptr; + size_t hi_var_ptr = (size_t)&lo_var_ptr; + size_t cur_var_ptr; + size_t direction = (hi_var_ptr > lo_var_ptr) ? 1 : -1; + + size_t buffer_min = get_min_buffer_address(interpreter); + size_t buffer_max = get_max_buffer_address(interpreter); + size_t pmc_min = get_min_pmc_address(interpreter); + size_t pmc_max = get_max_pmc_address(interpreter); + + if (!lo_var_ptr) + return last; + + for (cur_var_ptr = lo_var_ptr; + cur_var_ptr*direction<hi_var_ptr*direction; + cur_var_ptr += direction + ) { + size_t ptr = *(size_t *)cur_var_ptr; + if (pmc_min < ptr && ptr < pmc_max && is_pmc_ptr(interpreter,(void *)ptr)) { + last = mark_used((PMC *)ptr, last); + } else if (buffer_min < ptr && ptr < buffer_max && +is_buffer_ptr(interpreter,(void *)ptr)) { + buffer_lives((Buffer *)ptr); + } + } + return last; +} +#endif + /* Do a full trace run and mark all the PMCs as active if they are */ static void trace_active_PMCs(struct Parrot_Interp *interpreter) @@ -318,6 +418,9 @@ /* mark it as used and get an updated end of list */ last = mark_used(current, last); + /* Find important stuff on the system stack */ + last = trace_system_stack(interpreter,last); + /* Now, go run through the PMC registers and mark them as live */ /* First mark the current set. */ for (i = 0; i < NUM_REGISTERS; i++) { @@ -407,6 +510,61 @@ prev = current; } } + +INTVAL +contained_in_buffer_pool(struct Parrot_Interp *interpreter, + struct Resource_Pool *pool, void *ptr) +{ + struct Buffer_Arena *arena; + + for (arena = pool->last_Arena; arena; arena = arena->prev) { + size_t ptr_diff = (size_t)ptr - (size_t)arena->start_Buffer; + if (0 <= ptr_diff && ptr_diff < arena->total * sizeof(Buffer) + && ptr_diff % sizeof(Buffer) == 0) + return 1; + } + return 0; +} +INTVAL +contained_in_pmc_pool(struct Parrot_Interp *interpreter, + struct Resource_Pool *pool, void *ptr) +{ + struct PMC_Arena *arena; + + for (arena = pool->last_Arena; arena; arena = arena->prev) { + size_t ptr_diff = (size_t)ptr - (size_t)arena->start_PMC; + if (0 <= ptr_diff && ptr_diff < arena->total * sizeof(PMC) + && ptr_diff % sizeof(PMC) == 0) + return 1; + } + return 0; +} + +int +is_buffer_ptr(struct Parrot_Interp *interpreter, void *ptr) +{ + UINTVAL i; + + if (contained_in_buffer_pool(interpreter, + interpreter->arena_base->string_header_pool, ptr)) + return 1; + if (contained_in_buffer_pool(interpreter, + interpreter->arena_base->buffer_header_pool, ptr)) + return 1; + if (contained_in_buffer_pool(interpreter, + interpreter->arena_base->constant_string_header_pool, ptr)) + + return 1; + + return 0; +} + +int +is_pmc_ptr(struct Parrot_Interp *interpreter, void *ptr) +{ + return contained_in_pmc_pool(interpreter, + interpreter->arena_base->pmc_pool, ptr); +} + /* Scan any buffers in S registers and other non-PMC places and mark * them as active */ Index: include/parrot/interpreter.h =================================================================== RCS file: /cvs/public/parrot/include/parrot/interpreter.h,v retrieving revision 1.49 diff -u -r1.49 interpreter.h --- include/parrot/interpreter.h 4 Jul 2002 20:40:32 -0000 1.49 +++ include/parrot/interpreter.h 13 Jul 2002 09:10:58 -0000 @@ -175,6 +175,8 @@ requests are there? */ PDB_t *pdb; /* Debug system */ + + void *lo_var_ptr; /* Pointer to memory on runops system stack */ } Interp; #define PCONST(i) PF_CONST(interpreter->code, (i)) Index: include/parrot/resources.h =================================================================== RCS file: /cvs/public/parrot/include/parrot/resources.h,v retrieving revision 1.33 diff -u -r1.33 resources.h --- include/parrot/resources.h 4 Jun 2002 19:37:02 -0000 1.33 +++ include/parrot/resources.h 13 Jul 2002 09:10:58 -0000 @@ -45,6 +45,15 @@ void *Parrot_allocate(struct Parrot_Interp *, void *, size_t size); void *Parrot_allocate_string(struct Parrot_Interp *, STRING *, size_t size); +size_t get_min_buffer_address(struct Parrot_Interp *); +size_t get_max_buffer_address(struct Parrot_Interp *); +size_t get_min_pmc_address(struct Parrot_Interp *); +size_t get_max_pmc_address(struct Parrot_Interp *); +int is_buffer_ptr(struct Parrot_Interp *, void *); +int is_pmc_ptr(struct Parrot_Interp *, void *); +int contained_in_pool(struct Parrot_Interp *,struct Resource_Pool *, void *); +PMC *trace_system_stack(struct Parrot_Interp *, PMC *); + void Parrot_do_dod_run(struct Parrot_Interp *); void Parrot_go_collect(struct Parrot_Interp *); @@ -65,6 +74,7 @@ struct PMC_Arena { size_t used; /* Count of PMCs in this arena */ + size_t total; struct PMC_Arena *prev; struct PMC_Arena *next; PMC *start_PMC; /* Pointer to array of PMCs */ @@ -73,6 +83,7 @@ struct Buffer_Arena { size_t used; + size_t total; struct Buffer_Arena *prev; struct Buffer_Arena *next; Buffer *start_Buffer; @@ -88,6 +99,8 @@ size_t replenish_level; /* minimum free entries before replenishing */ void (*replenish)(struct Parrot_Interp *, struct Resource_Pool *); struct Memory_Pool *mem_pool; + size_t start_arena_memory; + size_t end_arena_memory; }; struct Arenas {