Commits

Maciej Fijalkowski committed 69578dc

General progress on the viewer

Comments (0)

Files changed (11)

 
+import cgi
 import flask
+import inspect
 from pypy.tool.logparser import parse_log_file, extract_category
 from pypy.jit.metainterp.test.oparser import parse
 from module_finder import load_code
 from loops import slice_debug_merge_points, parse_log_counts
+from display import CodeRepr
 
 from pygments import highlight
 from pygments.lexers import PythonLexer
         no = int(flask.request.args.get('no', '0'))
         # gather all functions
         loop = self.loops[no]
-        startline = loop.lineno - 1
-        import pdb
-        pdb.set_trace()
-        code = highlight(open(loop.filename).read(),
-                         PythonLexer(), HtmlFormatter(lineanchors='line'))
-        #mod = import_module
-        return flask.render_template('loop.html', code=code,
+        startline, endline = loop.linerange
+        code = load_code(loop.filename, loop.name, loop.startlineno)
+        source = inspect.getsource(code)
+        return flask.render_template('loop.html',
+                                     source=CodeRepr(source, code, loop),
                                      startline=startline)
-
+        
 def main():
     log = parse_log_file('log')
     log_counts = parse_log_counts(open('log.count').readlines())
     app.debug = True
     app.route('/')(server.index)
     app.route('/loop')(server.loop)
-    app.run()
+    app.run(use_reloader=False)
 
 if __name__ == '__main__':
     main()
+
+from pypy.jit.metainterp.resoperation import rop
+
+class LineRepr(object):
+    """ A representation of a single line
+    """
+    def __init__(self, line, in_loop, chunks=None):
+        self.line = line
+        self.in_loop = in_loop
+        if chunks is None:
+            self.chunks = []
+        else:
+            self.chunks = chunks
+
+class CodeRepr(object):
+    """ A representation of a single code object suitable for display
+    """
+    def __init__(self, source, code, loop):
+        startline, endline = loop.linerange
+        self.lines = []
+        self.firstlineno = code.co_firstlineno
+        for i, line in enumerate(source.split("\n")):
+            no = i + code.co_firstlineno
+            if no < startline or no > endline:
+                self.lines.append(LineRepr(line, False))
+            else:
+                self.lines.append(LineRepr(line, True))
+
+        last_lineno = -1
+        for chunk in loop.chunks:
+            no = chunk.lineno
+            if no < last_lineno:
+                no = last_lineno
+            else:
+                last_lineno = no
+            # only non-trivial chunks please
+            if (len(chunk.operations) > 1 or
+                (len(chunk.operations) > 0 and
+                 chunk.operations[0].getopnum() != rop.DEBUG_MERGE_POINT)):
+                self.lines[no - self.firstlineno].chunks.append(chunk)
+    
+        

log.count

-19883   <code object _optimize_charset, file '/home/fijal/src/pypy-trunk/lib-python/modified-2.5.2/sre_compile.py', line 214> #290 FOR_ITER
-645     <code object _optimize_charset, file '/home/fijal/src/pypy-trunk/lib-python/modified-2.5.2/sre_compile.py', line 214> #290 FOR_ITER
-3810    <code object _mk_bitmap, file '/home/fijal/src/pypy-trunk/lib-python/modified-2.5.2/sre_compile.py', line 265> #66 FOR_ITER
-334     <code object _mk_bitmap, file '/home/fijal/src/pypy-trunk/lib-python/modified-2.5.2/sre_compile.py', line 265> #66 FOR_ITER
-5       <code object _optimize_charset, file '/home/fijal/src/pypy-trunk/lib-python/modified-2.5.2/sre_compile.py', line 214> #346 POP_TOP
-2256920 <code object <genexp>, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 67> #24 POP_TOP
-2256864 <code object <genexp>, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 46> #20 POP_TOP
-1955880 <code object <genexp>, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 67> #9 STORE_FAST
-1956214 <code object <genexp>, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 46> #9 STORE_FAST
-482592  <code object permutations, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 28> #159 FOR_ITER
-281240  <code object <genexp>, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 67> #0 SETUP_LOOP
-281233  <code object <genexp>, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 46> #0 SETUP_LOOP
-1       <loop 12>
-278593  <code object n_queens, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 53> #25 FOR_ITER
-281233  <code object permutations, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 28> #320 POP_TOP
-117328  <code object <genexp>, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 68> #24 POP_TOP
-280630  <code object permutations, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 28> #194 JUMP_IF_FALSE
-101599  <code object <genexp>, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 68> #9 STORE_FAST
-1312    <code object n_queens, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 53> #25 FOR_ITER
-14181   <code object n_queens, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 53> #70 JUMP_IF_FALSE
-13791   <code object <genexp>, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 68> #0 SETUP_LOOP
-2667    <code object permutations, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 28> #133 LOAD_FAST
-20797   <code object <genexp>, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 46> #6 FOR_ITER
-21336   <code object <genexp>, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 67> #6 FOR_ITER
-2570    <code object <genexp>, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 67> #28 POP_BLOCK
-375     <code object permutations, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 28> #159 FOR_ITER
-2492    <code object n_queens, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 53> #25 FOR_ITER
-2428    <code object <genexp>, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 46> #24 POP_BLOCK
-2468    <code object permutations, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 28> #133 LOAD_FAST
-2357    <code object permutations, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 28> #159 FOR_ITER
-1613    <code object permutations, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 28> #159 FOR_ITER
-823     <code object <genexp>, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 68> #6 FOR_ITER
-426     <code object n_queens, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 53> #108 JUMP_FORWARD
     filename = None
     name = None
     startlineno = 0
+    _linerange = None
     
     def __init__(self, chunks):
         self.chunks = chunks
                 self.name = chunk.name
                 break
 
+    def getlinerange(self):
+        if self._linerange is None:
+            minline = sys.maxint
+            maxline = -1
+            for chunk in self.chunks:
+                if chunk.filename is not None:
+                    lineno = chunk.lineno
+                    minline = min(minline, lineno)
+                    maxline = max(maxline, lineno)
+            self._linerange = minline, maxline
+        return self._linerange
+    linerange = property(getlinerange)
+
     def repr(self):
         if self.filename is None:
             return "Unknown"
         return "%s, file '%s', line %d" % (self.name, self.filename,
                                            self.startlineno)
-
-    def key(self):
-        pass
-
+        
     def __repr__(self):
         return "[%s]" % ", ".join([repr(chunk) for chunk in self.chunks])
 
 
-import os, sys, marshal, types
+import os, sys, marshal, types, struct, imp
 
 def _all_codes_from(code):
     res = {}
                  if isinstance(co, types.CodeType)]
     return res
 
