cvsuser 04/08/18 05:53:32
Modified: classes fixedpmcarray.pmc resizablepmcarray.pmc
include/parrot dod.h
src dod.c gc_ims.c resources.c
t/op gc.t
Log:
gc subsystems 5 - fix lazy DOD; write barrier
* lazy DOD with async mutators isn't really simple :)
* start putting write barriers into mutator code
* more comments and fixes
* use custom_GC_FLAG as intermediate hack for denoting black objects
Revision Changes Path
1.19 +2 -1 parrot/classes/fixedpmcarray.pmc
Index: fixedpmcarray.pmc
===================================================================
RCS file: /cvs/public/parrot/classes/fixedpmcarray.pmc,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -w -r1.18 -r1.19
--- fixedpmcarray.pmc 29 Jul 2004 06:56:15 -0000 1.18
+++ fixedpmcarray.pmc 18 Aug 2004 12:53:25 -0000 1.19
@@ -1,6 +1,6 @@
/*
Copyright: 2001-2003 The Perl Foundation. All Rights Reserved.
-$Id: fixedpmcarray.pmc,v 1.18 2004/07/29 06:56:15 leo Exp $
+$Id: fixedpmcarray.pmc,v 1.19 2004/08/18 12:53:25 leo Exp $
=head1 NAME
@@ -634,6 +634,7 @@
"FixedPMCArray: index out of bounds!\n");
data = (PMC**)PMC_data(SELF);
+ DOD_WRITE_BARRIER(INTERP, SELF, data[key], src);
data[key] = src;
}
1.13 +6 -2 parrot/classes/resizablepmcarray.pmc
Index: resizablepmcarray.pmc
===================================================================
RCS file: /cvs/public/parrot/classes/resizablepmcarray.pmc,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -w -r1.12 -r1.13
--- resizablepmcarray.pmc 23 Jul 2004 13:26:21 -0000 1.12
+++ resizablepmcarray.pmc 18 Aug 2004 12:53:25 -0000 1.13
@@ -1,6 +1,6 @@
/*
Copyright: 2001-2003 The Perl Foundation. All Rights Reserved.
-$Id: resizablepmcarray.pmc,v 1.12 2004/07/23 13:26:21 leo Exp $
+$Id: resizablepmcarray.pmc,v 1.13 2004/08/18 12:53:25 leo Exp $
=head1 NAME
@@ -24,6 +24,7 @@
#include "parrot/parrot.h"
+
pmclass ResizablePMCArray extends FixedPMCArray need_ext does array {
void class_init () {
/* this should be autmatically done - probably */
@@ -152,6 +153,7 @@
*/
void set_pmc_keyed_int (INTVAL key, PMC* src) {
+ PMC **data;
/*
* TODO in python mode, only .append is allowed
*/
@@ -162,7 +164,9 @@
"ResizablePMCArray: index out of bounds!\n");
if (key >= PMC_int_val(SELF))
DYNSELF.set_integer_native(key+1);
- ((PMC**)PMC_data(SELF))[key] = src;
+ data = (PMC**)PMC_data(SELF);
+ DOD_WRITE_BARRIER(INTERP, SELF, data[key], src);
+ data[key] = src;
}
void set_pmc_keyed (PMC* key, PMC* src) {
1.18 +23 -1 parrot/include/parrot/dod.h
Index: dod.h
===================================================================
RCS file: /cvs/public/parrot/include/parrot/dod.h,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -w -r1.17 -r1.18
--- dod.h 17 Aug 2004 08:21:29 -0000 1.17
+++ dod.h 18 Aug 2004 12:53:28 -0000 1.18
@@ -1,7 +1,7 @@
/* dod.h
* Copyright: 2001-2003 The Perl Foundation. All Rights Reserved.
* CVS Info
- * $Id: dod.h,v 1.17 2004/08/17 08:21:29 leo Exp $
+ * $Id: dod.h,v 1.18 2004/08/18 12:53:28 leo Exp $
* Overview:
* Handles dead object destruction of the various headers
* Data Structure and Algorithms:
@@ -71,6 +71,7 @@
int Parrot_dod_trace_children(Interp *, size_t how_many);
void Parrot_dod_sweep(Interp *, struct Small_Object_Pool *pool);
void Parrot_dod_ms_run_init(Interp *interpreter);
+void Parrot_dod_clear_live_bits(Interp*);
/* GC subsystem init functions */
void Parrot_gc_ms_init(Interp* interpreter);
@@ -78,6 +79,27 @@
/* synchron entry point, mainly for lazy sweeps */
void Parrot_dod_ims_run(Interp *interpreter, UINTVAL flags);
+void Parrot_dod_ims_wb(Interp*, PMC *, PMC *);
+/*
+ * write barrier
+ */
+#if PARROT_GC_IMS
+# define DOD_WRITE_BARRIER(interp, agg, old, new) \
+ do { \
+ if ( \
+ PObj_live_TEST(agg) && \
+ (PObj_get_FLAGS(agg) & PObj_custom_GC_FLAG) && \
+ !PObj_live_TEST(new)) { \
+ Parrot_dod_ims_wb(interp, agg, new); \
+ } \
+ } while (0)
+
+#endif
+
+#if PARROT_GC_MS
+# define DOD_WRITE_BARRIER(interp, agg, old, new)
+#endif
+
#endif /* PARROT_DOD_H_GUARD */
/*
1.127 +26 -14 parrot/src/dod.c
Index: dod.c
===================================================================
RCS file: /cvs/public/parrot/src/dod.c,v
retrieving revision 1.126
retrieving revision 1.127
diff -u -w -r1.126 -r1.127
--- dod.c 17 Aug 2004 11:03:38 -0000 1.126
+++ dod.c 18 Aug 2004 12:53:29 -0000 1.127
@@ -1,6 +1,6 @@
/*
Copyright: 2001-2003 The Perl Foundation. All Rights Reserved.
-$Id: dod.c,v 1.126 2004/08/17 11:03:38 leo Exp $
+$Id: dod.c,v 1.127 2004/08/18 12:53:29 leo Exp $
=head1 NAME
@@ -279,8 +279,10 @@
if (interpreter->profile)
profile_dod_start(interpreter);
/* We have to start somewhere, the interpreter globals is a good place */
+ if (!arena_base->dod_mark_start) {
arena_base->dod_mark_start = arena_base->dod_mark_ptr =
interpreter->iglobals;
+ }
/* mark it as used */
pobject_lives(interpreter, (PObj *)interpreter->iglobals);
@@ -379,7 +381,7 @@
int
Parrot_dod_trace_children(Interp *interpreter, size_t how_many)
{
- PMC *prev = NULL, *next;
+ PMC *next;
struct Arenas *arena_base = interpreter->arena_base;
INTVAL i = 0;
UINTVAL mask = PObj_data_is_PMC_array_FLAG | PObj_custom_mark_FLAG;
@@ -400,7 +402,7 @@
profile_dod_start(interpreter);
pt_DOD_mark_root_finished(interpreter);
- for (; current != prev; current = PMC_next_for_GC(current)) {
+ for (; ; current = next) {
UINTVAL bits = PObj_get_FLAGS(current) & mask;
if (lazy_dod && arena_base->num_early_PMCs_seen >=
@@ -409,6 +411,10 @@
}
arena_base->dod_trace_ptr = current;
/*
+ * short-term hack to color objects black
+ */
+ PObj_get_FLAGS(current) |= PObj_custom_GC_FLAG;
+ /*
* clearing the flag is much more expensive then testing
*/
if (!PObj_needs_early_DOD_TEST(current)
@@ -444,14 +450,16 @@
}
}
+ next = PMC_next_for_GC(current);
+ if (next == current)
+ break;
if (--how_many == 0) {
- if (current != PMC_next_for_GC(current))
- current = PMC_next_for_GC(current);
+ current = next;
break;
}
- prev = current;
}
arena_base->dod_mark_start = current;
+ arena_base->dod_trace_ptr = NULL;
if (interpreter->profile)
profile_dod_end(interpreter, PARROT_PROF_DOD_p2);
return 1;
@@ -762,6 +770,7 @@
total_used++;
#if !ARENA_DOD_FLAGS
PObj_live_CLEAR(b);
+ PObj_get_FLAGS(b) &= ~PObj_custom_GC_FLAG;
#endif
}
else {
@@ -989,7 +998,7 @@
/*
-=item C<static void clear_live_bits(Parrot_Interp interpreter)>
+=item C<static void Parrot_dod_clear_live_bits(Parrot_Interp interpreter)>
Run through all PMC arenas and clear live bits.
@@ -997,8 +1006,9 @@
*/
-static void
-clear_live_bits(Parrot_Interp interpreter)
+void Parrot_dod_clear_live_bits(Parrot_Interp interpreter);
+void
+Parrot_dod_clear_live_bits(Parrot_Interp interpreter)
{
struct Small_Object_Pool *pool = interpreter->arena_base->pmc_pool;
struct Small_Object_Arena *arena;
@@ -1098,6 +1108,7 @@
int j;
arena_base->dod_trace_ptr = NULL;
+ arena_base->dod_mark_start = NULL;
arena_base->num_early_PMCs_seen = 0;
arena_base->num_extended_PMCs = 0;
#if ARENA_DOD_FLAGS
@@ -1139,6 +1150,8 @@
/* Now go trace the PMCs */
if (trace_active_PMCs(interpreter, flags & DOD_trace_stack_FLAG)) {
+ arena_base->dod_trace_ptr = NULL;
+ arena_base->dod_mark_ptr = NULL;
/*
* mark is now finished
*/
@@ -1176,7 +1189,7 @@
* the live bits, but e.g. t/pmc/timer_7 succeeds w/o this
*/
#if 1
- clear_live_bits(interpreter);
+ Parrot_dod_clear_live_bits(interpreter);
#endif
if (interpreter->profile)
profile_dod_end(interpreter, PARROT_PROF_DOD_p2);
@@ -1184,7 +1197,6 @@
pt_DOD_stop_mark(interpreter);
/* Note it */
arena_base->dod_runs++;
- arena_base->dod_trace_ptr = NULL;
--arena_base->DOD_block_level;
return;
}
1.5 +133 -21 parrot/src/gc_ims.c
Index: gc_ims.c
===================================================================
RCS file: /cvs/public/parrot/src/gc_ims.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -w -r1.4 -r1.5
--- gc_ims.c 17 Aug 2004 11:03:38 -0000 1.4
+++ gc_ims.c 18 Aug 2004 12:53:29 -0000 1.5
@@ -1,6 +1,6 @@
/*
Copyright: 2001-2004 The Perl Foundation. All Rights Reserved.
-$Id: gc_ims.c,v 1.4 2004/08/17 11:03:38 leo Exp $
+$Id: gc_ims.c,v 1.5 2004/08/18 12:53:29 leo Exp $
=head1 NAME
@@ -337,6 +337,7 @@
*/
#include "parrot/parrot.h"
+#include <assert.h>
/*
* size of one arena
@@ -360,11 +361,18 @@
*/
#define REFILL_FACTOR 0.5
+#if 0
+# define IMS_DEBUG(x) fprintf x
+#else
+# define IMS_DEBUG(x)
+#endif
+
typedef enum { /* these states have to be in execution order */
GC_IMS_INITIAL, /* memory subsystem setup */
GC_IMS_STARTING, /* wait for DOD_block to clear */
GC_IMS_RE_INIT, /* start of normal operation - mark root */
GC_IMS_MARKING, /* mark children */
+ GC_IMS_START_SWEEP, /* mark finished, start sweep buffers */
GC_IMS_SWEEP, /* sweep buffers */
GC_IMS_COLLECT, /* collect buffer memory */
GC_IMS_FINISHED, /* update statistics */
@@ -385,12 +393,42 @@
static void parrot_gc_ims_run_increment(Interp*);
+/*
+
+=item C<static void gc_ims_add_free_object(Interp *interpreter,
+ struct Small_Object_Pool *pool, void *to_add)>
+
+Add object C<to_add> to the free_list in the given pool.
+C<pool->num_free_objects> has to be updated by the caller.
+
+=item C<static void *
+gc_ims_get_free_object(Interp *, struct Small_Object_Pool *pool)>
+
+Get a new object off the free_list in the given pool.
+
+=item C<static void
+gc_ims_alloc_objects(Interp *, struct Small_Object_Pool *pool)>
+
+Allocate new objects for the given pool.
+
+=cut
+
+*/
+
static void
gc_ims_add_free_object(Interp *interpreter,
struct Small_Object_Pool *pool, void *to_add)
{
*(void **)to_add = pool->free_list;
pool->free_list = to_add;
+#if ! DISABLE_GC_DEBUG
+ if (GC_DEBUG(interpreter)) {
+ if (pool == interpreter->arena_base->pmc_pool) {
+ PMC *p = to_add;
+ p->vtable = Parrot_base_vtables[enum_class_Null];
+ }
+ }
+#endif
}
@@ -407,6 +445,7 @@
ptr = pool->free_list;
pool->free_list = *(void **)ptr;
PObj_on_free_list_CLEAR((PObj*) ptr);
+ PObj_get_FLAGS((PObj*)ptr) &= ~PObj_custom_GC_FLAG;
--pool->num_free_objects;
#if ! DISABLE_GC_DEBUG
if (GC_DEBUG(interpreter))
@@ -490,7 +529,11 @@
arena_base->lazy_dod = 0;
g_ims = arena_base->gc_private;
Parrot_dod_ms_run_init(interpreter);
+ /*
+ * trace root set w/o system areas
+ */
Parrot_dod_trace_root(interpreter, 0);
+ g_ims->state = GC_IMS_MARKING;
}
@@ -500,9 +543,8 @@
Mark a bunch of children.
-TODO gather stats of items with and without a next_for_GC field.
+The work depends on item counts with and without a next_for_GC field.
The former are marked immediately, only the latter need real work here.
-Then adjust throttle on this data, so that we don't work too fast.
=cut
@@ -515,19 +557,28 @@
size_t todo;
struct Arenas *arena_base;
double work_factor;
+ PMC *next;
arena_base = interpreter->arena_base;
g_ims = arena_base->gc_private;
+ /*
+ * use statistics from the previous run
+ */
if (g_ims->n_objects) {
work_factor = (double)g_ims->n_extended_PMCs / g_ims->n_objects;
}
else
work_factor = 1.0;
todo = (double)g_ims->alloc_trigger * g_ims->throttle * work_factor;
+ assert(arena_base->lazy_dod == 0);
Parrot_dod_trace_children(interpreter, todo);
- if (arena_base->dod_trace_ptr ==
- PMC_next_for_GC(arena_base->dod_trace_ptr)) {
- g_ims->state = GC_IMS_SWEEP;
+ /*
+ * check if we are finished with marking - the end is
+ * self-referential
+ */
+ next = arena_base->dod_mark_start;
+ if (next == PMC_next_for_GC(next)) {
+ g_ims->state = GC_IMS_START_SWEEP;
}
}
@@ -551,16 +602,15 @@
int j;
size_t n_objects;
+ IMS_DEBUG((stderr, "\nSWEEP\n"));
g_ims = arena_base->gc_private;
/*
* as we are now gonna kill objects, make sure that we
* have traced the current stack
* except for a lazy run, which is invoked from the run loop
*/
- if (!g_ims->lazy) {
- /* no BARRIER yet - ark all roots */
- Parrot_dod_trace_root(interpreter, 1);
- }
+ /* no BARRIER yet - mark all roots */
+ Parrot_dod_trace_root(interpreter, g_ims->lazy ? 0 : 1);
/*
* mark (again) rest of children
*/
@@ -636,6 +686,7 @@
g_ims = arena_base->gc_private;
g_ims->allocations = 0;
++g_ims->increments;
+ IMS_DEBUG((stderr, "state = %d => ", g_ims->state));
switch (g_ims->state) {
case GC_IMS_INITIAL:
@@ -649,12 +700,15 @@
/* else fall through and start */
case GC_IMS_RE_INIT:
parrot_gc_ims_reinit(interpreter);
- g_ims->state = GC_IMS_MARKING;
break;
case GC_IMS_MARKING:
parrot_gc_ims_mark(interpreter);
break;
+
+ case GC_IMS_START_SWEEP:
+ g_ims->state = GC_IMS_SWEEP;
+ /* fall through */
case GC_IMS_SWEEP:
parrot_gc_ims_sweep(interpreter);
break;
@@ -666,14 +720,25 @@
g_ims->state = GC_IMS_CONSUMING;
/* fall through */
case GC_IMS_CONSUMING:
+ /*
+ * This currently looks only at PMCs and string_headers.
+ * There shouldn't be other pools that could run out of
+ * headers independent of PMCs
+ */
if (arena_base->pmc_pool->num_free_objects <
arena_base->pmc_pool->total_objects * REFILL_FACTOR) {
- g_ims->state = GC_IMS_RE_INIT;
+ g_ims->state = GC_IMS_STARTING;
+ }
+ else if (arena_base->string_header_pool->num_free_objects <
+ arena_base->string_header_pool->total_objects *
+ REFILL_FACTOR) {
+ g_ims->state = GC_IMS_STARTING;
}
break;
default:
PANIC("Unknown state in gc_ims");
}
+ IMS_DEBUG((stderr, "%d\n", g_ims->state));
}
/*
@@ -704,13 +769,17 @@
if (flags & DOD_finish_FLAG) {
/*
- * run until live flags are clear
+ * called from really_destroy. This interpreter is gonna die.
+ * The destruction includes a sweep over PMCs, so that
+ * destructors/finalizers are called.
+ *
+ * Be sure live bits are clear.
*/
- if (g_ims->state < GC_IMS_MARKING)
+ if (g_ims->state < GC_IMS_RE_INIT)
return;
- while (g_ims->state <= GC_IMS_COLLECT) {
- parrot_gc_ims_run_increment(interpreter);
- }
+ if (g_ims->state >= GC_IMS_FINISHED)
+ return;
+ Parrot_dod_clear_live_bits(interpreter);
return;
}
/* make the test happy that checks the count ;) */
@@ -720,17 +789,32 @@
parrot_gc_ims_run_increment(interpreter);
return;
}
+ /*
+ * lazy DOD handling
+ */
+ IMS_DEBUG((stderr, "\nLAZY state = %d\n", g_ims->state));
g_ims->lazy = lazy;
+ if (g_ims->state >= GC_IMS_COLLECT) {
+ /* we are beyond sweep, timely destruction is done */
+ if (arena_base->num_early_PMCs_seen >= arena_base->num_early_DOD_PMCs)
+ return;
+ /* when not all seen, start a fresh cycle */
+ g_ims->state = GC_IMS_RE_INIT;
+ /* run init, which clears lazy seen counter */
+ parrot_gc_ims_run_increment(interpreter);
+ }
/*
- * XXX this a short-term hack
- * num_early_DOD_PMCs can change any time during operation
- * need a high-prio queue that is always marked first
+ * run through all steps until we see enough PMCs that need timely
+ * destruction or we finished sweeping
*/
while (arena_base->num_early_PMCs_seen < arena_base->num_early_DOD_PMCs) {
parrot_gc_ims_run_increment(interpreter);
if (g_ims->state >= GC_IMS_COLLECT)
break;
}
+ /*
+ * if we stopped early, the lazy run was successful
+ */
if (g_ims->state < GC_IMS_COLLECT)
++arena_base->lazy_dod_runs;
g_ims->lazy = 0;
@@ -738,6 +822,34 @@
/*
+=item C<void Parrot_dod_ims_wb(Interp*, PMC *agg, PMC *new)>
+
+Write barriere called by the DOD_WRITE_BARRIER macro. Always when a
+white object gets store into a black aggregate, either the object must
+be greyed or the aggregate must be rescanned - by greying it.
+
+=cut
+
+*/
+
+#define DOD_IMS_GREY_NEW 1
+
+
+void
+Parrot_dod_ims_wb(Interp* interpreter, PMC *agg, PMC *new)
+{
+#if DOD_IMS_GREY_NEW
+ IMS_DEBUG((stderr, "%d ", ((Gc_ims_private *)interpreter->arena_base->
+ gc_private)->state));
+ pobject_lives(interpreter, (PObj*)new);
+#else
+ PObj_get_FLAGS(agg) &= ~ (PObj_live_FLAG|PObj_custom_GC_FLAG);
+ pobject_lives(interpreter, (PObj*)agg);
+#endif
+}
+
+/*
+
=back
=head1 SEE ALSO
1.128 +3 -7 parrot/src/resources.c
Index: resources.c
===================================================================
RCS file: /cvs/public/parrot/src/resources.c,v
retrieving revision 1.127
retrieving revision 1.128
diff -u -w -r1.127 -r1.128
--- resources.c 15 Aug 2004 04:39:23 -0000 1.127
+++ resources.c 18 Aug 2004 12:53:29 -0000 1.128
@@ -1,6 +1,6 @@
/*
Copyright: 2001-2003 The Perl Foundation. All Rights Reserved.
-$Id: resources.c,v 1.127 2004/08/15 04:39:23 chromatic Exp $
+$Id: resources.c,v 1.128 2004/08/18 12:53:29 leo Exp $
=head1 NAME
@@ -132,13 +132,8 @@
alloc_new_block(interpreter, size, pool);
interpreter->arena_base->mem_allocs_since_last_collect++;
}
- if (0 && GC_DEBUG(interpreter)) {
- Parrot_do_dod_run(interpreter, DOD_trace_stack_FLAG);
- if (pool->compact) {
- (*pool->compact) (interpreter, pool);
- }
- }
if (pool->top_block->free < size) {
+#if PARROT_GC_MS
Parrot_do_dod_run(interpreter, DOD_trace_stack_FLAG);
/* Compact the pool if allowed and worthwhile */
if (pool->compact) {
@@ -152,6 +147,7 @@
}
}
+#endif
if (pool->top_block->free < size) {
if (pool->minimum_block_size < 65536*16)
pool->minimum_block_size *= 2;
1.15 +54 -2 parrot/t/op/gc.t
Index: gc.t
===================================================================
RCS file: /cvs/public/parrot/t/op/gc.t,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -w -r1.14 -r1.15
--- gc.t 24 Jun 2004 10:12:19 -0000 1.14
+++ gc.t 18 Aug 2004 12:53:31 -0000 1.15
@@ -1,6 +1,6 @@
#! perl -w
# Copyright: 2001-2003 The Perl Foundation. All Rights Reserved.
-# $Id: gc.t,v 1.14 2004/06/24 10:12:19 leo Exp $
+# $Id: gc.t,v 1.15 2004/08/18 12:53:31 leo Exp $
=head1 NAME
@@ -17,7 +17,7 @@
=cut
-use Parrot::Test tests => 14;
+use Parrot::Test tests => 15;
output_is( <<'CODE', '1', "sweep 1" );
interpinfo I1, 2 # How many DOD runs have we done already?
@@ -474,3 +474,55 @@
ok 1
10
OUTPUT
+
+output_is(<<'CODE', <<OUTPUT, "write barrier 1");
+ null I2
+ set I3, 100
+lp3:
+ null I0
+ set I1, 1000
+ new P1, .ResizablePMCArray
+lp1:
+ new P2, .ResizablePMCArray
+ new P0, .Integer
+ set P0, I0
+ set P2[0], P0
+ set P1[I0], P2
+ if I0, not_0
+ needs_destroy P0
+ # force marking past P2[0]
+ sweep 0
+not_0:
+ new P3, .Undef
+ new P4, .Undef
+ inc I0
+ lt I0, I1, lp1
+
+ null I0
+ # trace 1
+lp2:
+ set P2, P1[I0]
+ set P2, P2[0]
+ eq P2, I0, ok
+ print "nok\n"
+ print "I0: "
+ print I0
+ print " P2: "
+ print P2
+ print " type: "
+ typeof S0, P2
+ print S0
+ print " I2: "
+ print I2
+ print "\n"
+ exit 1
+ok:
+ inc I0
+ lt I0, I1, lp2
+ inc I2
+ lt I2, I3, lp3
+ print "ok\n"
+ end
+CODE
+ok
+OUTPUT