[pypy-commit] pypy stmgc-c8: import stmgc/c8ccc22dbf16

arigo noreply at buildbot.pypy.org
Wed Jun 24 16:35:42 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: stmgc-c8
Changeset: r78297:eeea8ac4da6b
Date: 2015-06-24 16:35 +0200
http://bitbucket.org/pypy/pypy/changeset/eeea8ac4da6b/

Log:	import stmgc/c8ccc22dbf16

diff --git a/rpython/translator/stm/src_stm/revision b/rpython/translator/stm/src_stm/revision
--- a/rpython/translator/stm/src_stm/revision
+++ b/rpython/translator/stm/src_stm/revision
@@ -1,1 +1,1 @@
-9ffba4fe03df
+c8ccc22dbf16
diff --git a/rpython/translator/stm/src_stm/stm/core.c b/rpython/translator/stm/src_stm/stm/core.c
--- a/rpython/translator/stm/src_stm/stm/core.c
+++ b/rpython/translator/stm/src_stm/stm/core.c
@@ -511,10 +511,12 @@
            try to detach an inevitable transaction regularly */
         detached = fetch_detached_transaction();
         if (detached == 0) {
+            EMIT_WAIT(STM_WAIT_OTHER_INEVITABLE);
             if (!cond_wait_timeout(C_SEGMENT_FREE_OR_SAFE_POINT_REQ, 0.00001))
                 goto wait_some_more;
         }
     }
+    EMIT_WAIT_DONE();
     s_mutex_unlock();
 
     if (detached != 0)
@@ -1130,6 +1132,7 @@
 static void _do_start_transaction(stm_thread_local_t *tl)
 {
     assert(!_stm_in_transaction(tl));
+    tl->wait_event_emitted = 0;
 
     acquire_thread_segment(tl);
     /* GS invalid before this point! */
@@ -1318,6 +1321,7 @@
     }
     assert(STM_SEGMENT->running_thread->self_or_0_if_atomic ==
            (intptr_t)(STM_SEGMENT->running_thread));
+    assert(STM_SEGMENT->running_thread->wait_event_emitted == 0);
 
     dprintf(("> stm_commit_transaction(external=%d)\n", (int)external));
     minor_collection(/*commit=*/ true, external);
@@ -1582,9 +1586,8 @@
 
         if (any_soon_finished_or_inevitable_thread_segment() &&
                 num_waits <= NB_SEGMENTS) {
-#if STM_TESTS
-            timing_become_inevitable(); /* for tests: another transaction */
-            stm_abort_transaction();    /* is already inevitable, abort   */
+#if STM_TESTS                           /* for tests: another transaction */
+            stm_abort_transaction();    /*   is already inevitable, abort */
 #endif
 
             bool timed_out = false;
@@ -1594,6 +1597,7 @@
                     !safe_point_requested()) {
 
                 /* wait until C_SEGMENT_FREE_OR_SAFE_POINT_REQ is signalled */
+                EMIT_WAIT(STM_WAIT_OTHER_INEVITABLE);
                 if (!cond_wait_timeout(C_SEGMENT_FREE_OR_SAFE_POINT_REQ,
                                        0.000054321))
                     timed_out = true;
@@ -1607,14 +1611,17 @@
                    not too common.  We don't want two threads constantly
                    detaching each other. */
                 intptr_t detached = fetch_detached_transaction();
-                if (detached != 0)
+                if (detached != 0) {
+                    EMIT_WAIT_DONE();
                     commit_fetched_detached_transaction(detached);
+                }
             }
             else {
                 num_waits++;
             }
             goto retry_from_start;
         }
+        EMIT_WAIT_DONE();
         if (!_validate_and_turn_inevitable())
             goto retry_from_start;
     }
diff --git a/rpython/translator/stm/src_stm/stm/marker.h b/rpython/translator/stm/src_stm/stm/marker.h
--- a/rpython/translator/stm/src_stm/stm/marker.h
+++ b/rpython/translator/stm/src_stm/stm/marker.h
@@ -15,3 +15,28 @@
 
 #define timing_become_inevitable()                                      \
     (timing_enabled() ? _timing_become_inevitable() : (void)0)
