[pypy-commit] stmgc c8-marker: in-progress: import some code from c7

arigo noreply at buildbot.pypy.org
Sat Mar 7 16:33:45 CET 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: c8-marker
Changeset: r1695:a3f57a07666c
Date: 2015-03-07 16:34 +0100
http://bitbucket.org/pypy/stmgc/changeset/a3f57a07666c/

Log:	in-progress: import some code from c7

diff --git a/c8/stm/core.c b/c8/stm/core.c
--- a/c8/stm/core.c
+++ b/c8/stm/core.c
@@ -528,6 +528,7 @@
         STM_PSEGMENT->safe_point = SP_NO_TRANSACTION;
 
         list_clear(STM_PSEGMENT->modified_old_objects);
+        list_clear(STM_PSEGMENT->modified_old_objects_markers);
         STM_PSEGMENT->last_commit_log_entry = new;
         release_modification_lock(STM_SEGMENT->segment_num);
     }
@@ -557,6 +558,7 @@
         STM_PSEGMENT->transaction_state = TS_NONE;
         STM_PSEGMENT->safe_point = SP_NO_TRANSACTION;
         list_clear(STM_PSEGMENT->modified_old_objects);
+        list_clear(STM_PSEGMENT->modified_old_objects_markers);
         STM_PSEGMENT->last_commit_log_entry = new;
 
         /* do it: */
@@ -630,6 +632,7 @@
             (uintptr_t)obj,     /* obj */
             (uintptr_t)bk_slice,  /* bk_addr */
             NEW_SLICE(slice_off, slice_sz));
+        timing_record_write();
         dprintf(("> append slice %p, off=%lu, sz=%lu\n", bk_slice, slice_off, slice_sz));
         release_modification_lock(STM_SEGMENT->segment_num);
 
@@ -1051,6 +1054,7 @@
 
     assert(STM_PSEGMENT->safe_point == SP_NO_TRANSACTION);
     assert(STM_PSEGMENT->transaction_state == TS_NONE);
+    timing_event(tl, STM_TRANSACTION_START);
     STM_PSEGMENT->transaction_state = TS_REGULAR;
     STM_PSEGMENT->safe_point = SP_RUNNING;
 #ifndef NDEBUG
@@ -1071,6 +1075,7 @@
     }
 
     assert(list_is_empty(STM_PSEGMENT->modified_old_objects));
+    assert(list_is_empty(STM_PSEGMENT->modified_old_objects_markers));
     assert(list_is_empty(STM_PSEGMENT->large_overflow_objects));
     assert(list_is_empty(STM_PSEGMENT->objects_pointing_to_nursery));
     assert(list_is_empty(STM_PSEGMENT->young_weakrefs));
@@ -1080,6 +1085,10 @@
     assert(tree_is_cleared(STM_PSEGMENT->callbacks_on_commit_and_abort[1]));
     assert(list_is_empty(STM_PSEGMENT->young_objects_with_light_finalizers));
     assert(STM_PSEGMENT->finalizers == NULL);
+#ifndef NDEBUG
+    /* this should not be used when objects_pointing_to_nursery == NULL */
+    STM_PSEGMENT->modified_old_objects_markers_num_old = 99999999999999999L;
+#endif
 
     check_nursery_at_transaction_start();
 
@@ -1125,7 +1134,7 @@
 
 /************************************************************/
 
-static void _finish_transaction()
+static void _finish_transaction(enum stm_event_e event)
 {
     stm_thread_local_t *tl = STM_SEGMENT->running_thread;
 
@@ -1136,6 +1145,7 @@
     list_clear(STM_PSEGMENT->objects_pointing_to_nursery);
     list_clear(STM_PSEGMENT->old_objects_with_cards_set);
     list_clear(STM_PSEGMENT->large_overflow_objects);
+    timing_event(tl, event);
 
     release_thread_segment(tl);
     /* cannot access STM_SEGMENT or STM_PSEGMENT from here ! */
@@ -1236,7 +1246,7 @@
 
     /* done */
     stm_thread_local_t *tl = STM_SEGMENT->running_thread;
-    _finish_transaction();
+    _finish_transaction(STM_TRANSACTION_COMMIT);
     /* cannot access STM_SEGMENT or STM_PSEGMENT from here ! */
 
     s_mutex_unlock();
@@ -1369,7 +1379,7 @@
                                                    : NURSERY_END;
     }
 
