Author: Armin Rigo <[email protected]>
Branch: stmgc-c7
Changeset: r73781:e51b6e693dec
Date: 2014-10-05 15:16 +0200
http://bitbucket.org/pypy/pypy/changeset/e51b6e693dec/

Log:    Reporting a summary of a PYPYSTM file

diff --git a/pypy/stm/print_stm_log.py b/pypy/stm/print_stm_log.py
new file mode 100755
--- /dev/null
+++ b/pypy/stm/print_stm_log.py
@@ -0,0 +1,175 @@
+#!/usr/bin/env python
+import sys
+import struct
+
+# ____________________________________________________________
+
+STM_TRANSACTION_START   = 0
+STM_TRANSACTION_COMMIT  = 1
+STM_TRANSACTION_ABORT   = 2
+
+# contention; see details at the start of contention.c
+STM_CONTENTION_WRITE_WRITE = 3   # markers: self loc / other written loc
+STM_CONTENTION_WRITE_READ  = 4   # markers: self written loc / other missing
+STM_CONTENTION_INEVITABLE  = 5   # markers: self loc / other inev loc
+
+# following a contention, we get from the same thread one of
+# STM_ABORTING_OTHER_CONTENTION, STM_TRANSACTION_ABORT (self-abort),
+# or STM_WAIT_CONTENTION (self-wait).
+STM_ABORTING_OTHER_CONTENTION = 6
+
+# always one STM_WAIT_xxx followed later by STM_WAIT_DONE
+STM_WAIT_FREE_SEGMENT  = 7
+STM_WAIT_SYNC_PAUSE    = 8
+STM_WAIT_CONTENTION    = 9
+STM_WAIT_DONE          = 10
+
+# start and end of GC cycles
+STM_GC_MINOR_START  = 11
+STM_GC_MINOR_DONE   = 12
+STM_GC_MAJOR_START  = 13
+STM_GC_MAJOR_DONE   = 14
+
+event_name = {}
+for _key, _value in globals().items():
+    if _key.startswith('STM_'):
+        event_name[_value] = _key
+
+# ____________________________________________________________
+
+
+class LogEntry(object):
+    def __init__(self, timestamp, threadnum, otherthreadnum,
+                 event, marker1, marker2):
+        self.timestamp = timestamp
+        self.threadnum = threadnum
+        self.otherthreadnum = otherthreadnum
+        self.event = event
+        self.marker1 = marker1
+        self.marker2 = marker2
+
+
+def parse_log(filename):
+    f = open(filename, 'rb')
+    result = []
+    try:
+        header = f.read(16)
+        if header != "STMGC-C7-PROF01\n":
+            raise ValueError("wrong format in file %r" % (filename,))
+        result = []
+        while True:
+            packet = f.read(19)
+            if not packet: break
+            sec, nsec, threadnum, otherthreadnum, event, len1, len2 = \
+                  struct.unpack("IIIIBBB", packet)
+            m1 = f.read(len1)
+            m2 = f.read(len2)
+            result.append(LogEntry(sec + 0.000000001 * nsec,
+                                   threadnum, otherthreadnum, event, m1, m2))
+    finally:
+        f.close()
+    return result
+
+
+
+class ThreadState(object):
+    def __init__(self, threadnum):
+        self.threadnum = threadnum
+        self.cpu_time = 0.0
+
+    def transaction_start(self, entry):
+        self._start = entry
+        self._conflict = None
+
+    def transaction_stop(self, entry):
+        transaction_time = entry.timestamp - self._start.timestamp
+        self.cpu_time += transaction_time
+        self._start = None
+        if self._conflict and entry.event == STM_TRANSACTION_ABORT:
+            c = self._conflict[1]
+            c.aborted_time += transaction_time
+            self._conflict = None
+
+    def in_transaction(self):
+        return self._start is not None
+
+
+class ConflictSummary(object):
+    def __init__(self, event, marker1, marker2):
+        self.event = event
+        self.marker1 = marker1
+        self.marker2 = marker2
+        self.aborted_time = 0.0
+        self.paused_time = 0.0
+        self.num_events = 0
+
+    def sortkey(self):
+        return self.aborted_time + self.paused_time
+
+
+def percent(fraction, total):
+    r = '%.1f' % (fraction * 100.0 / total)
+    if len(r) > 3:
+        r = r.split('.')[0]
+    return r + '%'
+
+def dump(logentries):
+    total_time = logentries[-1].timestamp - logentries[0].timestamp
+    print 'Total real time:             %.3fs' % (total_time,)
+    #
+    threads = {}
+    conflicts = {}
+    for entry in logentries:
+        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.marker1, entry.marker2)
+            c = conflicts.get(summary)
+            if c is None:
+                c = conflicts[summary] = ConflictSummary(*summary)
+            c.num_events += 1
+            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_WAIT...
+    #
+    total_cpu_time = sum([t.cpu_time for t in threads.values()])
+    print 'Total CPU time in STM mode:  %.3fs (%s)' % (
+        total_cpu_time, percent(total_cpu_time, total_time))
+    print
+    #
+    values = sorted(conflicts.values(), key=ConflictSummary.sortkey)
+    for c in values[-1:-15:-1]:
+        print '%.3fs lost in aborts, %.3fs paused (%s)' % (
+            c.aborted_time, c.paused_time, event_name[c.event])
+        print ' ', c.marker1
+        if c.marker2:
+            print ' ', c.marker2
+        print
+
+
+def main(argv):
+    assert len(argv) == 1, "expected a filename argument"
+    dump(parse_log(argv[0]))
+    return 0
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv[1:]))
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to