# 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 {