[pypy-svn] r10294 - in pypy/dist: goal pypy/translator/tool
pedronis at codespeak.net
pedronis at codespeak.net
Mon Apr 4 17:37:07 CEST 2005
Author: pedronis
Date: Mon Apr 4 17:37:07 2005
New Revision: 10294
Modified:
pypy/dist/goal/translate_pypy.py
pypy/dist/pypy/translator/tool/graphpage.py
Log:
added graph pages for only the class hierarchy and a localized call graph for functions
(showing just a single function and its direct callers and callees, there are extra nodes that give
access to the same for those)
there's a threshold for translate_pypy.py for the number of functions in translator set with -huge=.
Above the threshold we don't try to show the full call graph but only the localized one for the entry-point.
Command are accesible at the translate_pypy prompt to ask for a graph: see help graphs:
- for example classhier will show the class hierarchy graph,
- try showg intobject.W_IntObject.__mm_mul after translate_pypy targetpypy1 analysis for an
example of localized call graph.
Modified: pypy/dist/goal/translate_pypy.py
==============================================================================
--- pypy/dist/goal/translate_pypy.py (original)
+++ pypy/dist/goal/translate_pypy.py Mon Apr 4 17:37:07 2005
@@ -21,6 +21,8 @@
-tcc Equivalent to the envvar PYPY_CC='tcc -shared -o "%s.so" "%s.c"'
-- http://fabrice.bellard.free.fr/tcc/
-no-d Disable recording of debugging information
+ -huge=% Threshold in the number of functions after which only a local call
+ graph and not a full one is displayed
"""
import autopath, sys, threading, pdb, os
@@ -43,7 +45,7 @@
# __________ Main __________
def analyse(target):
- global t
+ global t, entry_point
entry_point, inputtypes = target()
@@ -152,6 +154,7 @@
if __name__ == '__main__':
targetspec = 'targetpypy'
+ huge = 100
options = {'-text': False,
'-no-c': False,
@@ -172,6 +175,8 @@
except ValueError:
if os.path.isfile(arg+'.py'):
targetspec = arg
+ elif arg.startwith('-huge='):
+ huge = int(arg[6:])
else:
assert arg in options, "unknown option %r" % (arg,)
options[arg] = True
@@ -206,7 +211,7 @@
print "don't know about", x
def run_server():
- from pypy.translator.tool.graphpage import TranslatorPage
+ from pypy.translator.tool import graphpage
from pypy.translator.tool.pygame.graphclient import get_layout
from pypy.translator.tool.pygame.graphdisplay import GraphDisplay
import pygame
@@ -214,7 +219,12 @@
if not options['-no-mark-some-objects']:
find_someobjects(t, quiet=True)
- display = GraphDisplay(get_layout(TranslatorPage(t)))
+ if len(t.functions) <= huge:
+ page = graphpage.TranslatorPage(t)
+ else:
+ page = graphpage.LocalizedCallGraphPage(t, entry_point)
+
+ display = GraphDisplay(get_layout(page))
async_quit = display.async_quit
def show(page):
display.async_cmd(layout=get_layout(page))
@@ -236,27 +246,103 @@
return
self.show(page)
- def do_show(self, arg):
- if '.' in arg:
- name = ''
- obj = None
- for comp in arg.split('.'):
- name += comp
- obj = getattr(obj, comp, None)
- if obj is None:
- try:
- obj = __import__(name, {}, {}, ['*'])
- except ImportError:
- print "*** Not found: %s" % arg
- return
- name += '.'
- if hasattr(obj, 'im_func'):
- obj = obj.im_func
- if obj in t.flowgraphs:
- from pypy.translator.tool.graphpage import FlowGraphPage
- self._show(FlowGraphPage(t, [obj]))
+ def _importobj(self, fullname):
+ obj = None
+ name = ''
+ for comp in fullname.split('.'):
+ name += comp
+ obj = getattr(obj, comp, None)
+ if obj is None:
+ try:
+ obj = __import__(name, {}, {}, ['*'])
+ except ImportError:
+ raise NameError
+ name += '.'
+ return obj
+
+ TRYPREFIXES = ['','pypy.','pypy.objspace.','pypy.interpreter.', 'pypy.objspace.std.' ]
+
+ def _getobj(self, name):
+ if '.' in name:
+ for pfx in self.TRYPREFIXES:
+ try:
+ return self._importobj(pfx+name)
+ except NameError:
+ pass
+ try:
+ return self._getval(name)
+ except (NameError, AttributeError, LookupError):
+ print "*** Not found:", name
+ return None
+
+ def do_showg(self, arg):
+ """showg obj
+show graph for obj, obj can be an expression or a dotted name
+(in which case prefixing with some packages in pypy is tried (see help pypyprefixes)).
+if obj is a function or method, the localized call graph is shown;
+if obj is a class or ClassDef the class definition graph is shown"""
+ from pypy.annotation.classdef import ClassDef
+ from pypy.translator.tool import graphpage
+ obj = self._getobj(arg)
+ if obj is None:
+ return
+ if hasattr(obj, 'im_func'):
+ obj = obj.im_func
+ if obj in t.flowgraphs:
+ page = graphpage.LocalizedCallGraphPage(t, obj)
+ elif obj in getattr(t.annotator, 'getuserclasses', lambda: {})():
+ page = graphpage.ClassDefPage(t, t.annotator.getuserclasses()[obj])
+ elif isinstance(obj, ClassDef):
+ page = graphpage.ClassDefPage(t, obj)
else:
print "*** Nothing to do"
+ return
+ self._show(page)
+
+ def do_flowg(self, arg):
+ """callg obj
+show flow graph for function obj, obj can be an expression or a dotted name
+(in which case prefixing with some packages in pypy is tried (see help pypyprefixes))"""
+ import types
+ from pypy.translator.tool import graphpage
+ obj = self._getobj(arg)
+ if obj is None:
+ return
+ if hasattr(obj, 'im_func'):
+ obj = obj.im_func
+ if not isinstance(obj, types.FunctionType):
+ print "*** Not a function"
+ return
+ self._show(graphpage.FlowGraphPage(t, [obj]))
+
+ def do_callg(self, arg):
+ """callg obj
+show localized call-graph for function obj, obj can be an expression or a dotted name
+(in which case prefixing with some packages in pypy is tried (see help pypyprefixes))"""
+ import types
+ from pypy.translator.tool import graphpage
+ obj = self._getobj(arg)
+ if obj is None:
+ return
+ if hasattr(obj, 'im_func'):
+ obj = obj.im_func
+ if not isinstance(obj, types.FunctionType):
+ print "*** Not a function"
+ return
+ self._show(graphpage.LocalizedCallGraphPage(t, obj))
+
+ def do_classhier(self, arg):
+ """classhier
+show class hierarchy graph"""
+ from pypy.translator.tool import graphpage
+ self._show(graphpage.ClassHierarchyPage(t))
+
+ def help_graphs(self):
+ print "graph commands are: showg, flowg, callg, classhier"
+
+ def help_pypyprefixes(self):
+ print "these prefixes are tried for dotted names in graph commands:"
+ print self.TRYPREFIXES
def debug(got_error):
pdb_plus_show = PdbPlusShow()
Modified: pypy/dist/pypy/translator/tool/graphpage.py
==============================================================================
--- pypy/dist/pypy/translator/tool/graphpage.py (original)
+++ pypy/dist/pypy/translator/tool/graphpage.py Mon Apr 4 17:37:07 2005
@@ -1,4 +1,4 @@
-import inspect
+import inspect, types
from pypy.objspace.flow.model import traverse, Block
from pypy.translator.tool.make_dot import DotGen, make_dot, make_dot_graphs
from pypy.interpreter.pycode import CO_VARARGS, CO_VARKEYWORDS
@@ -208,7 +208,7 @@
if isinstance(obj, ClassDef):
#data = '%s.%s' % (obj.cls.__module__, obj.cls.__name__)
data = repr(obj.cls)
- else:
+ elif isinstance(obj, types.FunctionType):
func = obj
try:
source = inspect.getsource(func)
@@ -217,6 +217,8 @@
data = '%s:%d\n%s' % (func.func_globals.get('__name__', '?'),
func.func_code.co_firstlineno,
source.split('\n')[0])
+ else:
+ continue
self.links[name] = data
def get_blocked_functions(self, functions):
@@ -300,6 +302,70 @@
self.compute_class_hieararchy(dotgen)
+class LocalizedCallGraphPage(BaseTranslatorPage):
+ """A GraphPage showing a the call graph between functions
+ as well as the class hierarchy."""
+
+ def graph_name(self, func0):
+ return 'LCG_%s' % nameof(func0)
+
+ def do_compute(self, dotgen, func0):
+ translator = self.translator
+
+ functions = {}
+
+ for f1, f2 in translator.callgraph.itervalues():
+ if f1 is func0 or f2 is func0:
+ dotgen.emit_edge(nameof(f1), nameof(f2))
+ functions[f1] = True
+ functions[f2] = True
+
+ functions = functions.keys()
+
+ # show the call graph
+ blocked_functions = self.get_blocked_functions(functions)
+
+ highlight_functions = getattr(translator, 'highlight_functions', {}) # XXX
+ for func in functions:
+ name = func.func_name
+ class_ = getattr(func, 'class_', None)
+ if class_ is not None:
+ name = '%s.%s' % (class_.__name__, name)
+ data = self.labelof(func, name)
+ if func in blocked_functions:
+ kw = {'fillcolor': 'red'}
+ elif func in highlight_functions:
+ kw = {'fillcolor': '#ffcccc'}
+ else:
+ kw = {}
+ dotgen.emit_node(nameof(func), label=data, shape="box", **kw)
+
+ if func is not func0:
+ lcg = 'LCG_%s' % nameof(func)
+ label = name+'...'
+ dotgen.emit_node(lcg, label=label)
+ dotgen.emit_edge(nameof(func), lcg)
+ self.links[label] = 'go to its localized call graph'
+ self.object_by_name[label] = func
+
+ def followlink(self, name):
+ if name.endswith('...'):
+ obj = self.object_by_name[name]
+ return LocalizedCallGraphPage(self.translator, obj)
+ return BaseTranslatorPage.followlink(self, name)
+
+class ClassHierarchyPage(BaseTranslatorPage):
+ """A GraphPage showing the class hierarchy."""
+
+ def graph_name(self):
+ return 'class_hierarchy'
+
+ def do_compute(self, dotgen):
+ translator = self.translator
+
+ # show the class hierarchy
+ self.compute_class_hieararchy(dotgen)
+
def nameof(obj, cache={}):
# NB. the purpose of the cache is not performance, but to ensure that
# two objects that compare equal get the same name
More information about the Pypy-commit
mailing list