-    _finish_transaction();
+    _finish_transaction(STM_TRANSACTION_ABORT);
     /* cannot access STM_SEGMENT or STM_PSEGMENT from here ! */
 
     return tl;
diff --git a/c8/stm/core.h b/c8/stm/core.h
--- a/c8/stm/core.h
+++ b/c8/stm/core.h
@@ -93,6 +93,12 @@
     struct tree_s *young_outside_nursery;
     struct tree_s *nursery_objects_shadows;
 
+    /* For each entry in 'modified_old_objects', we have two entries
+       in the following list, which give the marker at the time we added
+       the entry to modified_old_objects. */
+    struct list_s *modified_old_objects_markers;
+    uintptr_t modified_old_objects_markers_num_old;
+
     /* List of all young weakrefs to check in minor collections. These
        are the only weakrefs that may point to young objects and never
        contain NULL. */
diff --git a/c8/stm/gcpage.c b/c8/stm/gcpage.c
--- a/c8/stm/gcpage.c
+++ b/c8/stm/gcpage.c
@@ -386,6 +386,20 @@
     LIST_FREE(uniques);
 }
 
+static void mark_visit_from_markers(void)
+{
+    long j;
+    for (j = 1; j < NB_SEGMENTS; j++) {
+        struct stm_priv_segment_info_s *pseg = get_priv_segment(j);
+        struct list_s *lst = pseg->modified_old_objects_markers;
+        uintptr_t i;
+        for (i = list_count(lst); i > 0; i -= 2) {
+            mark_visit_possibly_new_object((object_t *)list_item(lst, i - 1),
+                                           pseg);
+        }
+    }
+}
+
 static void mark_visit_from_roots(void)
 {
     if (testing_prebuilt_objs != NULL) {
@@ -683,6 +697,7 @@
     /* marking */
     LIST_CREATE(marked_objects_to_trace);
     mark_visit_from_modified_objects();
+    mark_visit_from_markers();
     mark_visit_from_roots();
     mark_visit_from_finalizer_pending();
 
diff --git a/c7/stm/marker.c b/c8/stm/marker.c
copy from c7/stm/marker.c
copy to c8/stm/marker.c
--- a/c7/stm/marker.c
+++ b/c8/stm/marker.c
@@ -31,15 +31,6 @@
     }
 }
 