-
 def gather_all_code_objs(fname):
     """ Gathers all code objects from a give fname and sorts them by
     starting lineno
     """
     fname = str(fname)
     if fname.endswith('.pyc'):
-        code = marshal.loads(open(fname).read()[8:])
-        assert isinstance(code, types.CodeType)
+        f = open(fname)
+        magic = f.read(4)
+        f.read(4) # timestamp
+        if magic != imp.get_magic():
+            f.close()
+            code = compile(open(fname[:-1]).read(), fname, 'exec')
+        else:
+            code = marshal.loads(f.read())
+            f.close()
+            assert isinstance(code, types.CodeType)
     elif fname.endswith('.py'):
         code = compile(open(fname).read(), fname, 'exec')
     else:
+
 #single_loop {
-  float: right;
+    float: right;
 }
 
 #loops {
 }
 
 #main {
-  float: left;
-  width: 50%;
+    float: left;
+    width: 50%;
+}
+
+.source {
+    white-space: pre;
+    font-size: 15px;
+}
+
+.hidden {
+    color: #aaa;
+}
+
+.visible {
+    color: #0f0;
+}
+
+.operations {
+    display: block;
+    border: 1px solid #CACACA;
+    -moz-border-radius: 5px;
+	  -webkit-border-radius: 5px;
+    border-radius: 5px;
+	  -webkit-box-shadow: 0px 0px 7px #cacaca;
+    margin-left: 100px;
+    padding-bottom: 5px;
+    padding-top: 5px;
+}
+
+.single-operation {
+    font-size: 12px;
+    white-space: pre;
+    margin-left: 10px;
 }

templates/loop.html

   <script src="/static/script.js"></script>
   <script>
     $(document).ready(function() {
-      $.scrollTo($("[name=line-{{startline}}]"), 200);
+      $.scrollTo($("#line-{{startline}}"), 200);
     });
   </script>
 </head>
 <body>
