[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