Author: Armin Rigo <[email protected]>
Branch: c7-full-profiling
Changeset: r1450:8f88cdb1d916
Date: 2014-10-04 17:24 +0200
http://bitbucket.org/pypy/stmgc/changeset/8f88cdb1d916/

Log:    Write the full to-disk profiling support here too

diff --git a/c7/stm/forksupport.c b/c7/stm/forksupport.c
--- a/c7/stm/forksupport.c
+++ b/c7/stm/forksupport.c
@@ -55,14 +55,12 @@
     s_mutex_unlock();
 
     bool was_in_transaction = _stm_in_transaction(this_tl);
-    if (was_in_transaction) {
-        stm_become_inevitable(this_tl, "fork");
-        /* Note that the line above can still fail and abort, which should
-           be fine */
-    }
-    else {
-        stm_start_inevitable_transaction(this_tl);
-    }
+    if (!was_in_transaction)
+        stm_start_transaction(this_tl);
+
+    stm_become_inevitable(this_tl, "fork");
+    /* Note that the line above can still fail and abort, which should
+       be fine */
 
     s_mutex_lock();
     synchronize_all_threads(STOP_OTHERS_UNTIL_MUTEX_UNLOCK);
@@ -203,6 +201,9 @@
        just release these locks early */
     s_mutex_unlock();
 
+    /* Open a new profiling file, if any */
+    forksupport_open_new_profiling_file();
+
     /* Move the copy of the mmap over the old one, overwriting it
        and thus freeing the old mapping in this process
     */
diff --git a/c7/stm/prof.c b/c7/stm/prof.c
new file mode 100644
--- /dev/null
+++ b/c7/stm/prof.c
@@ -0,0 +1,102 @@
+#include <time.h>
+
+
+static FILE *profiling_file;
+static char *profiling_basefn = NULL;
+static int (*profiling_expand_marker)(stm_loc_marker_t *, char *, int);
+
+
+static void _stm_profiling_event(stm_thread_local_t *tl,
+                                 enum stm_event_e event,
+                                 stm_loc_marker_t *markers)
+{
+    struct buf_s {
+        uint32_t tv_sec;
+        uint32_t tv_nsec;
+        uint32_t thread_num;
+        uint8_t event;
+        uint8_t marker_length[2];
+        char extra[256];
+    } __attribute__((packed));
+
+    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;
+
+    int len0 = 0;
+    int len1 = 0;
+    if (markers != NULL) {
+        if (markers[0].odd_number != 0)
+            len0 = profiling_expand_marker(&markers[0], buf.extra, 128);
+        if (markers[1].odd_number != 0)
+            len1 = profiling_expand_marker(&markers[1], buf.extra + len0, 128);
+    }
+    buf.marker_length[0] = len0;
+    buf.marker_length[1] = len1;
+
+    fwrite(&buf, offsetof(struct buf_s, extra) + len0 + len1,
+           1, profiling_file);
+}
+
+static int default_expand_marker(stm_loc_marker_t *m, char *p, int s)
+{
+    *(uintptr_t *)p = m->odd_number;
+    return sizeof(uintptr_t);
+}
+
+static bool open_timing_log(const char *filename)
+{
+    profiling_file = fopen(filename, "w");
+    if (profiling_file == NULL)
+        return false;
+
+    fwrite("STMGC-C7-PROF01\n", 16, 1, profiling_file);
+    stmcb_timing_event = _stm_profiling_event;
+    return true;
+}
+
+static bool close_timing_log(void)
+{
+    if (stmcb_timing_event == &_stm_profiling_event) {
+        stmcb_timing_event = NULL;
+        fclose(profiling_file);
+        profiling_file = NULL;
+        return true;
+    }
+    return false;
+}
+
+static void forksupport_open_new_profiling_file(void)
+{
+    if (close_timing_log() && profiling_basefn != NULL) {
+        char filename[1024];
+        snprintf(filename, sizeof(filename),
+                 "%s.fork%ld", profiling_basefn, (long)getpid());
+        open_timing_log(filename);
+    }
+}
+
+int stm_set_timing_log(const char *profiling_file_name,
+                       int expand_marker(stm_loc_marker_t *, char *, int))
+{
+    close_timing_log();
+    free(profiling_basefn);
+    profiling_basefn = NULL;
+
+    if (profiling_file_name == NULL)
+        return 0;
+
+    if (!expand_marker)
+        expand_marker = default_expand_marker;
+    profiling_expand_marker = expand_marker;
+
+    if (!open_timing_log(profiling_file_name))
+        return -1;
+
+    profiling_basefn = strdup(profiling_file_name);
+    return 0;
+}
diff --git a/c7/stm/prof.h b/c7/stm/prof.h
new file mode 100644
--- /dev/null
+++ b/c7/stm/prof.h
@@ -0,0 +1,2 @@
+
+static void forksupport_open_new_profiling_file(void);
diff --git a/c7/stm/setup.c b/c7/stm/setup.c
--- a/c7/stm/setup.c
+++ b/c7/stm/setup.c
@@ -225,6 +225,8 @@
     return (pthread_t *)(tl->creating_pthread);
 }
 
