[pypy-svn] r52828 - in pypy/branch/jit-hotpath/pypy/jit: rainbow timeshifter

arigo at codespeak.net arigo at codespeak.net
Sat Mar 22 15:41:01 CET 2008


Author: arigo
Date: Sat Mar 22 15:41:00 2008
New Revision: 52828

Added:
   pypy/branch/jit-hotpath/pypy/jit/timeshifter/rdump.py   (contents, props changed)
Modified:
   pypy/branch/jit-hotpath/pypy/jit/rainbow/fallback.py
   pypy/branch/jit-hotpath/pypy/jit/rainbow/interpreter.py
   pypy/branch/jit-hotpath/pypy/jit/timeshifter/rcontainer.py
Log:
Some RPython support code to dump the jitstate and redboxes
into a nice .dot file.


Modified: pypy/branch/jit-hotpath/pypy/jit/rainbow/fallback.py
==============================================================================
--- pypy/branch/jit-hotpath/pypy/jit/rainbow/fallback.py	(original)
+++ pypy/branch/jit-hotpath/pypy/jit/rainbow/fallback.py	Sat Mar 22 15:41:00 2008
@@ -272,7 +272,7 @@
     def green_result_from_red(self, gv):
         self.green_result(gv)
 
-    def trace(self):
+    def dump(self):
         bytecode = self.bytecode
         msg = '*** fallback trace: in %s position %d ***' % (bytecode.name,
                                                              self.pc)
@@ -286,7 +286,7 @@
 
     @arguments()
     def opimpl_trace(self):
-        msg = self.trace()
+        msg = self.dump()
         self.interpreter.debug_trace(msg)
 
     @arguments("green", "2byte", returns="red")

Modified: pypy/branch/jit-hotpath/pypy/jit/rainbow/interpreter.py
==============================================================================
--- pypy/branch/jit-hotpath/pypy/jit/rainbow/interpreter.py	(original)
+++ pypy/branch/jit-hotpath/pypy/jit/rainbow/interpreter.py	Sat Mar 22 15:41:00 2008
@@ -442,7 +442,7 @@
         else:
             self.frame = None
 
-    def trace(self):
+    def dump(self):
         # Prints the current frame position and a dump if available.
         # Although this opcode is not actually generated by
         # codewriter.py so far, it can be called manually in a C-level
@@ -455,12 +455,15 @@
         print msg
         if bytecode.dump_copy is not None:
             print bytecode.dump_copy
+        from pypy.jit.timeshifter import rdump
+        rdump.dump_jitstate(self.jitstate)
         return msg
+    dump._dont_inline_ = True
 
     # operation implementations
     @arguments()
     def opimpl_trace(self):
-        msg = self.trace()
+        msg = self.dump()
         self.debug_trace(msg)
 
     @arguments("green", "2byte", returns="red")

Modified: pypy/branch/jit-hotpath/pypy/jit/timeshifter/rcontainer.py
==============================================================================
--- pypy/branch/jit-hotpath/pypy/jit/timeshifter/rcontainer.py	(original)
+++ pypy/branch/jit-hotpath/pypy/jit/timeshifter/rcontainer.py	Sat Mar 22 15:41:00 2008
@@ -86,6 +86,7 @@
     def __init__(self, RGenOp, TYPE):
         self.TYPE = TYPE
         self.PTRTYPE = lltype.Ptr(TYPE)
+        self.name = TYPE._name
         self.ptrkind = RGenOp.kindToken(self.PTRTYPE)
 
         self.immutable = TYPE._hints.get('immutable', False)