+
+
+static inline void emit_wait(stm_thread_local_t *tl, enum stm_event_e event)
+{
+    if (!timing_enabled())
+        return;
+    if (tl->wait_event_emitted != 0) {
+        if (tl->wait_event_emitted == event)
+            return;
+        stmcb_timing_event(tl, STM_WAIT_DONE, NULL);
+    }
+    tl->wait_event_emitted = event;
+    stmcb_timing_event(tl, event, NULL);
+}
+
+static inline void emit_wait_done(stm_thread_local_t *tl)
+{
+    if (tl->wait_event_emitted != 0) {
+        tl->wait_event_emitted = 0;
+        stmcb_timing_event(tl, STM_WAIT_DONE, NULL);
+    }
+}
+
+#define EMIT_WAIT(event)  emit_wait(STM_SEGMENT->running_thread, event)
+#define EMIT_WAIT_DONE()  emit_wait_done(STM_SEGMENT->running_thread)
diff --git a/rpython/translator/stm/src_stm/stm/prof.c b/rpython/translator/stm/src_stm/stm/prof.c
--- a/rpython/translator/stm/src_stm/stm/prof.c
+++ b/rpython/translator/stm/src_stm/stm/prof.c
@@ -2,7 +2,7 @@
 #include <stdio.h>
 #include <time.h>
 
-static FILE *profiling_file;
+static FILE *volatile profiling_file;
 static char *profiling_basefn = NULL;
 static stm_expand_marker_fn profiling_expand_marker;
 
@@ -26,9 +26,6 @@
 
     struct buf_s buf;
     struct timespec t;
-    clock_gettime(CLOCK_MONOTONIC, &t);
-    buf.tv_sec = t.tv_sec;
-    buf.tv_nsec = t.tv_nsec;
     buf.thread_num = tl->thread_local_counter;
     buf.event = event;
     buf.marker_length = 0;
@@ -39,10 +36,29 @@
                                                     buf.extra, MARKER_LEN_MAX);
     }
 
-    if (fwrite(&buf, offsetof(struct buf_s, extra) + buf.marker_length,
-               1, profiling_file) != 1) {
+    size_t result, outsize = offsetof(struct buf_s, extra) + buf.marker_length;
+    FILE *f = profiling_file;
+    if (f == NULL)
+        return;
+    flockfile(f);
+
+    /* We expect the following CLOCK_MONOTONIC to be really monotonic:
+       it should guarantee that the file will be perfectly ordered by time.
+       That's why we do it inside flockfile()/funlockfile(). */
+    clock_gettime(CLOCK_MONOTONIC, &t);
+    buf.tv_sec = t.tv_sec;
+    buf.tv_nsec = t.tv_nsec;
+
+    result = fwrite_unlocked(&buf, outsize, 1, f);
+    funlockfile(f);
+
+    if (result != 1) {
         fprintf(stderr, "stmgc: profiling log file closed unexpectedly: %m\n");
-        close_timing_log();
+
+        /* xxx the FILE leaks here, but it is better than random crashes if
+           we try to close it while other threads are still writing to it
+        */
+        profiling_file = NULL;
     }
 }
 
@@ -54,11 +70,12 @@
 
 static bool open_timing_log(const char *filename)
 {
-    profiling_file = fopen(filename, "w");
-    if (profiling_file == NULL)
+    FILE *f = fopen(filename, "w");
+    profiling_file = f;
+    if (f == NULL)
         return false;
 
-    fwrite("STMGC-C8-PROF01\n", 16, 1, profiling_file);
+    fwrite("STMGC-C8-PROF01\n", 16, 1, f);
     stmcb_timing_event = _stm_profiling_event;
     return true;
 }