-  {{code|safe}}
+  {% for sourceline in source.lines %}
+     {% if sourceline.in_loop %}
+         <div id="line-{{loop.index + source.firstlineno}}" class="source visible">{{sourceline.line}}</div>
+         {% if sourceline.chunks %}
+            <div class="operations">
+                {% for chunk in sourceline.chunks %}
+                   {% for op in chunk.operations[1:] %}
+                      <span class="single-operation">{{op.repr() + "\n"}}</span>
+                   {% endfor %}
+                {% endfor %}
+            </div>
+         {% endif %}
+     {% else %}
+         <div id="line-{{loop.index + source.firstlineno}}" class="source hidden">{{sourceline.line}}</div>
+     {% endif %}
+  {% endfor %}
 </body>

test/test_display.py

+
+from display import CodeRepr
+
+class MockLoop(object):
+    pass
+
+class MockCode(object):
+    pass
+
+class MockChunk(object):
+    def __init__(self, operations, lineno):
+        self.operations = operations
+        self.lineno = lineno
+
+SOURCE = """def f():
+return a + b
+"""
+
+def test_code_repr():
+    loop = MockLoop()
+    loop.chunks = [MockChunk([], 3), MockChunk(['a', 'b', 'c'], 4),
+                   MockChunk(['a', 'b'], 4)]
+    MockLoop.linerange = (4, 5)
+    code = MockCode()
+    code.co_firstlineno = 3
+    repr = CodeRepr(SOURCE, code, loop)
+    assert len(repr.lines) == 3
+    assert repr.lines[1].in_loop
+    assert not repr.lines[0].in_loop
+    assert repr.lines[0].chunks == []
+    assert repr.lines[1].chunks == [loop.chunks[1], loop.chunks[2]]

test/test_loops.py

     res = slice_debug_merge_points(ops)
     assert res.repr() == res.chunks[1].repr()
 
-LINES = """19883   <code object _optimize_charset, file '/home/fijal/src/pypy-trunk/lib-python/modified-2.5.2/sre_compile.py', line 214> #290 FOR_ITER
-645     <code object _optimize_charset, file '/home/fijal/src/pypy-trunk/lib-python/modified-2.5.2/sre_compile.py', line 214> #290 FOR_ITER
-3810    <code object _mk_bitmap, file '/home/fijal/src/pypy-trunk/lib-python/modified-2.5.2/sre_compile.py', line 265> #66 FOR_ITER
-334     <code object _mk_bitmap, file '/home/fijal/src/pypy-trunk/lib-python/modified-2.5.2/sre_compile.py', line 265> #66 FOR_ITER
-5       <code object _optimize_charset, file '/home/fijal/src/pypy-trunk/lib-python/modified-2.5.2/sre_compile.py', line 214> #346 POP_TOP
-2256920 <code object <genexp>, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 67> #24 POP_TOP
-2256864 <code object <genexp>, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 46> #20 POP_TOP
-1955880 <code object <genexp>, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 67> #9 STORE_FAST
-1956214 <code object <genexp>, file '/home/fijal/src/pypy-benchmarks/unladen_swallow/performance/bm_ai.py', line 46> #9 STORE_FAST
-""".split("\n")
 
 #def test_parse_log_count():
 #    parse_log_counts(LINES)
     ''' % locals())
     res = slice_debug_merge_points(ops)
     assert res.chunks[1].lineno == 3
+
+def test_linerange():
+    fname = str(py.path.local(__file__).join('..', 'x.py'))
+    ops = parse('''
+    [i0, i1]
+    debug_merge_point("<code object f, file '%(fname)s', line 5> #9 LOAD_FAST")
+    debug_merge_point("<code object f, file '%(fname)s', line 5> #12 LOAD_CONST")
+    debug_merge_point("<code object f, file '%(fname)s', line 5> #22 LOAD_CONST")
+    debug_merge_point("<code object f, file '%(fname)s', line 5> #6 SETUP_LOOP")
+    ''' % locals())
+    res = slice_debug_merge_points(ops)
+    assert res.linerange == (7, 8)

test/test_module.py

     assert code.co_name == 'sub'
     assert code.co_filename == '/usr/lib/python2.6/re.py'
     assert code.co_firstlineno == 144
+
+def test_ast():
+    pass
 
 def f(a, b):
     return a + b
+
+def g():
+    i = 0
+    while i < 10:
+        i += 1