Added: pypy/branch/jit-hotpath/pypy/jit/timeshifter/rdump.py
==============================================================================
--- (empty file)
+++ pypy/branch/jit-hotpath/pypy/jit/timeshifter/rdump.py	Sat Mar 22 15:41:00 2008
@@ -0,0 +1,240 @@
+import os
+from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.jit.timeshifter import rvalue, rcontainer, vlist
+from pypy.rlib.objectmodel import compute_unique_id as getid
+
+DUMPFILENAME = '%s.dot'
+
+
+class GraphBuilder:
+
+    def __init__(self):
+        self.nodelines = []
+        self.edgelines = []
+        self.memo = rvalue.Memo()
+        self.none_counter = 0
+        self.seen_ids = {}
+
+    def done(self, basename):
+        lines = ['digraph %s {\n' % basename]
+        lines += self.nodelines
+        lines += self.edgelines
+        lines.append('}\n')
+        buf = ''.join(lines)
+        filename = DUMPFILENAME % basename
+        fd = os.open(filename, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0644)
+        while buf:
+            count = os.write(fd, buf)
+            buf = buf[count:]
+        os.close(fd)
+        print "Wrote dump to", filename
+
+    def see(self, id):
+        if id in self.seen_ids:
+            return False
+        else:
+            self.seen_ids[id] = None
+            return True
+
+    def quote(self, s):
+        s = '\\"'.join(s.split('"'))
+        s = '\\n'.join(s.split('\n'))
+        return s
+
+    def iname(self, id):
+        if id != 0:    # special support for edges pointing to None
+            name = 'n_%x' % id
+            name = name.replace('-', '_')
+        else:
+            name = 'None%d' % self.none_counter
+            self.none_counter += 1
+            self.nodelines.append('%s [label="None", color="#A0A0A0"];\n' %
+                                  (name,))
+        return name
+
+    def emit_node(self, id, label, shape="box", fillcolor="", color=""):
+        args = []
+        args.append('label="%s"' % self.quote(label))
+        args.append('shape="%s"' % shape)
+        if fillcolor:
+            args.append('fillcolor="%s"' % fillcolor)
+        if color:
+            args.append('color="%s"' % color)
+        self.nodelines.append('%s [%s];\n' % (self.iname(id), ', '.join(args)))
+
+    def emit_edge(self, id1, id2, label="", color="", weak=False):
+        args = []
+        if label:
+            args.append('label="%s"' % self.quote(label))
+        if color:
+            args.append('color="%s"' % color)
+        if weak:
+            args.append('constraint=false')
+        if args:
+            args = '[%s]' % (', '.join(args),)
+        else:
+            args = ''
+        self.edgelines.append('%s -> %s %s;\n' % (self.iname(id1),
+                                                  self.iname(id2),
+                                                  args))
+
+    def add_jitstate(self, jitstate):
+        if jitstate is None:
+            return 0
+        id = getid(jitstate)
+        if self.see(id):
+            text = str(jitstate)
+            self.emit_edge(id, self.add_frame(jitstate.frame), color="red")
+            self.emit_edge(id, self.add_redbox(jitstate.exc_type_box),
+                           "exc_type")
+            self.emit_edge(id, self.add_redbox(jitstate.exc_value_box),
+                           "exc_value")
+            for i in range(len(jitstate.virtualizables)):
+                box = jitstate.virtualizables[i]
+                self.emit_edge(id, self.add_redbox(box),
+                               "virtualizables[%d]" % i)
+            self.emit_node(id, text, fillcolor="#a5e6f0")
+        return id
+
+    def add_frame(self, frame):
+        if frame is None:
+            return 0
+        id = getid(frame)
+        if self.see(id):
+            text = str(frame) + "\\n"
+            if frame.bytecode is not None:
+                text += "bytecode = '%s'\n" % frame.bytecode.name
+                # XXX large nodes in dot are too annoying
+                #self.emit_edge(id, self.add_bytecode(frame.bytecode),
+                #               "bytecode")
+            text += "pc = %d\n" % frame.pc
+            if frame.backframe is not None:
+                self.emit_edge(id, self.add_frame(frame.backframe),
+                               color="red")
+            for i in range(len(frame.local_boxes)):
+                box = frame.local_boxes[i]
+                self.emit_edge(id, self.add_redbox(box), "local_boxes[%d]" % i)
+            self.emit_node(id, text, color="red", fillcolor="#ffd0d0")
+        return id
+
+    def add_bytecode(self, bytecode):
+        if bytecode is None:
+            return 0
+        id = getid(bytecode)
+        if self.see(id):
+            if bytecode.dump_copy is not None:
+                text = bytecode.dump_copy
+            else:
+                text = "JITCODE %s" % bytecode.name
+            self.emit_node(id, text, color="red", fillcolor="#FFC0C0")
+        return id
+
+    def intgenvar(self, genvar):
+        if genvar is None:
+            return 'genvar=None'
+        elif genvar.is_const:
+            svalue = genvar.revealconst(lltype.Signed)
+            uvalue = genvar.revealconst(lltype.Unsigned)
+            return '%d (0x%x)' % (svalue, uvalue)
+        else:
+            return str(genvar)
+
+    def doublegenvar(self, genvar):
+        if genvar is None:
+            return 'genvar=None'
+        elif genvar.is_const:
+            return str(genvar.revealconst(lltype.Float))
+        else:
+            return str(genvar)
+
+    def ptrgenvar(self, genvar):
+        if genvar is None:
+            return 'genvar=None'
+        elif genvar.is_const:
+            return str(genvar.revealconst(llmemory.Address))
+        else:
+            return str(genvar)
+
+    def add_redbox(self, redbox):
+        if redbox is None:
+            return 0
+        id = getid(redbox)
+        if self.see(id):
+            text = "%s\\n" % str(redbox)
+            if isinstance(redbox, rvalue.PtrRedBox):
+                if redbox.genvar is None and redbox.content is not None:
+                    text += "virtual"
+                else:
+                    text += self.ptrgenvar(redbox.genvar)
+                if redbox.content is not None:
+                    self.emit_edge(id, self.add_container(redbox.content))
+            elif isinstance(redbox, rvalue.DoubleRedBox):
+                text += self.doublegenvar(redbox.genvar)
+            else:
+                text += self.intgenvar(redbox.genvar)
+            self.emit_node(id, text)
+        return id
+
+    def add_container(self, container):
+        if container is None:
+            return 0
+        id = getid(container)
+        if self.see(id):
+            text = "%s\\n" % str(container)
+
+            if isinstance(container, rcontainer.VirtualContainer):
+                # most cases should arrive here, it's not exclusive for
+                # the cases below
+                self.emit_edge(id, self.add_redbox(container.ownbox),
+                               color="#808000", weak=True)
+
+            if isinstance(container, rcontainer.VirtualStruct):
+                text += container.typedesc.name
+                fielddescs = container.typedesc.fielddescs
+                for i in range(len(container.content_boxes)):
+                    try:
+                        name = fielddescs[i].fieldname
+                    except IndexError:
+                        name = 'field out of bounds (%d)' % (i,)
+                    box = container.content_boxes[i]
+                    self.emit_edge(id, self.add_redbox(box), name)
+
+            if isinstance(container, vlist.VirtualList):
+                text += 'length %d' % len(container.item_boxes)
+                for i in range(len(container.item_boxes)):
+                    box = item_boxes.item_boxes[i]
+                    self.emit_edge(id, self.add_redbox(box),
+                                   'item_boxes[%d]' % i)
+
+            self.emit_node(id, text, fillcolor="#ffff60", color="#808000")
+        return id
+
+# ____________________________________________________________
+#
+# Public API
+
+def dump_jitstate(jitstate):
+    gb = GraphBuilder()
+    gb.add_jitstate(jitstate)
+    gb.done("jitstate")
+
+def dump_frame(frame):
+    gb = GraphBuilder()
+    gb.add_frame(frame)
+    gb.done("frame")
+
+def dump_redbox(redbox):
+    gb = GraphBuilder()
+    gb.add_redbox(redbox)
+    gb.done("redbox")
+
+def dump_container(container):
+    gb = GraphBuilder()
+    gb.add_container(container)
+    gb.done("container")
+
+# keep these functions non-inlined so that they are callable from gdb
+dump_jitstate._dont_inline_ = True
+dump_frame._dont_inline_ = True
+dump_redbox._dont_inline_ = True
+dump_container._dont_inline_ = True



More information about the Pypy-commit mailing list