Leopold Toetsch writes: > Luke Palmer <[EMAIL PROTECTED]> wrote: > > > In any case, seeing that depth first case (see the footnote) has given > > me even more hope that I won't be agonizing over scope exit. > > Can you summarize your scheme again please WRT this and other > enhancements. I'm somewhat lost in all the improvements that were > proposed since your original.
Alright, here's a patch that implements it. The current scheme is actually quite a bit simpler than the one I originally proposed. It should provide much better performance, too. Bear with me, because I don't know my way around the DOD very well. First, do I increment num_early_DOD_PMCs in the right place? That's where it was set to 1 before... Also, the critical block that makes this an optimization is missing, marked with an XXX. I didn't implement it because I don't really know the control flow of DOD, so I didn't know how to abort cleanly. Can someone give me some hints here? Other than those few, but unignorable, caveats, Enjoy! Index: include/parrot/interpreter.h =================================================================== RCS file: /cvs/public/parrot/include/parrot/interpreter.h,v retrieving revision 1.85 diff -u -r1.85 interpreter.h --- include/parrot/interpreter.h 28 Aug 2003 15:26:24 -0000 1.85 +++ include/parrot/interpreter.h 5 Sep 2003 11:28:24 -0000 @@ -188,14 +188,19 @@ /* per interpreter global vars */ INTVAL world_inited; /* Parrot_init is done */ - PMC *mark_ptr; /* last PMC marked used in DOD runs */ PMC *iglobals; /* SArray of PMCs, containing: */ /* 0: PMC *Parrot_base_classname_hash; hash containing name->base_type */ /* 1: PMC *Parrot_compreg_hash; hash containing assembler/compilers */ /* 2: PMC *Argv; list of argv */ /* 3: PMC *Env; hash_like Env PMC */ /* 4: PMC *ParrotInterpreter that's me */ - int has_early_DOD_PMCs; /* Flag that some want immediate destruction */ + UINTVAL num_early_DOD_PMCs; /* how many want immediate destruction */ + UINTVAL DOD_early_PMCs_seen; /* how many that want immediate destruction + * has DOD seen */ + PMC *dod_mark_ptr; /* last PMC marked used in DOD runs */ + PMC *dod_trace_ptr; /* last PMC trace_children was called on */ + int lazy_dod; /* flag indicating whether we should stop + when we find all impatient pmcs */ } Interp; /* &gen_from_enum(iglobals.pasm) */ Index: include/parrot/pobj.h =================================================================== RCS file: /cvs/public/parrot/include/parrot/pobj.h,v retrieving revision 1.28 diff -u -r1.28 pobj.h --- include/parrot/pobj.h 28 Aug 2003 13:44:25 -0000 1.28 +++ include/parrot/pobj.h 5 Sep 2003 11:28:24 -0000 @@ -198,7 +198,7 @@ PObj_active_destroy_FLAG = 1 << 22, /* For debugging, report when this buffer gets moved around */ PObj_report_FLAG = 1 << 23, - + /* PMC specific FLAGs */ /* Set to true if the PMC data pointer points to something that @@ -218,12 +218,14 @@ */ b_PObj_is_special_PMC_FLAG = 1 << 26, - b_PObj_needs_early_DOD_FLAG = 1 << 27, + /* This PObj is connected by some route to a "needs_early_DOD" object */ + PObj_high_priority_DOD_FLAG = 1 << 27, + b_PObj_needs_early_DOD_FLAG = (1 << 27 | 1 << 28), /* True if the PMC is a class */ - PObj_is_class_FLAG = 1 << 28, + PObj_is_class_FLAG = 1 << 29, /* True if the PMC is a parrot object */ - PObj_is_object_FLAG = 1 << 29 + PObj_is_object_FLAG = 1 << 30 } PObj_flags; @@ -340,6 +342,10 @@ #define PObj_report_TEST(o) PObj_flag_TEST(report, o) #define PObj_report_SET(o) PObj_flag_SET(report, o) #define PObj_report_CLEAR(o) PObj_flag_CLEAR(report, o) + +#define PObj_high_priority_DOD_TEST(o) PObj_flag_TEST(high_priority_DOD, o) +#define PObj_high_priority_DOD_SET(o) PObj_flag_SET(high_priority_DOD, o) +#define PObj_high_priority_DOD_CLEAR(o) PObj_flag_CLEAR(high_priority_DOD, o) #define PObj_on_free_list_TEST(o) DOD_flag_TEST(on_free_list, o) #define PObj_on_free_list_SET(o) DOD_flag_SET(on_free_list, o) Index: include/parrot/dod.h =================================================================== RCS file: /cvs/public/parrot/include/parrot/dod.h,v retrieving revision 1.11 diff -u -r1.11 dod.h --- include/parrot/dod.h 28 Jul 2003 13:38:00 -0000 1.11 +++ include/parrot/dod.h 5 Sep 2003 11:28:24 -0000 @@ -40,7 +40,12 @@ #define Parrot_is_blocked_GC(interpreter) \ ((interpreter)->GC_block_level) -void Parrot_do_dod_run(struct Parrot_Interp *, int trace_stack); +enum { + DOD_trace_stack_FLAG = 1 << 0, + DOD_lazy_FLAG = 1 << 1 +}; + +void Parrot_do_dod_run(struct Parrot_Interp *, UINTVAL flags); void trace_system_areas(struct Parrot_Interp *); void trace_mem_block(struct Parrot_Interp *, size_t, size_t); Index: dod.c =================================================================== RCS file: /cvs/public/parrot/dod.c,v retrieving revision 1.70 diff -u -r1.70 dod.c --- dod.c 28 Aug 2003 16:56:15 -0000 1.70 +++ dod.c 5 Sep 2003 11:28:24 -0000 @@ -43,19 +43,34 @@ size_t ns = n >> ARENA_FLAG_SHIFT; UINTVAL nm = (n & ARENA_FLAG_MASK) << 2; UINTVAL *dod_flags = arena->dod_flags + ns; - if (*dod_flags & ((PObj_on_free_list_FLAG | PObj_live_FLAG) << nm)) + if (*dod_flags & PObj_on_free_list_FLAG << nm) + return; + if (PObj_high_priority_DOD_TEST(obj) && interpreter->dod_trace_ptr) + /* set obj's parent to high priority */ + PObj_high_priority_DOD_SET(interpreter->dod_trace_ptr); + if (*dod_flags & PObj_live_FLAG << nm) return; ++arena->live_objects; *dod_flags |= PObj_live_FLAG << nm; if (*dod_flags & (PObj_is_special_PMC_FLAG << nm)) { if (((PMC*)obj)->pmc_ext) { - /* put it on the end of the list */ - interpreter->mark_ptr->next_for_GC = (PMC *)obj; + if (PObj_high_priority_DOD_TEST(obj) + && ++interpreter->DOD_early_PMCs_seen + && interpreter->dod_trace_ptr) { + /* put it at the head of the list */ + ((PMC*)obj)->next_for_GC = interpreter->dod_trace_ptr + ->next_for_GC->next_for_GC; + interpreter->dod_trace_ptr->next_for_GC = (PMC*)obj; + } + else { + /* put it on the end of the list */ + interpreter->dod_mark_ptr->next_for_GC = (PMC *)obj; - /* Explicitly make the tail of the linked list be - * self-referential */ - interpreter->mark_ptr = ((PMC*)obj)->next_for_GC = (PMC *)obj; + /* Explicitly make the tail of the linked list be + * self-referential */ + interpreter->dod_mark_ptr = ((PMC*)obj)->next_for_GC = (PMC *)obj; + } } else if (PObj_custom_mark_TEST(obj)) VTABLE_mark(interpreter, (PMC *) obj); @@ -84,6 +99,8 @@ } # endif #endif + if (PObj_high_priority_DOD_TEST(obj) && interpreter->dod_trace_ptr) + PObj_high_priority_DOD_SET(interpreter->dod_trace_ptr); /* mark it live */ PObj_live_SET(obj); /* if object is a PMC and contains buffers or PMCs, then attach @@ -91,12 +108,22 @@ */ if (PObj_is_special_PMC_TEST(obj)) { if (((PMC*)obj)->pmc_ext) { - /* put it on the end of the list */ - interpreter->mark_ptr->next_for_GC = (PMC *)obj; + if (PObj_high_priority_DOD_TEST(obj) + && ++interpreter->DOD_early_PMCs_seen + && interpreter->dod_trace_ptr) { + /* put it at the head of the list */ + ((PMC*)obj)->next_for_GC = interpreter->dod_trace_ptr + ->next_for_GC->next_for_GC; + interpreter->dod_trace_ptr->next_for_GC = (PMC*)obj; + } + else { + /* put it on the end of the list */ + interpreter->dod_mark_ptr->next_for_GC = (PMC *)obj; - /* Explicitly make the tail of the linked list be - * self-referential */ - interpreter->mark_ptr = ((PMC*)obj)->next_for_GC = (PMC *)obj; + /* Explicitly make the tail of the linked list be + * self-referential */ + interpreter->dod_mark_ptr = ((PMC*)obj)->next_for_GC = (PMC *)obj; + } } else if (PObj_custom_mark_TEST(obj)) VTABLE_mark(interpreter, (PMC *) obj); @@ -134,7 +161,7 @@ struct Stash *stash = 0; /* We have to start somewhere, the interpreter globals is a good place */ - interpreter->mark_ptr = current = interpreter->iglobals; + interpreter->dod_mark_ptr = current = interpreter->iglobals; /* mark it as used */ pobject_lives(interpreter, (PObj *)interpreter->iglobals); @@ -204,7 +231,13 @@ unsigned i = 0; UINTVAL mask = PObj_is_PMC_ptr_FLAG | PObj_is_buffer_ptr_FLAG | PObj_custom_mark_FLAG; - + + if (interpreter->DOD_early_PMCs_seen >= interpreter->num_early_DOD_PMCs) + ; /* XXX (lp): abort DOD and set a flag saying "no GC allowed" */ + + PObj_high_priority_DOD_CLEAR(current); + interpreter->dod_trace_ptr = current; + for (; current != prev; current = current->next_for_GC) { UINTVAL bits = PObj_get_FLAGS(current) & mask; @@ -454,7 +487,7 @@ #endif /* We have no impatient things. Yet. */ - interpreter->has_early_DOD_PMCs = 0; + interpreter->num_early_DOD_PMCs = 0; /* Run through all the buffer header pools and mark */ for (cur_arena = pool->last_Arena; @@ -499,11 +532,11 @@ total_used++; #if ARENA_DOD_FLAGS if ((*dod_flags & (PObj_needs_early_DOD_FLAG << nm))) - interpreter->has_early_DOD_PMCs = 1; + ++interpreter->num_early_DOD_PMCs; #else PObj_live_CLEAR(b); if (PObj_needs_early_DOD_TEST(b)) - interpreter->has_early_DOD_PMCs = 1; + ++interpreter->num_early_DOD_PMCs; #endif } else { @@ -699,7 +732,7 @@ /* See if we can find some unused headers */ void -Parrot_do_dod_run(struct Parrot_Interp *interpreter, int trace_stack) +Parrot_do_dod_run(struct Parrot_Interp *interpreter, UINTVAL flags) { struct Small_Object_Pool *header_pool; int j; @@ -711,6 +744,8 @@ } Parrot_block_DOD(interpreter); + interpreter->lazy_dod = flags & DOD_lazy_FLAG; + interpreter->dod_trace_ptr = NULL; #if ARENA_DOD_FLAGS clear_live_counter(interpreter, interpreter->arena_base->pmc_pool); for (j = 0; j < (INTVAL)interpreter->arena_base->num_sized; j++) { @@ -720,7 +755,7 @@ } #endif /* Now go trace the PMCs */ - trace_active_PMCs(interpreter, trace_stack); + trace_active_PMCs(interpreter, flags & DOD_trace_stack_FLAG); /* And the buffers */ trace_active_buffers(interpreter); @@ -730,7 +765,7 @@ * marking everything, if something was missed * not - these could also be stale objects */ - if (trace_stack) { + if (flags & DOD_trace_stack_FLAG) { # if ! DISABLE_GC_DEBUG CONSERVATIVE_POINTER_CHASING = 1; # endif @@ -763,6 +798,7 @@ } /* Note it */ interpreter->dod_runs++; + interpreter->dod_trace_ptr = NULL; Parrot_unblock_DOD(interpreter); return; } Index: interpreter.c =================================================================== RCS file: /cvs/public/parrot/interpreter.c,v retrieving revision 1.199 diff -u -r1.199 interpreter.c --- interpreter.c 28 Aug 2003 15:26:21 -0000 1.199 +++ interpreter.c 5 Sep 2003 11:28:24 -0000 @@ -865,7 +865,7 @@ */ Parrot_IOData_mark(interpreter, interpreter->piodata); - if (interpreter->has_early_DOD_PMCs) + if (interpreter->num_early_DOD_PMCs) free_unused_pobjects(interpreter, interpreter->arena_base->pmc_pool); /* we destroy all child interpreters and the last one too, Index: resources.c =================================================================== RCS file: /cvs/public/parrot/resources.c,v retrieving revision 1.108 diff -u -r1.108 resources.c --- resources.c 28 Jul 2003 13:37:55 -0000 1.108 +++ resources.c 5 Sep 2003 11:28:24 -0000 @@ -106,13 +106,13 @@ interpreter->mem_allocs_since_last_collect++; } if (0 && GC_DEBUG(interpreter)) { - Parrot_do_dod_run(interpreter, 1); + Parrot_do_dod_run(interpreter, DOD_trace_stack_FLAG); if (pool->compact) { (*pool->compact) (interpreter, pool); } } if (pool->top_block->free < size) { - Parrot_do_dod_run(interpreter, 1); + Parrot_do_dod_run(interpreter, DOD_trace_stack_FLAG); /* Compact the pool if allowed and worthwhile */ if (pool->compact) { /* don't bother reclaiming if it's just chicken feed */ Index: smallobject.c =================================================================== RCS file: /cvs/public/parrot/smallobject.c,v retrieving revision 1.26 diff -u -r1.26 smallobject.c --- smallobject.c 26 Aug 2003 10:05:44 -0000 1.26 +++ smallobject.c 5 Sep 2003 11:28:24 -0000 @@ -68,7 +68,7 @@ if (pool->skip) pool->skip = 0; else { - Parrot_do_dod_run(interpreter, 1); + Parrot_do_dod_run(interpreter, DOD_trace_stack_FLAG); if (pool->num_free_objects <= pool->replenish_level) pool->skip = 1; } Index: string.c =================================================================== RCS file: /cvs/public/parrot/string.c,v retrieving revision 1.143 diff -u -r1.143 string.c --- string.c 27 Aug 2003 16:27:28 -0000 1.143 +++ string.c 5 Sep 2003 11:28:24 -0000 @@ -943,7 +943,7 @@ /* It's easy to forget that string comparison can trigger GC */ if (interpreter && GC_DEBUG(interpreter)) - Parrot_do_dod_run(interpreter, 1); + Parrot_do_dod_run(interpreter, DOD_trace_stack_FLAG); if (s1->type != s2->type || s1->encoding != s2->encoding) { s1 = string_transcode(interpreter, s1, NULL, string_unicode_type, @@ -1018,7 +1018,7 @@ /* trigger GC for debug */ if (interpreter && GC_DEBUG(interpreter)) - Parrot_do_dod_run(interpreter, 1); + Parrot_do_dod_run(interpreter, DOD_trace_stack_FLAG); if (s1->type != s2->type || s1->encoding != s2->encoding) { s1 = string_transcode(interpreter, s1, NULL, string_unicode_type, @@ -1080,7 +1080,7 @@ /* trigger GC for debug */ if (interpreter && GC_DEBUG(interpreter)) - Parrot_do_dod_run(interpreter, 1); + Parrot_do_dod_run(interpreter, DOD_trace_stack_FLAG); if (s1 && s2) { if (s1->type != s2->type || s1->encoding != s2->encoding) { @@ -1162,7 +1162,7 @@ /* trigger GC for debug */ if (interpreter && GC_DEBUG(interpreter)) - Parrot_do_dod_run(interpreter, 1); + Parrot_do_dod_run(interpreter, DOD_trace_stack_FLAG); if (s1 && s2) { if (s1->type != s2->type || s1->encoding != s2->encoding) { Index: classes/timer.pmc =================================================================== RCS file: /cvs/public/parrot/classes/timer.pmc,v retrieving revision 1.7 diff -u -r1.7 timer.pmc --- classes/timer.pmc 25 Aug 2003 09:46:23 -0000 1.7 +++ classes/timer.pmc 5 Sep 2003 11:28:24 -0000 @@ -253,7 +253,7 @@ t->self = SELF; SELF->cache.struct_val = t; PObj_active_destroy_SET(SELF); - interpreter->has_early_DOD_PMCs = 1; + interpreter->num_early_DOD_PMCs++; } void init_pmc(PMC *init) { Index: io/io.c =================================================================== RCS file: /cvs/public/parrot/io/io.c,v retrieving revision 1.53 diff -u -r1.53 io.c --- io/io.c 2 Sep 2003 16:41:14 -0000 1.53 +++ io/io.c 5 Sep 2003 11:28:24 -0000 @@ -748,12 +748,12 @@ INTVAL i; ParrotIOTable table = piodata->table; - /* XXX boe: Parrot_really_destroy might call us with mark_ptr not + /* XXX boe: Parrot_really_destroy might call us with dod_mark_ptr not * set. This is neccessary until destruction ordering prevents * the premature destruction of the standardhandles */ - if (!interpreter->mark_ptr) - interpreter->mark_ptr = table[0]; + if (!interpreter->dod_mark_ptr) + interpreter->dod_mark_ptr = table[0]; for (i = 0; i < PIO_NR_OPEN; i++) { if (table[i]) { Index: core.ops =================================================================== RCS file: /cvs/public/parrot/core.ops,v retrieving revision 1.324 diff -u -r1.324 core.ops --- core.ops 29 Aug 2003 11:30:17 -0000 1.324 +++ core.ops 5 Sep 2003 11:28:24 -0000 @@ -837,8 +837,11 @@ =cut op sweep(inconst INT) { - if ($1 || interpreter->has_early_DOD_PMCs) + if ($1) Parrot_do_dod_run(interpreter, 0); + else + if (interpreter->num_early_DOD_PMCs) + Parrot_do_dod_run(interpreter, DOD_lazy_FLAG); goto NEXT(); } @@ -906,7 +909,7 @@ op needs_destroy(in PMC) { PObj_needs_early_DOD_SET($1); - interpreter->has_early_DOD_PMCs = 1; + interpreter->num_early_DOD_PMCs = 1; goto NEXT(); }