@@ -66,9 +83,11 @@
 static bool close_timing_log(void)
 {
     if (stmcb_timing_event == &_stm_profiling_event) {
+        FILE *f = profiling_file;
         stmcb_timing_event = NULL;
-        fclose(profiling_file);
         profiling_file = NULL;
+        if (f != NULL)
+            fclose(f);
         return true;
     }
     return false;
@@ -76,8 +95,9 @@
 
 static void prof_forksupport_prepare(void)
 {
-    if (profiling_file != NULL)
-        fflush(profiling_file);
+    FILE *f = profiling_file;
+    if (f != NULL)
+        fflush(f);
 }
 
 static void prof_forksupport_child(void)
diff --git a/rpython/translator/stm/src_stm/stm/sync.c b/rpython/translator/stm/src_stm/stm/sync.c
--- a/rpython/translator/stm/src_stm/stm/sync.c
+++ b/rpython/translator/stm/src_stm/stm/sync.c
@@ -243,13 +243,13 @@
     /* No segment available.  Wait until release_thread_segment()
        signals that one segment has been freed.  Note that we prefer
        waiting rather than detaching an inevitable transaction, here. */
-    timing_event(tl, STM_WAIT_FREE_SEGMENT);
+    emit_wait(tl, STM_WAIT_FREE_SEGMENT);
     cond_wait(C_SEGMENT_FREE);
-    timing_event(tl, STM_WAIT_DONE);
 
     goto retry_from_start;
 
  got_num:
+    emit_wait_done(tl);
     OPT_ASSERT(num >= 0 && num < NB_SEGMENTS-1);
     sync_ctl.in_use1[num+1] = 1;
     assert(STM_SEGMENT->segment_num == num+1);
@@ -425,15 +425,15 @@
 #ifdef STM_TESTS
         abort_with_mutex();
 #endif
-        timing_event(STM_SEGMENT->running_thread, STM_WAIT_SYNC_PAUSE);
+        EMIT_WAIT(STM_WAIT_SYNC_PAUSE);
         cond_signal(C_AT_SAFE_POINT);
         STM_PSEGMENT->safe_point = SP_WAIT_FOR_C_REQUEST_REMOVED;
         cond_wait(C_REQUEST_REMOVED);
         STM_PSEGMENT->safe_point = SP_RUNNING;
-        timing_event(STM_SEGMENT->running_thread, STM_WAIT_DONE);
         assert(!STM_SEGMENT->no_safe_point_here);
         dprintf(("left safe point\n"));
     }
+    EMIT_WAIT_DONE();
 }
 
 static void synchronize_all_threads(enum sync_type_e sync_type)
@@ -461,12 +461,14 @@
 
         intptr_t detached = fetch_detached_transaction();
         if (detached != 0) {
+            EMIT_WAIT_DONE();
             remove_requests_for_safe_point();    /* => C_REQUEST_REMOVED */
             s_mutex_unlock();
             commit_fetched_detached_transaction(detached);
             s_mutex_lock();
             goto restart;
         }
+        EMIT_WAIT(STM_WAIT_SYNCING);
         STM_PSEGMENT->safe_point = SP_WAIT_FOR_C_AT_SAFE_POINT;
         cond_wait_timeout(C_AT_SAFE_POINT, 0.00001);
         /* every 10 microsec, try again fetch_detached_transaction() */
@@ -477,6 +479,7 @@
             abort_with_mutex();
         }
     }
+    EMIT_WAIT_DONE();
 
     if (UNLIKELY(sync_type == STOP_OTHERS_AND_BECOME_GLOBALLY_UNIQUE)) {
         globally_unique_transaction = true;
diff --git a/rpython/translator/stm/src_stm/stmgc.h b/rpython/translator/stm/src_stm/stmgc.h
--- a/rpython/translator/stm/src_stm/stmgc.h
+++ b/rpython/translator/stm/src_stm/stmgc.h
@@ -71,6 +71,7 @@
     /* the next fields are handled internally by the library */
     int last_associated_segment_num;   /* always a valid seg num */
     int thread_local_counter;
+    int wait_event_emitted;
     struct stm_thread_local_s *prev, *next;
     intptr_t self_or_0_if_atomic;
     void *creating_pthread[2];
@@ -580,10 +581,6 @@
     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,
-
     /* inevitable contention: all threads that try to become inevitable
        have a STM_BECOME_INEVITABLE event with a position marker.  Then,
        if it waits it gets a STM_WAIT_OTHER_INEVITABLE.  It is possible
@@ -591,8 +588,14 @@
        STM_TRANSACTION_ABORT if it fails to become inevitable. */
     STM_BECOME_INEVITABLE,
 
-    /* always one STM_WAIT_xxx followed later by STM_WAIT_DONE */
+    /* 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 or
+       possibly STM_TRANSACTION_ABORT */
     STM_WAIT_FREE_SEGMENT,
+    STM_WAIT_SYNCING,
     STM_WAIT_SYNC_PAUSE,
     STM_WAIT_OTHER_INEVITABLE,
     STM_WAIT_DONE,


More information about the pypy-commit mailing list