[pypy-svn] r10020 - in pypy/dist/pypy: objspace tool

rxe at codespeak.net rxe at codespeak.net
Mon Mar 21 21:20:55 CET 2005


Author: rxe
Date: Mon Mar 21 21:20:55 2005
New Revision: 10020

Modified:
   pypy/dist/pypy/objspace/trace.py
   pypy/dist/pypy/tool/traceinteractive.py
   pypy/dist/pypy/tool/traceop.py
Log:
Fix up traceobject space to trace in realtime - warranting itself the name
trace object space.
ResultPrinter now acts reasonably - with options to recurse on operations and
to ignore any frames with code objects that are applevel.



Modified: pypy/dist/pypy/objspace/trace.py
==============================================================================
--- pypy/dist/pypy/objspace/trace.py	(original)
+++ pypy/dist/pypy/objspace/trace.py	Mon Mar 21 21:20:55 2005
@@ -4,7 +4,8 @@
 """
 
 from __future__ import generators
-from pypy.tool import pydis 
+from pypy.tool import pydis
+from pypy.tool.traceop import ResultPrinter
 from pypy.interpreter.baseobjspace import ObjSpace
 
 # __________________________________________________________________________
@@ -49,24 +50,21 @@
     def __init__(self, callinfo, e):
         self.callinfo = callinfo
         self.ex = e
-
+                
 class TraceResult(object):
-    """ this is the state of tracing-in-progress. """
+    """ This is the state of tracing-in-progress. """
     def __init__(self, tracespace):
         self.events = []
+        self.reentrant = True
         self.tracespace = tracespace
+        self.printer = ResultPrinter()
 
-    def append(self, arg):
-        self.events.append(arg)
-
-    def getdisresult(self, frame, _cache = {}):
-        """ return (possibly cached) pydis result for the given frame. """
-        try:
-            return _cache[id(frame.code)]
-        except KeyError:
-            res = _cache[id(frame.code)] = pydis.pydis(frame.code)
-            assert res is not None
-            return res
+    def append(self, event):
+        if self.reentrant:
+            self.reentrant = False
+            self.events.append(event)
+            self.printer.print_event(self.tracespace, self, event)
+            self.reentrant = True
 
     def getbytecodes(self):
         for event in self.events:
@@ -83,6 +81,16 @@
         for event in self.events:
             yield event
 
+    def getdisresult(self, frame, _cache = {}): # XXX Should perhaps be local to TraceResult
+        """ return (possibly cached) pydis result for the given frame. """
+
+        try:
+            return _cache[id(frame.code)]
+        except KeyError:
+            res = _cache[id(frame.code)] = pydis.pydis(frame.code)
+            assert res is not None
+            return res
+
 # __________________________________________________________________________
 #
 # Tracer Proxy objects 
@@ -93,7 +101,7 @@
     def __init__(self, result, ec):
         self.ec = ec
         self.result = result
-
+        
     def __getattr__(self, name):
         """ generically pass through everything else ... """
         return getattr(self.ec, name)
@@ -112,13 +120,14 @@
     def bytecode_trace(self, frame):
         """ called just before execution of a bytecode. """
         self.result.append(ExecBytecode(frame))
+        self.ec.bytecode_trace(frame)
 
 class CallableTracer(object):
     def __init__(self, result, name, func):
         self.result = result
         self.name = name
         self.func = func
-
+        
     def __call__(self, *args, **kwargs):
         callinfo = CallInfo(self.name, self.func, args, kwargs) 
         self.result.append(CallBegin(callinfo))
@@ -152,9 +161,12 @@
     global operations
     if operations is None:
         operations = dict([(r[0], r[0]) for r in ObjSpace.MethodTable])
-        for name in ObjSpace.IrregularOpTable+ ["get_and_call_function"]:
+        for name in ObjSpace.IrregularOpTable + ["get_and_call_function"]:
             operations[name] = name
 
+    # Remove list
+    for name in ["wrap", "unwrap"]:
+        operations.pop(name, None)
     return operations
 
 def create_trace_space(space = None, operations = None):    
@@ -207,8 +219,7 @@
 
     trace_clz = type("Trace" + space.__class__.__name__, (Trace,), {})
     space.__oldclass__, space.__class__ = space.__class__, trace_clz
-
-    # XXX Ensure space's sys & builtin are fully loaded?
+    
     space.settrace()
     return space
 

Modified: pypy/dist/pypy/tool/traceinteractive.py
==============================================================================
--- pypy/dist/pypy/tool/traceinteractive.py	(original)
+++ pypy/dist/pypy/tool/traceinteractive.py	Mon Mar 21 21:20:55 2005
@@ -18,7 +18,6 @@
 import autopath
 
 from pypy.tool import pydis
-from pypy.tool.traceop import ResultPrinter
 
 from pypy.interpreter import executioncontext, pyframe, baseobjspace
 from pypy.interpreter.baseobjspace import ObjSpace
@@ -109,7 +108,6 @@
         # Trace is binary (on or off), but we have different print levels
         # for tracelevel > 0
         self.tracelevel = 0
-        self.resprinter = ResultPrinter()
         
     def interact(self, banner=None):
         if banner is None:
@@ -160,10 +158,6 @@
 
         self.tracelevel = tracelevel
 
-        # XXX Do something better than this - I'm not really sure what is useful
-        # and what isn't (rxe)
-        self.resprinter.operations_level = tracelevel
-
     def runcode(self, code):
         # 'code' is a CPython code object
         from pypy.interpreter.pycode import PyCode
@@ -189,14 +183,13 @@
             if tracelevel != self.tracelevel:
                 self.set_tracelevel(tracelevel)
 
-            if res is not None and self.tracelevel:                
-                self.resprinter.print_result(s, res)
+            #if res is not None and self.tracelevel:                
+            #    self.resprinter.print_result(s, res)
                               
         except baseobjspace.OperationError, operationerr:
             if self.tracelevel:
                 res = s.getresult()
                 s.settrace()
-                self.resprinter.print_result(s, res)
 
             # XXX insert exception info into the application-level sys.last_xxx
             print

Modified: pypy/dist/pypy/tool/traceop.py
==============================================================================
--- pypy/dist/pypy/tool/traceop.py	(original)
+++ pypy/dist/pypy/tool/traceop.py	Mon Mar 21 21:20:55 2005
@@ -1,21 +1,6 @@
 
 import autopath
 
-from pypy.tool import pydis
-from pypy.objspace import trace
-
-def getdisresult(obj, _cache={}):
-    """ return dissassemble result for the given obj which can be a
-        pyframe or function or a code object. 
-    """
-    obj = getattr(obj, 'func_code', obj)
-    obj = getattr(obj, 'code', obj)
-    try:
-        return _cache[obj]
-    except KeyError:
-        disresult = _cache[obj] = pydis.pydis(obj)
-        return disresult
-
 class Stack(list):
     push = list.append
 
@@ -30,50 +15,38 @@
 
 class ResultPrinter:
 
-    def __init__(self,
-                 operations_level = 2,
-                 indentor = '  ',
-                 skip_bytecodes = ["PRINT_EXPR", "PRINT_ITEM", "PRINT_NEWLINE"]):
+    def __init__(self, show_applevel = False, recursive_operations = False, indentor = '  '):
         
         # Configurable stuff
-        self.indentor = indentor
-        self.skip_bytecodes = skip_bytecodes
-        self.operations_level = operations_level
-        
-        self.reset()
+        self.indentor = indentor        
+        self.show_applevel = show_applevel
+        self.recursive_operations = recursive_operations
+
+        # Keeps a stack of current state to handle
+        # showing of applevel and recursive operations
+        self.indent_state = Stack()
 
     def reset(self):
-        # State stuff
-        self.ops = Stack()
-        self.frames = Stack()
-        self.frame_count = 0
-        self.skip_frame_count = None
+        self.indent_state = Stack()
 
     def print_line(self, line, additional_indent = 0):
-        if self.skip_frame_count is not None:
-            return
-
-        if self.frame_count:
-            indent = self.frame_count + additional_indent - 1
+        state = self.indent_state.top()
+        if state is not None and not state[0]:
+            return  
+        
+        indent_count = len([c for c, t, f in self.indent_state if c])
+        if indent_count:
+            indent = indent_count + additional_indent - 1
             assert (indent >= 0)
             line = (self.indentor * indent) + "|-" + line 
 
         print line
-
+        
     def print_line_operations(self, line, additional_indent = 0):
-        # Don't allow operations to be exposed if operations level is up
-        # but do allow operations to be printed
-        if len(self.ops) > self.operations_level:
-            return
-
         self.print_line(line, additional_indent = additional_indent)
         
     def print_frame(self, print_type, frame):
 
-        # Don't allow frames to be exposed if operations level is up
-        if len(self.ops) >= self.operations_level:
-            return
-
         code = getattr(frame, 'code', None)
         filename = getattr(code, 'co_filename', "")
         lineno = getattr(code, 'co_firstlineno', "")
@@ -82,15 +55,9 @@
         self.print_line(s)        
 
     def print_bytecode(self, index, bytecode):
-
-        # Don't allow bytecodes to be exposed if operations level is up
-        if len(self.ops) >= self.operations_level:
-            return
-
         s = "%2d%s%s" % (index, (self.indentor * 2), bytecode)
         self.print_line(s)
 
-
     def print_op_enter(self, name, str_args):
         s = " " * 17
         s += ">> %s%s" % (name, str_args)
@@ -102,104 +69,105 @@
         s += "%s =: %s" % (name, str_res)
         self.print_line_operations(s)
 
-
     def print_op_exc(self, name, exc):
         s = " " * 17
         s += "x= %s %s" % (name, exc)
         self.print_line_operations(s)
 
-       
-    def print_result(self, space, traceres):
+    def print_result(self, space, event_result):
+        for event in event_result.getevents():
+            print_event(space, event, event_result)
+            
+    def print_event(self, space, event_result, event):
+        from pypy.objspace import trace
+        
+        if isinstance(event, trace.EnterFrame):
+            frame = event.frame
+            if self.show_applevel or not frame.code.getapplevel():
+                show = True
+            else:
+                show = False
 
-        self.reset()
+            self.indent_state.append((show, trace.EnterFrame, frame))
+            self.print_frame("enter", frame)
 
-        for event in traceres.getevents():
+        elif isinstance(event, trace.LeaveFrame):
 
-            if isinstance(event, trace.EnterFrame):
-                frame = event.frame
-                self.print_frame("enter", frame)
-
-                self.frames.push(frame)
-                self.frame_count += 1
-                
-            elif isinstance(event, trace.LeaveFrame):
-                lastframe = self.frames.pop()
-                self.frame_count -= 1
-                
-                # Reset skip frame count?
-                if self.frame_count < self.skip_frame_count:
-                    self.skip_frame_count = None
-                    
-                self.print_frame("leave", lastframe)           
-                
-            elif isinstance(event, trace.ExecBytecode):
-
-                # Reset skip frame count?
-                if self.frame_count == self.skip_frame_count:
-                    self.skip_frame_count = None
-
-                frame = event.frame 
-                assert (frame == self.frames.top())
-                
-                # Get bytecode from frame
-                disresult = getdisresult(frame)
-                bytecode = disresult.getbytecode(event.index)
-                self.print_bytecode(event.index, bytecode)
-
-                # When operations_level > 1, some bytecodes produce high number of
-                # operations / bytecodes (usually because they have been written at app
-                # level) - this hack avoids them recursing on them selves
-                if bytecode.name in self.skip_bytecodes:
-                    self.print_line("...", 1)
-                    self.skip_frame_count = self.frame_count           
-
-            elif isinstance(event, trace.CallBegin):
-                info = event.callinfo
-
-                self.ops.push(info)
-                lastframe = self.frames.top()
-                self.print_op_enter(info.name, repr_args(space, lastframe, info.args))
-                self.frame_count += 1
-
-            elif isinstance(event, trace.CallFinished):
-                info = event.callinfo
-
-                self.frame_count -= 1
-                self.print_op_leave(info.name, repr_value(space, event.res))
-                
-                assert self.ops.pop() == event.callinfo
-                    
-            elif isinstance(event, trace.CallException):
-                info = event.callinfo
-                self.frame_count -= 1
-                
-                self.print_op_exc(info.name, event.ex)
-                
-                assert self.ops.pop() == event.callinfo
+            lastframe = self.indent_state.top()[2]
+            assert lastframe is not None
 
-            else:
-                pass
+            self.print_frame("leave", lastframe)           
+            self.indent_state.pop()
 
+        elif isinstance(event, trace.ExecBytecode):
+
+            frame = event.frame
+            assert (frame == self.get_last_frame())
+
+            # Get bytecode from frame
+            disresult = event_result.getdisresult(frame)
+            bytecode = disresult.getbytecode(event.index)
+            self.print_bytecode(event.index, bytecode)
+
+        elif isinstance(event, trace.CallBegin):
+            lastframe = self.get_last_frame()
+            info = event.callinfo
+
+            show = True
+
+            # Check if we are in applevel?
+            if not self.show_applevel:
+                if lastframe is None or lastframe.code.getapplevel():
+                    show = False
+
+            # Check if recursive operations?
+            prev_indent_state = self.indent_state.top()
+            if not self.recursive_operations and prev_indent_state is not None:
+                if prev_indent_state[1] == trace.CallBegin:
+                    show = False
+
+            self.indent_state.append((show, trace.CallBegin, None))
+            self.print_op_enter(info.name, repr_args(space,
+                                                     self.get_last_frame(),
+                                                     info.args))
+
+        elif isinstance(event, trace.CallFinished):
+            info = event.callinfo
+
+            self.print_op_leave(info.name, repr_value(space, event.res))
+            self.indent_state.pop()
+
+        elif isinstance(event, trace.CallException):
+            info = event.callinfo
+
+            self.print_op_exc(info.name, event.ex)
+            self.indent_state.pop()                
+
+    def get_last_frame(self):
+        for c, t, f in self.indent_state[::-1]:
+            if f is not None:
+                return f
+            
 print_result = ResultPrinter().print_result
 
 def repr_value(space, value):
     """ representations for debugging purposes """        
-    res = str(value)
     try:
         # XXX Sure this won't go down well - didn't really want
         # to clutter up the interpeter code 
         from pypy.interpreter.function import Function, Method
+        from pypy.interpreter.eval import Code
 
         if isinstance(value, Function):
-            res = "Function(%s, %s)" % (value.name, value.code)
+            res = "Function(%s)" % value.name
 
         if isinstance(value, Method):
-            res = "Method(%s, %s)" % (value.w_function.name, value.w_function.code)
-
-    except Exception, exc:
-        pass
+            res = "Method(%s)" % value.w_function.name
+        raise Exception, "XXX only certain types or toooo slow"
+    except:
+        res = str(value)
     
-    return res[:240]
+    return res[:80]
 
 def repr_args(space, frame, args):
     l = []
@@ -213,7 +181,6 @@
             
     return "(" + ", ".join(l) + ")"
 
-
 def perform_trace(tspace, app_func, *args_w, **kwds_w):
     from pypy.interpreter.gateway import app2interp
     from pypy.interpreter.argument import Arguments    
@@ -231,8 +198,9 @@
     tspace.settrace()
     return w_result, trace_result
 
-
 if __name__ == '__main__':
+
+    from pypy.objspace import trace
     from pypy.tool import option
     args = option.process_options(option.get_standard_options(),
                                   option.Options)
@@ -250,7 +218,5 @@
         return count
 
     # Note includes lazy loading of builtins
-    res, traceres = perform_trace(tspace, app_test, tspace.wrap(5))
-    print_result(tspace, traceres)
-
-    print "Result", res
+    res = perform_trace(tspace, app_test, tspace.wrap(5))
+    print "Result:", res



More information about the Pypy-commit mailing list