+static int thread_local_counters = 0;
+
 void stm_register_thread_local(stm_thread_local_t *tl)
 {
     int num;
@@ -247,6 +249,7 @@
        numbers automatically. */
     num = (num % NB_SEGMENTS) + 1;
     tl->associated_segment_num = num;
+    tl->thread_local_counter = ++thread_local_counters;
     *_get_cpth(tl) = pthread_self();
     _init_shadow_stack(tl);
     set_gs_register(get_segment_base(num));
diff --git a/c7/stmgc.c b/c7/stmgc.c
--- a/c7/stmgc.c
+++ b/c7/stmgc.c
@@ -15,6 +15,7 @@
 #include "stm/fprintcolor.h"
 #include "stm/weakref.h"
 #include "stm/marker.h"
+#include "stm/prof.h"
 
 #include "stm/misc.c"
 #include "stm/list.c"
@@ -34,4 +35,5 @@
 #include "stm/fprintcolor.c"
 #include "stm/weakref.c"
 #include "stm/marker.c"
+#include "stm/prof.c"
 #include "stm/rewind_setjmp.c"
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -66,10 +66,11 @@
     char *mem_clear_on_abort;
     size_t mem_bytes_to_clear_on_abort;
     /* after an abort, some details about the abort are stored there.
-       (these fields are not modified on a successful commit) */
+       (this field is not modified on a successful commit) */
     long last_abort__bytes_in_nursery;
     /* the next fields are handled internally by the library */
     int associated_segment_num;
+    int thread_local_counter;
     struct stm_thread_local_s *prev, *next;
     void *creating_pthread[2];
 } stm_thread_local_t;
@@ -467,6 +468,17 @@
                                   enum stm_event_e event,
                                   stm_loc_marker_t *markers);
 
+/* Calling this sets up a stmcb_timing_event callback that will produce
+   a binary file calling 'profiling_file_name'.  After a fork(), it is
+   written to 'profiling_file_name.fork<PID>'.  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 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);             \
@@ -492,8 +504,6 @@
     _ss->ss = (object_t *)_odd_num;                             \
 } while (0)
 
-char *_stm_expand_marker(void);
-
 
 /* ==================== END ==================== */
 
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -152,6 +152,9 @@
                                       stm_loc_marker_t *markers);
 stmcb_timing_event_fn stmcb_timing_event;
 
+int stm_set_timing_log(const char *profiling_file_name,
+                       int expand_marker(stm_loc_marker_t *, char *, int));
+
 void stm_push_marker(stm_thread_local_t *, uintptr_t, object_t *);
 void stm_update_marker_num(stm_thread_local_t *, uintptr_t);
 void stm_pop_marker(stm_thread_local_t *);
diff --git a/c7/test/test_prof.py b/c7/test/test_prof.py
new file mode 100644
--- /dev/null
+++ b/c7/test/test_prof.py
@@ -0,0 +1,77 @@
+from support import *
+import py, os, struct
+
+udir = py.path.local.make_numbered_dir(prefix = 'stmgc-')
+
+
+def read_log(filename):
+    f = open(filename, 'rb')
+    header = f.read(16)
+    assert header == "STMGC-C7-PROF01\n"
+    result = []
+    while True:
+        packet = f.read(15)
+        if not packet: break
+        sec, nsec, threadnum, event, len0, len1 = \
+              struct.unpack("IIIBBB", packet)
+        result.append((sec + 0.000000001 * nsec,
+                       threadnum,
+                       event,
+                       f.read(len0),
+                       f.read(len1)))
+    f.close()
+    return result
+
+
+class TestProf(BaseTest):
+
+    def test_simple(self):
+        filename = os.path.join(str(udir), 'simple.prof')
+        r = lib.stm_set_timing_log(filename, ffi.NULL)
+        assert r == 0
+        try:
+            self.start_transaction()
+            self.commit_transaction()
+        finally:
+            lib.stm_set_timing_log(ffi.NULL, ffi.NULL)
+
+        result = read_log(filename)
+        assert result[0][2] == lib.STM_TRANSACTION_START
+        assert result[1][2] == lib.STM_GC_MINOR_START
+        assert result[2][2] == lib.STM_GC_MINOR_DONE
+        assert result[3][2] == lib.STM_TRANSACTION_COMMIT
+        assert len(result) == 4
+
+    def test_contention(self):
+        @ffi.callback("int(stm_loc_marker_t *, char *, int)")
+        def expand_marker(marker, p, s):
+            p[0] = chr(100 + marker.odd_number)
+            return 1
+        filename = os.path.join(str(udir), 'contention.prof')
+        r = lib.stm_set_timing_log(filename, expand_marker)
+        assert r == 0
+        try:
+            p = stm_allocate_old(16)
+            self.start_transaction()
+            assert stm_get_char(p) == '\x00'    # read
+            #
+            self.switch(1)
+            self.start_transaction()
+            self.push_root(ffi.cast("object_t *", 19))
+            self.push_root(ffi.cast("object_t *", ffi.NULL))
+            stm_set_char(p, 'B')                # write
+            py.test.raises(Conflict, self.commit_transaction)
+        finally:
+            lib.stm_set_timing_log(ffi.NULL, ffi.NULL)
+
+        result = read_log(filename)
+        id0 = result[0][1]
+        id1 = result[1][1]
+        assert result[0][1:5] == (id0, lib.STM_TRANSACTION_START, '', '')
+        assert result[1][1:5] == (id1, lib.STM_TRANSACTION_START, '', '')
+        assert result[2][1:5] == (id1, lib.STM_GC_MINOR_START, '', '')
+        assert result[3][1:5] == (id1, lib.STM_GC_MINOR_DONE, '', '')
+        assert result[4][1:5] == (id1, lib.STM_CONTENTION_WRITE_READ,
+                                  chr(119), '')
+        assert result[5][1:5] == (id1, lib.STM_TRANSACTION_ABORT, '', '')
+        assert len(result) == 6
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to