Author: Armin Rigo <[email protected]>
Branch: stmgc-c8
Changeset: r76295:7031b770c8e1
Date: 2015-03-10 17:15 +0100
http://bitbucket.org/pypy/pypy/changeset/7031b770c8e1/

Log:    Update the logic in print_stm_log. Still missing: inevitables

diff --git a/pypy/stm/print_stm_log.py b/pypy/stm/print_stm_log.py
--- a/pypy/stm/print_stm_log.py
+++ b/pypy/stm/print_stm_log.py
@@ -12,19 +12,26 @@
 # saying where the write was done.  Followed by STM_TRANSACTION_ABORT.
 STM_CONTENTION_WRITE_READ  = 3
 
+# 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
+# that a thread gets STM_BECOME_INEVITABLE followed by
+# STM_TRANSACTION_ABORT if it fails to become inevitable.
+STM_BECOME_INEVITABLE      = 4
+
 # always one STM_WAIT_xxx followed later by STM_WAIT_DONE
-STM_WAIT_FREE_SEGMENT      = 4
-STM_WAIT_SYNC_PAUSE        = 5
-STM_WAIT_OTHER_INEVITABLE  = 6
-STM_WAIT_DONE              = 7
+STM_WAIT_FREE_SEGMENT      = 5
+STM_WAIT_SYNC_PAUSE        = 6
+STM_WAIT_OTHER_INEVITABLE  = 7
+STM_WAIT_DONE              = 8
 
 # start and end of GC cycles
-STM_GC_MINOR_START  = 8
-STM_GC_MINOR_DONE   = 9
-STM_GC_MAJOR_START  = 10
-STM_GC_MAJOR_DONE   = 11
+STM_GC_MINOR_START  = 9
+STM_GC_MINOR_DONE   = 10
+STM_GC_MAJOR_START  = 11
+STM_GC_MAJOR_DONE   = 12
 
-_STM_EVENT_N  = 12
+_STM_EVENT_N  = 13
 
 PAUSE_AFTER_ABORT   = 0.000001      # usleep(1) after every abort
 
@@ -81,43 +88,65 @@
 class ThreadState(object):
     def __init__(self, threadnum):
         self.threadnum = threadnum
-        self.cpu_time = 0.0
+        self.cpu_time_committed = 0.0
+        self.cpu_time_aborted = 0.0
+        self._prev = (0.0, "stop")
+        self.reset_counters()
+
+    def reset_counters(self):
+        self._transaction_cpu_time = 0.0
+        self._transaction_pause_time = 0.0
+        self._transaction_aborting = False
 
     def transaction_start(self, entry):
-        self._start = entry
-        self._conflict = None
-        self._pause = None
-        self._paused_time = 0.0
+        self.reset_counters()
+        self.progress(entry, "run")
 
-    def transaction_stop(self, entry):
-        transaction_time = entry.timestamp - self._start.timestamp
-        transaction_time -= self._paused_time
-        assert transaction_time >= 0.0
-        self.cpu_time += transaction_time
-        self._start = None
-        self._pause = None
-        if self._conflict and entry.event == STM_TRANSACTION_ABORT:
-            c = self._conflict[1]
-            c.aborted_time += transaction_time
-            c.paused_time += PAUSE_AFTER_ABORT
-            self._conflict = None
+    def progress(self, entry, new_state):
+        prev_time, prev_state = self._prev
+        add_time = entry.timestamp - prev_time
+        assert add_time >= 0.0
+        if prev_state == "run":
+            self._transaction_cpu_time += add_time
+        elif prev_state == "pause":
+            self._transaction_pause_time += add_time
+        self._prev = entry.timestamp, new_state
+
+    def transaction_commit(self, entry):
+        assert not self._transaction_aborting
+        self.progress(entry, "stop")
+        self.cpu_time_committed += self._transaction_cpu_time
+
+    def transaction_abort(self, entry):
+        self.progress(entry, "stop")
+        self.cpu_time_aborted += self._transaction_cpu_time
+
+    def become_inevitable(self, entry):
+        "XXX"
 
     def transaction_pause(self, entry):
-        self._pause = entry
+        self.progress(entry, "pause")
 
     def transaction_unpause(self, entry):
-        if self._pause is None:
+        self.progress(entry, "run")
+
+    def contention_write_read(self, entry, out_conflicts):
+        # This thread is aborted because it has read an object, but
+        # another thread already committed a change to that object.
+        # The marker is pointing inside the other thread's write.
+        if self._transaction_aborting:
+            print >> sys.stderr, "note: double STM_CONTENTION_WRITE_READ"
             return
-        pause_time = entry.timestamp - self._pause.timestamp
-        self._paused_time += pause_time
-        self._pause = None
-        if self._conflict and self._conflict[0] == "local":
-            c = self._conflict[1]
-            c.paused_time += pause_time
-            self._conflict = None
-
-    def in_transaction(self):
-        return self._start is not None
+        self._transaction_aborting = True
+        summary = (entry.event, entry.marker)
+        c = out_conflicts.get(summary)
+        if c is None:
+            c = out_conflicts[summary] = ConflictSummary(*summary)
+        c.num_events += 1
+        c.timestamps.append(entry.timestamp)
+        self.progress(entry, "run")
+        c.aborted_time += self._transaction_cpu_time
+        c.paused_time += self._transaction_pause_time
 
 
 class ConflictSummary(object):
