[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