Commits

Anonymous committed 80ffa1a

Adding tree view script

Comments (0)

Files changed (2)

+# Convert browser and shell spew to a common format for diffing.
+
+import os, re, sys
+
+LINE_OFFSET = 40
+
+def repl(m):
+    path, lineno, pc = m.groups()
+    lineno = int(lineno)
+    dir, base = os.path.split(path)
+    if base.endswith('.html'):
+        base = base[:-5] + '.js'
+        lineno -= LINE_OFFSET
+    #print path
+    return '%s:%d'%(base, lineno)
+
+for line in sys.stdin:
+    if line.startswith('js_Interpret') or line.startswith('    out'):
+        continue
+    line = re.sub(r'((?:http:)?[-./a-zA-z0-9]+):(\d+)@(\d+)', repl, line)
+    sys.stdout.write(line)
+import sys
+
+class Item(object):
+    next_id = 0
+
+class Root(object):
+    def __init__(self, pc):
+        self.id = pc[1:]
+        self.pc = pc
+        self.children = []
+
+class Fragment(object):
+    def __init__(self, id, pc):
+        self.id = id
+        self.pc = pc
+        self.parent = None
+        self.children = []
+        self.callees = []
+        self.callers = []
+
+class Point(object):
+    def __init__(self):
+        self.id = Item.next_id
+        Item.next_id += 1
+
+        self.inpath = None
+        self.outpaths = []
+        self.call = None
+
+        self.shape = 'point'
+
+class Segment(object):
+    def __init__(self, start, end):
+        self.id = Item.next_id
+        Item.next_id += 1
+
+        self.start = start
+        self.end = end
+        
+        assert end.inpath is None
+        start.outpaths.append(self)
+        end.inpath = self
+        
+def parse_line(line):
+    parts = line.split()
+    if parts[0] not in ('record', 'finish', 'nest'):
+        return None
+    o = Item()
+    o.id = Item.next_id
+    Item.next_id += 1
+    o.kind = parts[0]
+    for p in parts[1:]:
+        k, v = p.split('=')
+        setattr(o, k, v)
+    return o
+
+def parse():
+    for line in sys.stdin:
+        o = parse_line(line)
+        if o:
+            yield o
+
+def build_fragments():
+    next_seq = 1
+    fs = {}
+    rm = {}
+    f = None
+    fo = None
+    for o in parse():
+        if o.kind == 'record':
+            f = Fragment(o.trace[1:], o.pc)
+            f.filename = o.filename
+            f.line = o.line
+            fo = o
+        elif o.kind == 'finish':
+            if fo.trace != fo.root:
+                f.parent = fs[fo.lastLeft]
+                f.parent.children.append(f)
+            for c in f.callees:
+                c.callers.append(f)
+            fs[fo.trace] = f
+
+            if not f.parent:
+                root = rm.get(f.pc)
+                if not root:
+                    rm[f.pc] = root = Root(f.pc)
+                    root.line = f.line
+                root.children.append(f)
+
+            f.seq = next_seq
+            next_seq += 1
+        elif o.kind == 'nest':
+            f.callees.append(fs[o.inner])
+    return fs, rm
+
+def transpose_fragments(fs, rs, points):
+    for r in rs:
+        start = Point()
+        points.append(start)
+        for f in r.children:
+            transpose_tree(f, start, points)
+
+    for p in points:
+        if p.call:
+            p.call = p.call.start, p.call.end
+
+def transpose_tree(f, start, points):
+    start.line = f.line
+    start.filename = f.filename
+    start.shape = 'circle'
+
+    point = Point()
+    points.append(point)
+    Segment(start, point)
+    last = point
+
+    for c in f.children:
+        next = Point()
+        points.append(next)
+        Segment(last, next)
+
+        point = Point()
+        points.append(point)
+        Segment(last, point)
+        
+        last = next
+
+        transpose_tree(c, point, points)
+
+    for c in f.callees:
+        last.call = c
+        
+        next = Point()
+        points.append(next)
+        Segment(last, next)
+
+        last = next
+
+    last.shape = 'box width=.25 height=.25'
+
+    f.start = start
+    f.end = last
+
+class NameShortener(object):
+    def __init__(self):
+        self.m = {}
+        self.ns = set()
+
+    def get(self, name):
+        ans = self.m.get(name)
+        if ans: return ans
+
+        import os.path
+        base = os.path.basename(name)
+        for i in range(1, len(base)):
+            ans = base[:i]
+            if ans not in self.ns: break
+        self.m[name] = ans
+        return ans
+
+    def list(self):
+        for k, v in sorted(self.m.items(), key=lambda t: t[1]):
+            print >> sys.stderr, '%-6s %s'%(v, k)
+        
+
+def print_fragment_graph(fs, rs):
+    print 'digraph G {'
+    for r in rs:
+        if len(r.children) > 1:
+            print '    %s [label="%s", shape=rectangle, style=dotted];'%(r.id, r.line)
+            for f in r.children:
+                print '    %s -> %s [style=dotted];'%(r.id, f.id)
+        else:
+            for f in r.children:
+                f.square = True
+    for f in fs:
+        shape = ''
+        if getattr(f, 'square', None):
+            shape = 'shape=rectangle'
+        print '    %s [label="%s [%d]" %s];'%(f.id, f.line, f.seq, shape)
+        for c in f.children:
+            print '    %s -> %s;'%(f.id, c.id)
+        for c in f.callees:
+            print '    %s -> %s [style=dashed];'%(f.id, c.id)
+    print '}'
+
+def print_segment_graph(points):
+    ns = NameShortener()
+    print 'digraph G {'
+    for p in points:
+        line = getattr(p, 'line', '')
+        if line:
+            tag = ns.get(p.filename)
+            label = tag + line
+        else:
+            label = ''
+        print '    %d [label="%s" shape=%s];'%(p.id, label, p.shape)
+        for s in p.outpaths:
+            print '    %d -> %d [arrowhead=none];'%(
+                s.start.id, s.end.id)
+        if p.call:
+            s, e = p.call
+            print '    %d -> %d [arrowhead=vee, style=dashed, constraint=false];'%(
+                p.id, s.id)
+            #print '    %d -> %d [arrowtail=none, arrowhead=crow, style=dashed, constraint=false];'%(p.id, e.id)
+            
+    print '}'
+
+    ns.list()
+
+fm, rm = build_fragments()
+#print_fragment_graph(fm.values(), rm.values())
+points = []
+transpose_fragments(fm.values(), rm.values(), points)
+print_segment_graph(points)