[pypy-commit] pypy statistics-maps: a script to turn map stats files into dot files

cfbolz pypy.commits at gmail.com
Tue Feb 9 03:30:32 EST 2016


Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: statistics-maps
Changeset: r82122:84c6a5b5979f
Date: 2016-02-09 09:28 +0100
http://bitbucket.org/pypy/pypy/changeset/84c6a5b5979f/

Log:	a script to turn map stats files into dot files

diff --git a/pypy/tool/mapstatsdot.py b/pypy/tool/mapstatsdot.py
new file mode 100644
--- /dev/null
+++ b/pypy/tool/mapstatsdot.py
@@ -0,0 +1,217 @@
+#! /usr/bin/env python
+import sys
+
+class Getattrwrap(object):
+    def __init__(self, obj):
+        self.obj = obj
+
+    def __getattr__(self, name):
+        try:
+            return self.obj[name]
+        except KeyError:
+            return None
+
+    def __repr__(self):
+        return "<%s>" % (self.obj, )
+
+
+class Map(object):
+    allmaps = {}
+    instances = 0
+
+    def __init__(self, typ, id):
+        self.type = typ
+        self.id = id
+        self.allmaps[id] = self
+
+    @staticmethod
+    def make(content):
+        typ = content.type
+        cls = Map
+        if typ == 'PlainAttribute':
+            cls = Attribute
+        elif "Terminator" in typ:
+            cls = Terminator
+        else:
+            import pdb; pdb.set_trace()
+        return cls(typ, content.id)
+
+    def fill(self, content):
+        self.raw = content
+        self.type = content.type
+        self.direct_instances = content.instances
+        self.instances += content.instances
+
+        transitions = content.transitions
+        d = {}
+        if transitions:
+            for id, count in transitions.iteritems():
+                map = Map.getmap(id)
+                map.instances += count
+                d[map] = count
+        self.transitions = d
+
+    @staticmethod
+    def getmap(id):
+        return Map.allmaps[id]
+
+    def dot(self, output, seen):
+        if self in seen:
+            return
+        seen.add(self)
+        if hasattr(self, 'back'):
+            self.back.dot(output, seen)
+        if not self.instances:
+            return
+        node = output.node(self.id, label=self.getlabel(),
+                           shape="box", labeljust="r",
+                           fillcolor=self.getfillcolor())
+        for next, count in self.transitions.iteritems():
+            next.dot(output, seen)
+            output.edge(self.id, next.id, label=str(count))
+        return node
+
+    def getfillcolor(self):
+        if len(self.transitions) > 1:
+            return "red"
+        return "white"
+
+
+class Terminator(Map):
+    def fill(self, content):
+        Map.fill(self, content)
+        self.w_cls = content.w_cls
+
+    def getlabel(self):
+        return self.w_cls
+
+class Attribute(Map):
+    def fill(self, content):
+        Map.fill(self, content)
+        self.back = Map.getmap(content.back)
+        self.name = content.name
+        self.nametype = content.index
+        self.ever_mutated = content.ever_mutated
+        self.can_contain_mutable_cell = content.can_contain_mutable_cell
+        self.hprof_status = content._hprof_status
+        self.constant = False
+        if self.hprof_status == "i":
+            self.constant = True
+        if self.hprof_status == "o":
+            self.constant = True
+        self.constant_class = content._hprof_const_cls
+        self.number_unnecessary_writes = content.number_unnecessary_writes
+
+        writes = content.writes
+        d = {}
+        if writes:
+            for tup, count in writes.iteritems():
+                key, index, cls = tup.strip('()').split(', ')
+                if key.startswith('"'):
+                    key = eval(key)
+                assert key == self.name
+                assert int(index) == self.nametype
+                d[cls] = count
+        self.writes = d
+
+        reads = content.reads
+        count = 0
+        if reads:
+            assert len(reads) == 1
+            for tup, count in reads.iteritems():
+                key, index = tup.strip('()').split(', ')
+                if key.startswith('"'):
+                    key = eval(key)
+                assert key == self.name
+                assert int(index) == self.nametype
+        self.reads = count
+
+    def getlabel(self):
+        if self.nametype == 0:
+            name = self.name
+        else:
+            name = self.name + " " + str(self.nametype)
+        if self.hprof_status == "i":
+            name += " (constant int)"
+        if self.hprof_status == "o":
+            name += " (constant obj)"
+        label = [name]
+        label.append("reads: %s" % self.reads)
+        label.append("writes:")
+        for write, count in self.writes.items():
+            label.append("    %s: %s" % (write, count))
+        if self.number_unnecessary_writes and self.constant:
+            assert len(self.writes) == 1
+            label[-1] += " (%s unnecessary)" % (self.number_unnecessary_writes, )
+        if not self.ever_mutated:
+            label.append('immutable')
+        if self.can_contain_mutable_cell and not self.constant_class:
+            label.append('may be a cell')
+        if self.constant_class:
+            label.append('constant class: ' + self.constant_class)
+        return "\\l".join(label)
+
+    def getfillcolor(self):
+        if len(self.transitions) > 1:
+            return "red"
+        if len(self.writes) > 1: # more than one type
+            return "yellow"
+        if self.constant:
+            return "green"
+        if self.constant_class:
+            return "greenyellow"
+        return "white"
+
+def dot(allmaps):
+    import graphviz
+    output = graphviz.Digraph()
+    seen = set()
+    #allmaps = [map for map in allmaps if map.instances and map.getfillcolor() != "white"]
+    allmaps.sort(key=lambda map: getattr(map, "instances", 0))
+    allmaps.reverse()
+    for map in allmaps:
+        map.dot(output, seen)
+    print output.source
+
+
+def main():
+    input = eval(file(sys.argv[1]).read())
+    input = [Getattrwrap(obj) for obj in input]
+    allmaps = []
+    for mp in input:
+        allmaps.append(Map.make(mp))
+    for content in input:
+        mp = Map.getmap(content.id)
+        mp.fill(content)
+    totalreads = 0
+    goodreads = 0
+    totalwrites = 0
+    goodwrites = 0
+    totalattrs = 0
+    goodattrs = 0
+    unnecessary = 0
+
+    for mp in allmaps:
+        if not isinstance(mp, Attribute):
+            continue
+        totalwrites += sum(mp.writes.values())
+        totalreads += mp.reads
+        totalattrs += 1
+        if len(mp.writes) == 1:
+            goodwrites += sum(mp.writes.values())
+            goodreads += mp.reads
+            goodattrs += 1
+        if mp.constant:
+            unnecessary += mp.number_unnecessary_writes
+    with file("out.csv", "a") as f:
+        print >> f, ", ".join(map(str, [sys.argv[1], totalreads, goodreads, totalwrites, goodwrites, unnecessary, totalattrs, goodattrs]))
+    print >> sys.stderr, "reads:", totalreads, goodreads, float(goodreads) / totalreads
+    print >> sys.stderr, "writes:", totalwrites, goodwrites, float(goodwrites) / totalwrites
+    print >> sys.stderr, "unnecessary writes:", unnecessary, totalwrites, float(unnecessary) / totalwrites
+    print >> sys.stderr, "attrs:", totalattrs, goodattrs, float(goodattrs) / totalattrs
+    print >> sys.stderr, "reads / writes", float(totalreads) / totalwrites
+
+    dot(allmaps)
+
+if __name__ == '__main__':
+    main()


More information about the pypy-commit mailing list