[pypy-commit] stmgc default: add _GC_DEBUGPRINTS, comments, and some fairly untested code about tracing h_original in major_collections
Raemi
noreply at buildbot.pypy.org
Wed Jul 3 17:04:25 CEST 2013
Author: Remi Meier <meierrem at student.ethz.ch>
Branch:
Changeset: r344:f37e2b89a0fc
Date: 2013-07-03 17:03 +0200
http://bitbucket.org/pypy/stmgc/changeset/f37e2b89a0fc/
Log: add _GC_DEBUGPRINTS, comments, and some fairly untested code about
tracing h_original in major_collections
diff --git a/c4/Makefile b/c4/Makefile
--- a/c4/Makefile
+++ b/c4/Makefile
@@ -21,15 +21,16 @@
C_FILES = et.c lists.c steal.c nursery.c gcpage.c \
stmsync.c dbgmem.c fprintcolor.c
-DEBUG = -g -DGC_NURSERY=0x10000 -D_GC_DEBUG=1
+DEBUG = -g -DGC_NURSERY=0x10000 -D_GC_DEBUG=1 -DDUMP_EXTRA=1 -D_GC_DEBUGPRINTS=1
-# note that we don't say -DNDEBUG, so that asserts should still be compiled it
+# note that we don't say -DNDEBUG, so that asserts should still be compiled in
+# also, all debug code with extra checks but not the debugprints
build-%: %.c ${H_FILES} ${C_FILES} stmgc.c
- gcc -pthread -O2 -g $< -o build-$* -Wall stmgc.c -lrt
+ gcc -pthread -DGC_NURSERY=0x10000 -D_GC_DEBUG=1 -g $< -o build-$* -Wall stmgc.c -lrt
debug-%: %.c ${H_FILES} ${C_FILES}
- gcc -pthread ${DEBUG} $< -o debug-$* -Wall ${C_FILES} -lrt
+ gcc -pthread -DDUMP_EXTRA=1 ${DEBUG} $< -o debug-$* -Wall ${C_FILES} -lrt
release-%: %.c ${H_FILES} ${C_FILES} stmgc.c
gcc -pthread -DNDEBUG -O2 -g $< -o release-$* -Wall stmgc.c -lrt
diff --git a/c4/demo_random.c b/c4/demo_random.c
--- a/c4/demo_random.c
+++ b/c4/demo_random.c
@@ -105,6 +105,15 @@
*(to++) = *(from++);
}
+gcptr allocate_old(size_t size, int tid)
+{
+ gcptr p = stmgcpage_malloc(size);
+ memset(p, 0, size);
+ p->h_tid = GCFLAG_OLD | GCFLAG_WRITE_BARRIER | tid;
+ p->h_revision = -INT_MAX;
+ return p;
+}
+
gcptr allocate_pseudoprebuilt(size_t size, int tid)
{
gcptr x = calloc(1, size);
@@ -166,6 +175,15 @@
return 0;
}
+#ifdef _GC_DEBUG
+int is_free_old(gcptr p)
+{
+ fprintf(stdout, "\n=== check ===\n");
+ return (!_stm_can_access_memory((char*)p))
+ || (p->h_tid == DEBUG_WORD(0xDD));
+}
+#endif
+
void check_not_free(gcptr p)
{
assert(p != NULL);
@@ -179,6 +197,16 @@
if (p != NULL) {
check_not_free(p);
classify(p); // additional asserts
+ if (p->h_original && !(p->h_tid & GCFLAG_PREBUILT_ORIGINAL)) {
+ // must point to valid old object
+ gcptr id = (gcptr)p->h_original;
+ assert(id->h_tid & GCFLAG_OLD);
+ check_not_free(id);
+#ifdef _GC_DEBUG
+ if (!is_shared_prebuilt(id) && !(id->h_tid & GCFLAG_PREBUILT))
+ assert(!is_free_old(id));
+#endif
+ }
}
}
diff --git a/c4/fprintcolor.c b/c4/fprintcolor.c
--- a/c4/fprintcolor.c
+++ b/c4/fprintcolor.c
@@ -5,7 +5,7 @@
{
va_list ap;
-#ifdef _GC_DEBUG
+#ifdef _GC_DEBUGPRINTS
dprintf(("STM Subsystem: Fatal Error\n"));
#else
fprintf(stderr, "STM Subsystem: Fatal Error\n");
@@ -19,7 +19,7 @@
}
-#ifdef _GC_DEBUG
+#ifdef _GC_DEBUGPRINTS
static __thread revision_t tcolor = 0;
static revision_t tnextid = 0;
diff --git a/c4/fprintcolor.h b/c4/fprintcolor.h
--- a/c4/fprintcolor.h
+++ b/c4/fprintcolor.h
@@ -6,7 +6,7 @@
__attribute__((format (printf, 1, 2), noreturn));
-#ifdef _GC_DEBUG
+#ifdef _GC_DEBUGPRINTS
#define dprintf(args) threadcolor_printf args
int dprintfcolor(void);
diff --git a/c4/gcpage.c b/c4/gcpage.c
--- a/c4/gcpage.c
+++ b/c4/gcpage.c
@@ -235,6 +235,15 @@
if (!(obj->h_revision & 2)) {
/* go visit the more recent version */
obj = (gcptr)obj->h_revision;
+ if ((gcptr)obj->h_original == prev_obj
+ && !(prev_obj->h_tid & GCFLAG_VISITED)) {
+ assert(0); // why never hit?
+ // prev_obj is the ID copy
+ prev_obj->h_tid &= ~GCFLAG_PUBLIC_TO_PRIVATE;
+ /* see fix_outdated() */
+ prev_obj->h_tid |= GCFLAG_VISITED;
+ gcptrlist_insert(&objects_to_trace, prev_obj);
+ }
}
else {
/* it's a stub: keep it if it points to a protected version,
@@ -244,7 +253,11 @@
*/
assert(obj->h_tid & GCFLAG_STUB);
obj = (gcptr)(obj->h_revision - 2);
- if (!(obj->h_tid & GCFLAG_PUBLIC)) {
+ if (!(obj->h_tid & GCFLAG_PUBLIC) || !(prev_obj->h_original)) {
+ assert(prev_obj->h_original); // why never hit?
+ assert(!(obj->h_tid & GCFLAG_PUBLIC));
+ /* never?: stub->public where stub is id copy? */
+
prev_obj->h_tid |= GCFLAG_VISITED;
assert(*pobj == prev_obj);
gcptr obj1 = obj;
@@ -256,6 +269,9 @@
}
if (!(obj->h_revision & 3)) {
+ /* obj is neither a stub nor a most recent revision:
+ completely ignore obj->h_revision */
+
obj = (gcptr)obj->h_revision;
assert(obj->h_tid & GCFLAG_PUBLIC);
prev_obj->h_revision = (revision_t)obj;
@@ -274,7 +290,21 @@
assert(obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED);
gcptr B = (gcptr)obj->h_revision;
assert(B->h_tid & (GCFLAG_PUBLIC | GCFLAG_BACKUP_COPY));
-
+
+ gcptr id_copy = (gcptr)obj->h_original;
+ if (id_copy && id_copy != B) {
+ assert(id_copy == (gcptr)B->h_original);
+ assert(!(obj->h_tid & GCFLAG_PREBUILT_ORIGINAL));
+ if (!(id_copy->h_tid & GCFLAG_PREBUILT_ORIGINAL)) {
+ gcptrlist_insert(&objects_to_trace, id_copy);
+ }
+ else {
+ /* prebuilt originals won't get collected anyway
+ and if they are not reachable in any other way,
+ we only ever need their location, not their content */
+ }
+ }
+
obj->h_tid |= GCFLAG_VISITED;
B->h_tid |= GCFLAG_VISITED;
assert(!(obj->h_tid & GCFLAG_STUB));
@@ -375,8 +405,24 @@
outdated, it will be found at that time */
gcptr R = item->addr;
gcptr L = item->val;
+
+ /* Objects that were not visited yet must have the PUB_TO_PRIV
+ flag. Except if that transaction will abort anyway, then it
+ may be removed from a previous major collection that didn't
+ fix the PUB_TO_PRIV because the transaction was going to
+ abort anyway:
+ 1. minor_collect before major collect (R->L, R is outdated, abort)
+ 2. major collect removes flag
+ 3. major collect again, same thread, no time to abort
+ 4. flag still removed
+ */
+ assert(IMPLIES(!(R->h_tid & GCFLAG_VISITED) && d->active > 0,
+ R->h_tid & GCFLAG_PUBLIC_TO_PRIVATE));
visit_keep(R);
if (L != NULL) {
+ /* minor collection found R->L in public_to_young
+ and R was modified. It then sets item->val to NULL and wants
+ to abort later. */
revision_t v = L->h_revision;
visit_keep(L);
/* a bit of custom logic here: if L->h_revision used to
@@ -384,8 +430,10 @@
keep this property, even though visit_keep(L) might
decide it would be better to make it point to a more
recent copy. */
- if (v == (revision_t)R)
+ if (v == (revision_t)R) {
+ assert(L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED);
L->h_revision = v; /* restore */
+ }
}
} G2L_LOOP_END;
@@ -448,6 +496,7 @@
just removing it is very wrong --- we want 'd' to abort.
*/
if (obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) {
+ /* follow obj to its backup */
assert(IS_POINTER(obj->h_revision));
obj = (gcptr)obj->h_revision;
}
@@ -482,14 +531,16 @@
/* We are now after visiting all objects, and we know the
* transaction isn't aborting because of this collection. We have
* cleared GCFLAG_PUBLIC_TO_PRIVATE from public objects at the end
- * of the chain. Now we have to set it again on public objects that
- * have a private copy.
+ * of the chain (head revisions). Now we have to set it again on
+ * public objects that have a private copy.
*/
wlog_t *item;
dprintf(("fix public_to_private on thread %p\n", d));
G2L_LOOP_FORWARD(d->public_to_private, item) {
+ assert(item->addr->h_tid & GCFLAG_VISITED);
+ assert(item->val->h_tid & GCFLAG_VISITED);
assert(item->addr->h_tid & GCFLAG_PUBLIC);
/* assert(is_private(item->val)); but in the other thread,
diff --git a/c4/nursery.c b/c4/nursery.c
--- a/c4/nursery.c
+++ b/c4/nursery.c
@@ -48,7 +48,8 @@
inbetween the preceeding minor_collect() and
this assert (committransaction() ->
updatechainheads() -> stub_malloc() -> ...): */
- /* assert(!minor_collect_anything_to_do(d)); */
+ assert(!minor_collect_anything_to_do(d)
+ || d->nursery_current == d->nursery_end);
stm_free(d->nursery_base, GC_NURSERY);
gcptrlist_delete(&d->old_objects_to_trace);
@@ -430,6 +431,7 @@
gcptr P = items[i];
assert(P->h_tid & GCFLAG_PUBLIC);
assert(P->h_tid & GCFLAG_OLD);
+ assert(P->h_tid & GCFLAG_PUBLIC_TO_PRIVATE);
revision_t v = ACCESS_ONCE(P->h_revision);
wlog_t *item;
diff --git a/c4/stmsync.c b/c4/stmsync.c
--- a/c4/stmsync.c
+++ b/c4/stmsync.c
@@ -80,6 +80,7 @@
int stm_enter_callback_call(void)
{
int token = (thread_descriptor == NULL);
+ dprintf(("enter_callback_call(tok=%d)\n", token));
if (token == 1) {
stmgcpage_acquire_global_lock();
DescriptorInit();
@@ -93,6 +94,7 @@
void stm_leave_callback_call(int token)
{
+ dprintf(("leave_callback_call(%d)\n", token));
if (token == 1)
stmgc_minor_collect(); /* force everything out of the nursery */
More information about the pypy-commit
mailing list