-static void _timing_fetch_inev(void)
-{
-    stm_loc_marker_t marker;
-    marker.tl = STM_SEGMENT->running_thread;
-    marker_fetch(&marker);
-    STM_PSEGMENT->marker_inev.odd_number = marker.odd_number;
-    STM_PSEGMENT->marker_inev.object = marker.object;
-}
-
 static void marker_fetch_obj_write(object_t *obj, stm_loc_marker_t *out_marker)
 {
     /* From 'out_marker->tl', fill in 'out_marker->segment_base' and
@@ -48,23 +39,16 @@
     */
     assert(_has_mutex());
 
-    /* here, we acquired the other thread's marker_lock, which means that:
-
-       (1) it has finished filling 'modified_old_objects' after it sets
-           up the write_locks[] value that we're conflicting with
-
-       (2) it is not mutating 'modified_old_objects' right now (we have
-           the global mutex_lock at this point too).
-    */
-    long i;
+    long i, num;
     int in_segment_num = out_marker->tl->associated_segment_num;
     assert(in_segment_num >= 1);
     struct stm_priv_segment_info_s *pseg = get_priv_segment(in_segment_num);
     struct list_s *mlst = pseg->modified_old_objects;
     struct list_s *mlstm = pseg->modified_old_objects_markers;
-    assert(list_count(mlstm) <= 2 * list_count(mlst));
-    for (i = list_count(mlstm) / 2; --i >= 0; ) {
-        if (list_item(mlst, i) == (uintptr_t)obj) {
+    num = list_count(mlstm) / 2;
+    assert(num * 3 <= list_count(mlst));
+    for (i = 0; i < num; i++) {
+        if (list_item(mlst, i * 3) == (uintptr_t)obj) {
             out_marker->odd_number = list_item(mlstm, i * 2 + 0);
             out_marker->object = (object_t *)list_item(mlstm, i * 2 + 1);
             return;
@@ -80,7 +64,7 @@
     marker.tl = STM_SEGMENT->running_thread;
     marker_fetch(&marker);
 
-    long base_count = list_count(STM_PSEGMENT->modified_old_objects);
+    long base_count = list_count(STM_PSEGMENT->modified_old_objects) / 3;
     struct list_s *mlstm = STM_PSEGMENT->modified_old_objects_markers;
     while (list_count(mlstm) < 2 * base_count) {
         mlstm = list_append2(mlstm, 0, 0);
@@ -89,55 +73,21 @@
     STM_PSEGMENT->modified_old_objects_markers = mlstm;
 }
 
-static void _timing_contention(enum stm_event_e kind,
-                               uint8_t other_segment_num, object_t *obj)
+static void timing_write_read_contention(object_t *obj)
 {
-    struct stm_priv_segment_info_s *other_pseg;
-    other_pseg = get_priv_segment(other_segment_num);
+    if (stmcb_timing_event == NULL)
+        return;
 
-    char *other_segment_base = other_pseg->pub.segment_base;
-    acquire_marker_lock(other_segment_base);
+    /* Collect the older location of the write from the current thread. */
+    stm_loc_marker_t marker;
+    marker.tl = STM_SEGMENT->running_thread;
+    marker.segment_base = STM_SEGMENT->segment_base;
+    marker_fetch_obj_write(obj, &marker);
 
-    stm_loc_marker_t markers[2];
-
-    /* Collect the location for myself.  It's usually the current
-       location, except in a write-read abort, in which case it's the
-       older location of the write. */
-    markers[0].tl = STM_SEGMENT->running_thread;
-    markers[0].segment_base = STM_SEGMENT->segment_base;
-
-    if (kind == STM_CONTENTION_WRITE_READ)
-        marker_fetch_obj_write(obj, &markers[0]);
-    else
-        marker_fetch(&markers[0]);
-
-    /* For some categories, we can also collect the relevant information
-       for the other segment. */
-    markers[1].tl = other_pseg->pub.running_thread;
-    markers[1].segment_base = other_pseg->pub.segment_base;
-
-    switch (kind) {
-    case STM_CONTENTION_WRITE_WRITE:
-        marker_fetch_obj_write(obj, &markers[1]);
-        break;
-    case STM_CONTENTION_INEVITABLE:
-        markers[1].odd_number = other_pseg->marker_inev.odd_number;
-        markers[1].object = other_pseg->marker_inev.object;
-        break;
-    default:
-        markers[1].odd_number = 0;
-        markers[1].object = NULL;
-        break;
-    }
-
-    stmcb_timing_event(markers[0].tl, kind, markers);
-
-    /* only release the lock after stmcb_timing_event(), otherwise it could
-       run into race conditions trying to interpret 'markers[1].object' */
-    release_marker_lock(other_segment_base);
+    stmcb_timing_event(marker.tl, STM_CONTENTION_WRITE_READ, &marker);
 }
 
 
 void (*stmcb_timing_event)(stm_thread_local_t *tl, /* the local thread */
                            enum stm_event_e event,
-                           stm_loc_marker_t *markers);
+                           stm_loc_marker_t *marker);
diff --git a/c7/stm/marker.h b/c8/stm/marker.h
copy from c7/stm/marker.h
copy to c8/stm/marker.h
--- a/c7/stm/marker.h
+++ b/c8/stm/marker.h
@@ -1,8 +1,6 @@
 
 static void _timing_record_write(void);
-static void _timing_fetch_inev(void);
-static void _timing_contention(enum stm_event_e kind,
-                               uint8_t other_segment_num, object_t *obj);
+static void timing_write_read_contention(object_t *obj);
 
 
 #define timing_event(tl, event)                                         \
@@ -10,10 +8,3 @@
 
 #define timing_record_write()                                           \
     (stmcb_timing_event != NULL ? _timing_record_write() : (void)0)
-
-#define timing_fetch_inev()                                             \
-    (stmcb_timing_event != NULL ? _timing_fetch_inev() : (void)0)
-
-#define timing_contention(kind, other_segnum, obj)                      \
-    (stmcb_timing_event != NULL ?                                       \
-        _timing_contention(kind, other_segnum, obj) : (void)0)
diff --git a/c8/stm/nursery.c b/c8/stm/nursery.c
--- a/c8/stm/nursery.c
+++ b/c8/stm/nursery.c
@@ -410,6 +410,18 @@
     }
 }
 
+static void collect_roots_from_markers(uintptr_t num_old)
+{
+    dprintf(("collect_roots_from_markers\n"));
+    /* visit the marker objects */
+    struct list_s *mlst = STM_PSEGMENT->modified_old_objects_markers;
+    STM_PSEGMENT->modified_old_objects_markers_num_old = list_count(mlst);
+    uintptr_t i, total = list_count(mlst);
+    assert((total & 1) == 0);
+    for (i = num_old + 1; i < total; i += 2) {
+        minor_trace_if_young((object_t **)list_ptr_to_item(mlst, i));
+    }
+}
 
 static void collect_objs_still_young_but_with_finalizers(void)
 {
@@ -494,6 +506,13 @@
     dprintf(("minor_collection commit=%d\n", (int)commit));
 
     STM_PSEGMENT->minor_collect_will_commit_now = commit;
+
+    uintptr_t num_old;
+    if (STM_PSEGMENT->overflow_number_has_been_used)
+        num_old = STM_PSEGMENT->modified_old_objects_markers_num_old;
+    else
+        num_old = 0;
+
     if (!commit) {
         /* 'STM_PSEGMENT->overflow_number' is used now by this collection,
            in the sense that it's copied to the overflow objects */
@@ -502,6 +521,8 @@
 
     collect_cardrefs_to_nursery();
 
+    collect_roots_from_markers(num_old);
+
     collect_roots_in_nursery();
 
     if (STM_PSEGMENT->finalizers != NULL)
diff --git a/c8/stm/setup.c b/c8/stm/setup.c
--- a/c8/stm/setup.c
+++ b/c8/stm/setup.c
@@ -100,6 +100,7 @@
         pr->pub.segment_num = i;
         pr->pub.segment_base = segment_base;
         pr->modified_old_objects = list_create();
+        pr->modified_old_objects_markers = list_create();
         pr->large_overflow_objects = list_create();
         pr->young_weakrefs = list_create();
         pr->old_weakrefs = list_create();
@@ -152,6 +153,7 @@
         list_free(pr->objects_pointing_to_nursery);
         list_free(pr->old_objects_with_cards_set);
         list_free(pr->modified_old_objects);
+        list_free(pr->modified_old_objects_markers);
         assert(list_is_empty(pr->large_overflow_objects));
         list_free(pr->large_overflow_objects);
         list_free(pr->young_weakrefs);
diff --git a/c8/stmgc.c b/c8/stmgc.c
--- a/c8/stmgc.c
+++ b/c8/stmgc.c
@@ -14,6 +14,7 @@
 #include "stm/gcpage.h"
 #include "stm/extra.h"
 #include "stm/fprintcolor.h"
+#include "stm/marker.h"
 #include "stm/rewind_setjmp.h"
 #include "stm/finalizer.h"
 
@@ -34,5 +35,6 @@
 #include "stm/core.c"
 #include "stm/extra.c"
 #include "stm/fprintcolor.c"
+#include "stm/marker.c"
 #include "stm/rewind_setjmp.c"
 #include "stm/finalizer.c"
diff --git a/c8/stmgc.h b/c8/stmgc.h
--- a/c8/stmgc.h
+++ b/c8/stmgc.h
@@ -342,6 +342,69 @@
 void stm_resume_all_other_threads(void);
 
 
+/* Profiling events.  In the comments: content of the markers, if any */
+enum stm_event_e {
+    /* always STM_TRANSACTION_START followed later by one of COMMIT or ABORT */
+    STM_TRANSACTION_START,
+    STM_TRANSACTION_COMMIT,
+    STM_TRANSACTION_ABORT,
+
+    /* write-read contention: a "marker" is included in the PYPYSTM file
+       saying where the write was done.  Followed by STM_TRANSACTION_ABORT. */
+    STM_CONTENTION_WRITE_READ,
+
+    /* always one STM_WAIT_xxx followed later by STM_WAIT_DONE */
+    STM_WAIT_FREE_SEGMENT,
+    STM_WAIT_OTHER_INEVITABLE,
+    STM_WAIT_DONE,
+
+    /* start and end of GC cycles */
+    STM_GC_MINOR_START,
+    STM_GC_MINOR_DONE,
+    STM_GC_MAJOR_START,
+    STM_GC_MAJOR_DONE,
+
+    _STM_EVENT_N
+};
+
+#define STM_EVENT_NAMES                         \
+    "transaction start",                        \
+    "transaction commit",                       \
+    "transaction abort",                        \
+    "contention write read",                    \
+    "wait free segment",                        \
+    "wait other inevitable",                    \
+    "wait done",                                \
+    "gc minor start",                           \
+    "gc minor done",                            \
+    "gc major start",                           \
+    "gc major done"
+
+/* The markers pushed in the shadowstack are an odd number followed by a
+   regular pointer. */
+typedef struct {
+    stm_thread_local_t *tl;
+    char *segment_base;    /* base to interpret the 'object' below */
+    uintptr_t odd_number;  /* marker odd number, or 0 if marker is missing */
+    object_t *object;      /* marker object, or NULL if marker is missing */
+} stm_loc_marker_t;
+extern void (*stmcb_timing_event)(stm_thread_local_t *tl, /* the local thread */
+                                  enum stm_event_e event,
+                                  stm_loc_marker_t *marker);
+
+/* Calling this sets up a stmcb_timing_event callback that will produce
+   a binary file called 'profiling_file_name'.  Call it with
+   'fork_mode == 0' for only the main process, and with
+   'fork_mode == 1' to also write files called
+   'profiling_file_name.fork<PID>' after a fork().  Call it with NULL to
+   stop profiling.  Returns -1 in case of error (see errno then).
+   The optional 'expand_marker' function pointer is called to expand
+   the marker's odd_number and object into data, starting at the given
+   position and with the given maximum length. */
+int stm_set_timing_log(const char *profiling_file_name, int fork_mode,
+                       int expand_marker(stm_loc_marker_t *, char *, int));
+
+
 /* Convenience macros to push the markers into the shadowstack */
 #define STM_PUSH_MARKER(tl, odd_num, p)   do {  \
     uintptr_t _odd_num = (odd_num);             \
diff --git a/c8/test/support.py b/c8/test/support.py
--- a/c8/test/support.py
+++ b/c8/test/support.py
@@ -124,6 +124,46 @@
 long stm_call_on_abort(stm_thread_local_t *, void *key, void callback(void *));
 long stm_call_on_commit(stm_thread_local_t *, void *key, void callback(void *));
 
+/* Profiling events.  In the comments: content of the markers, if any */
+enum stm_event_e {
+    /* always STM_TRANSACTION_START followed later by one of COMMIT or ABORT */
+    STM_TRANSACTION_START,
+    STM_TRANSACTION_COMMIT,
+    STM_TRANSACTION_ABORT,
+
+    /* write-read contention: a "marker" is included in the PYPYSTM file
+       saying where the write was done.  Followed by STM_TRANSACTION_ABORT. */
+    STM_CONTENTION_WRITE_READ,
+
+    /* always one STM_WAIT_xxx followed later by STM_WAIT_DONE */
+    STM_WAIT_FREE_SEGMENT,
+    STM_WAIT_OTHER_INEVITABLE,
+    STM_WAIT_DONE,
+
+    /* start and end of GC cycles */
+    STM_GC_MINOR_START,
+    STM_GC_MINOR_DONE,
+    STM_GC_MAJOR_START,
+    STM_GC_MAJOR_DONE,
+    ...
+};
+
+typedef struct {
+    stm_thread_local_t *tl;
+    /* If segment_base==NULL, the remaining fields are undefined.  If non-NULL,
+       the rest is a marker to interpret from this segment_base addr. */
+    char *segment_base;
+    uintptr_t odd_number;
+    object_t *object;
+} stm_loc_marker_t;
+
+typedef void (*stmcb_timing_event_fn)(stm_thread_local_t *tl,
+                                      enum stm_event_e event,
+                                      stm_loc_marker_t *markers);
+stmcb_timing_event_fn stmcb_timing_event;
+
+int stm_set_timing_log(const char *profiling_file_name, int prof_mode,
+                       int expand_marker(stm_loc_marker_t *, char *, int));
 
 long _stm_count_modified_old_objects(void);
 long _stm_count_objects_pointing_to_nursery(void);
diff --git a/c7/test/test_marker.py b/c8/test/test_marker.py
copy from c7/test/test_marker.py
copy to c8/test/test_marker.py


More information about the pypy-commit mailing list