@@ -153,10 +182,12 @@
     s = '  %s' % marker
     match = r_marker.match(marker)
     if match:
-        line = linecache.getline(match.group(1), int(match.group(2)))
-        line = line.strip()
-        if line:
-            s += '\n    %s' % line
+        filename = match.group(1)
+        if not (filename.endswith('.pyc') or filename.endswith('.pyo')):
+            line = linecache.getline(filename, int(match.group(2)))
+            line = line.strip()
+            if line:
+                s += '\n    %s' % line
     return s
 
 def percent(fraction, total):
@@ -177,47 +208,26 @@
                 print >> sys.stderr, '%.0f%%' % (entry.frac * 100.0,),
         cnt += 1
         #
+        t = threads.get(entry.threadnum)
+        if t is None:
+            t = threads[entry.threadnum] = ThreadState(entry.threadnum)
+        #
         if entry.event == STM_TRANSACTION_START:
-            t = threads.get(entry.threadnum)
-            if t is None:
-                t = threads[entry.threadnum] = ThreadState(entry.threadnum)
             t.transaction_start(entry)
-        elif (entry.event == STM_TRANSACTION_COMMIT or
-              entry.event == STM_TRANSACTION_ABORT):
-            t = threads.get(entry.threadnum)
-            if t is not None and t.in_transaction():
-                t.transaction_stop(entry)
-        elif entry.event in (#STM_CONTENTION_WRITE_WRITE,
-                             STM_CONTENTION_WRITE_READ,
-                             #STM_CONTENTION_INEVITABLE,
-                             ):
-            summary = (entry.event, entry.marker)
-            c = conflicts.get(summary)
-            if c is None:
-                c = conflicts[summary] = ConflictSummary(*summary)
-            c.num_events += 1
-            c.timestamps.append(entry.timestamp)
-            t = threads.get(entry.threadnum)
-            if t is not None and t.in_transaction():
-                t._conflict = ("local", c, entry)
-        ## elif entry.event == STM_ABORTING_OTHER_CONTENTION:
-        ##     t = threads.get(entry.threadnum)
-        ##     if t is not None and t._conflict and t._conflict[0] == "local":
-        ##         _, c, entry = t._conflict
-        ##         t._conflict = None
-        ##         t2 = threads.get(entry.otherthreadnum)
-        ##         if t2 is not None and t2.in_transaction():
-        ##             t2._conflict = ("remote", c, entry)
+        elif entry.event == STM_TRANSACTION_COMMIT:
+            t.transaction_commit(entry)
+        elif entry.event == STM_TRANSACTION_ABORT:
+            t.transaction_abort(entry)
+        elif entry.event == STM_BECOME_INEVITABLE:
+            t.become_inevitable(entry)
+        elif entry.event == STM_CONTENTION_WRITE_READ:
+            t.contention_write_read(entry, conflicts)
         elif entry.event in (STM_WAIT_FREE_SEGMENT,
                              STM_WAIT_SYNC_PAUSE,
                              STM_WAIT_OTHER_INEVITABLE):
-            t = threads.get(entry.threadnum)
-            if t is not None and t.in_transaction():
-                t.transaction_pause(entry)
+            t.transaction_pause(entry)
         elif entry.event == STM_WAIT_DONE:
-            t = threads.get(entry.threadnum)
-            if t is not None and t.in_transaction():
-                t.transaction_unpause(entry)
+            t.transaction_unpause(entry)
     #
     if cnt == 0:
         raise Exception("empty file")
@@ -234,9 +244,15 @@
     print
     print 'Total real time:             %.3fs' % (total_time,)
     #
-    total_cpu_time = stmlog.get_total_cpu_time()
-    print 'Total CPU time in STM mode:  %.3fs (%s)' % (
-        total_cpu_time, percent(total_cpu_time, total_time))
+    total_cpu_time_committed = stmlog.get_total_cpu_time_committed()
+    total_cpu_time_aborted = stmlog.get_total_cpu_time_aborted()
+    total_cpu_time_total = total_cpu_time_committed + total_cpu_time_aborted
+    print 'Total CPU time in STM mode:  %.3fs (%s) committed' % (
+        total_cpu_time_committed, percent(total_cpu_time_committed, 
total_time))
+    print '                             %.3fs (%s) aborted' % (
+        total_cpu_time_aborted,   percent(total_cpu_time_aborted,   
total_time))
+    print '                             %.3fs (%s) total' % (
+        total_cpu_time_total,     percent(total_cpu_time_total,     
total_time))
     print
     #
     values = stmlog.get_conflicts()
@@ -256,8 +272,11 @@
     def __init__(self, filename):
         summarize_log_entries(parse_log(filename), self)
 
-    def get_total_cpu_time(self):
-        return sum([v.cpu_time for v in self.threads.values()])
+    def get_total_cpu_time_committed(self):
+        return sum([v.cpu_time_committed for v in self.threads.values()])
+
+    def get_total_cpu_time_aborted(self):
+        return sum([v.cpu_time_aborted for v in self.threads.values()])
 
     def get_conflicts(self):
         values = self.conflicts.values()
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to