[pypy-svn] r7749 - in pypy/trunk/src: goal pypy/objspace/flow pypy/translator pypy/translator/tool pypy/translator/tool/pygame
arigo at codespeak.net
arigo at codespeak.net
Sat Dec 4 13:38:00 CET 2004
Author: arigo
Date: Sat Dec 4 13:37:58 2004
New Revision: 7749
Added:
pypy/trunk/src/pypy/translator/tool/graphpage.py
- copied, changed from r7715, pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py
pypy/trunk/src/pypy/translator/tool/graphserver.py
pypy/trunk/src/pypy/translator/tool/pygame/graphclient.py (contents, props changed)
Removed:
pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py
Modified:
pypy/trunk/src/goal/translate_pypy.py
pypy/trunk/src/pypy/objspace/flow/model.py
pypy/trunk/src/pypy/translator/tool/flowtrace.py
pypy/trunk/src/pypy/translator/tool/make_dot.py
pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py
pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py
pypy/trunk/src/pypy/translator/translator.py
Log:
translate_pypy can now be a "web" server sending graphs to the "browser" in
translator/tool/pygame/. (The protocol is not HTTP, though.) It is useful
both for inspecting graphs generated by translate_pypy on a remote
supercomputer, and to track the progress of a running translate_pypy -- the
"server" is started early and runs in parallel with the annotation phase.
(In the latter case, red blocks correspond to functions that containing
pending blocks, not just dead-locked blocked blocks.)
To enable this, translate_pypy must be run with a port number to listen to.
For the stand-alone graph client run pypy/translator/tool/pygame/graphclient.
Modified: pypy/trunk/src/goal/translate_pypy.py
==============================================================================
--- pypy/trunk/src/goal/translate_pypy.py (original)
+++ pypy/trunk/src/goal/translate_pypy.py Sat Dec 4 13:37:58 2004
@@ -4,6 +4,8 @@
"""
Command-line options for translate_pypy:
+ port Listen on the given port number for connexions
+ (see pypy/translator/tool/pygame/graphclient.py)
-text Don't start the Pygame viewer
-no-a Don't infer annotations, just translate everything
-no-c Don't generate the C code
@@ -46,6 +48,8 @@
# caches (as far as analyzing the entry_point is concerned)
entry_point()
t = Translator(entry_point, verbose=True, simplifying=True)
+ if listen_port:
+ run_async_server()
if not options['-no-a']:
a = t.annotate([])
a.simplify()
@@ -138,6 +142,13 @@
cleanup(*cleanup_args)
return threading.Thread(target=_run_in_thread, args=())
+def run_async_server():
+ from pypy.translator.tool import graphpage, graphserver
+ homepage = graphpage.TranslatorPage(t)
+ graphserver.run_server(homepage, port=listen_port, background=True)
+ options['-text'] = True
+
+
if __name__ == '__main__':
options = {'-text': False,
@@ -149,12 +160,16 @@
'-tcc': False,
'-no-d': False,
}
+ listen_port = None
for arg in sys.argv[1:]:
if arg in ('-h', '--help'):
print __doc__.strip()
sys.exit()
- assert arg in options, "unknown option %r" % (arg,)
- options[arg] = True
+ try:
+ listen_port = int(arg)
+ except ValueError:
+ assert arg in options, "unknown option %r" % (arg,)
+ options[arg] = True
if options['-tcc']:
os.environ['PYPY_CC'] = 'tcc -shared -o "%s.so" "%s.c"'
if options['-no-d']:
@@ -186,14 +201,15 @@
print "don't know about", x
def run_server():
- from pypy.translator.tool.pygame.flowviewer import TranslatorLayout
+ from pypy.translator.tool.graphpage import TranslatorPage
+ from pypy.translator.tool.pygame.graphclient import get_layout
from pypy.translator.tool.pygame.graphdisplay import GraphDisplay
import pygame
if not options['-no-mark-some-objects']:
find_someobjects(t, quiet=True)
- display = GraphDisplay(TranslatorLayout(t))
+ display = GraphDisplay(get_layout(TranslatorPage(t)))
async_quit = display.async_quit
return display.run, async_quit, pygame.quit
Modified: pypy/trunk/src/pypy/objspace/flow/model.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/flow/model.py (original)
+++ pypy/trunk/src/pypy/objspace/flow/model.py Sat Dec 4 13:37:58 2004
@@ -43,8 +43,8 @@
return self._onlyex
def show(self):
- from pypy.translator.tool.pygame.flowviewer import SingleGraphLayout
- SingleGraphLayout(self).display()
+ from pypy.translator.tool.graphpage import SingleGraphPage
+ SingleGraphPage(self).display()
class Link:
def __init__(self, args, target, exitcase=None):
Modified: pypy/trunk/src/pypy/translator/tool/flowtrace.py
==============================================================================
--- pypy/trunk/src/pypy/translator/tool/flowtrace.py (original)
+++ pypy/trunk/src/pypy/translator/tool/flowtrace.py Sat Dec 4 13:37:58 2004
@@ -260,12 +260,12 @@
"""Shows the control flow graph with annotations if computed.
Requires 'dot' and pygame."""
from pypy.translator.tool.pygame.graphdisplay import GraphDisplay
- from pypy.translator.tool.pygame.flowviewer import FlowGraphLayout
+ from pypy.translator.tool.graphpage import FlowGraphPage
from pypy.translator.translator import Translator
t = Translator(func)
t.simplify()
#t.annotate([int])
- GraphDisplay(FlowGraphLayout(t)).run()
+ FlowGraphPage(t).display()
def timeit(num, func, *args):
from time import time as now
Copied: pypy/trunk/src/pypy/translator/tool/graphpage.py (from r7715, pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py)
==============================================================================
--- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original)
+++ pypy/trunk/src/pypy/translator/tool/graphpage.py Sat Dec 4 13:37:58 2004
@@ -1,27 +1,52 @@
-import autopath
import inspect
-from pypy.translator.tool.pygame.drawgraph import GraphLayout
-from pypy.translator.tool.make_dot import DotGen
+from pypy.objspace.flow.model import traverse
+from pypy.translator.tool.make_dot import DotGen, make_dot, make_dot_graphs
from pypy.interpreter.pycode import CO_VARARGS, CO_VARKEYWORDS
from pypy.annotation import model
from pypy.annotation.classdef import ClassDef
from pypy.tool.uid import uid
-class SingleGraphLayout(GraphLayout):
- """ A GraphLayout showing a single precomputed FlowGraph."""
+class GraphPage:
+ """Base class for the server-side content of one of the 'pages'
+ (one graph) sent over to and displayed by the client.
+ """
+ def __init__(self, *args):
+ self.args = args
+
+ def content(self):
+ """Compute the content of the page.
+ This doesn't modify the page in place; it returns a new GraphPage.
+ """
+ if hasattr(self, 'source'):
+ return self
+ else:
+ new = self.__class__()
+ new.source = '' # '''dot source'''
+ new.links = {} # {'word': 'statusbar text'}
+ new.compute(*self.args) # defined in subclasses
+ return new
+
+ def followlink(self, word):
+ raise KeyError
+
+ def display(self):
+ "Display a graph page locally."
+ from pypy.translator.tool.pygame.graphclient import get_layout
+ get_layout(self).display()
- def __init__(self, graph):
- from pypy.translator.tool.make_dot import make_dot
- fn = make_dot(graph.name, graph, target='plain')
- GraphLayout.__init__(self, fn)
+class SingleGraphPage(GraphPage):
+ """ A GraphPage showing a single precomputed FlowGraph."""
-class VariableHistoryGraphLayout(GraphLayout):
- """ A GraphLayout showing the history of variable bindings. """
+ def compute(self, graph):
+ self.source = make_dot(graph.name, graph, target=None)
- def __init__(self, translator, name, info, caused_by, history, func_names):
- self.links = {}
+
+class VariableHistoryGraphPage(GraphPage):
+ """ A GraphPage showing the history of variable bindings. """
+
+ def compute(self, translator, name, info, caused_by, history, func_names):
self.linkinfo = {}
self.translator = translator
self.func_names = func_names
@@ -44,9 +69,7 @@
label += '\\n' + self.createlink(caused_by)
dotgen.emit_node(str(n+1), shape="box", label=label)
dotgen.emit_edge(str(n+1), str(n))
- links = self.links # GraphLayout.__init__ will override it with {}
- GraphLayout.__init__(self, dotgen.generate(target='plain'))
- self.links.update(links)
+ self.source = dotgen.generate(target=None)
def createlink(self, position_key, wording='Caused by a call from'):
fn, block, pos = position_key
@@ -66,14 +89,13 @@
def followlink(self, funcname):
fn, block, pos = self.linkinfo[funcname]
# It would be nice to focus on the block
- return FlowGraphLayout(self.translator, [fn], self.func_names)
+ return FlowGraphPage(self.translator, [fn], self.func_names)
-class FlowGraphLayout(GraphLayout):
- """ A GraphLayout showing a Flow Graph (or a few flow graphs).
+class FlowGraphPage(GraphPage):
+ """ A GraphPage showing a Flow Graph (or a few flow graphs).
"""
- def __init__(self, translator, functions=None, func_names=None):
- from pypy.translator.tool.make_dot import make_dot_graphs
+ def compute(self, translator, functions=None, func_names=None):
self.translator = translator
self.annotator = translator.annotator
self.func_names = func_names or {}
@@ -84,8 +106,7 @@
for block, was_annotated in self.annotator.annotated.items():
if not was_annotated:
block.fillcolor = "red"
- fn = make_dot_graphs(graphs[0].name + "_graph", gs, target='plain')
- GraphLayout.__init__(self, fn)
+ self.source = make_dot_graphs(graphs[0].name+"_graph", gs, target=None)
# make the dictionary of links -- one per annotated variable
self.binding_history = {}
self.current_value = {}
@@ -109,7 +130,7 @@
caused_by = self.caused_by[varname]
history = list(self.binding_history.get(varname, []))
history.reverse()
- return VariableHistoryGraphLayout(self.translator, varname, cur_value,
+ return VariableHistoryGraphPage(self.translator, varname, cur_value,
caused_by, history, self.func_names)
@@ -127,10 +148,10 @@
return '\\n'.join(lines)
-class ClassDefLayout(GraphLayout):
- """A GraphLayout showing the attributes of a class.
+class ClassDefPage(GraphPage):
+ """A GraphPage showing the attributes of a class.
"""
- def __init__(self, translator, cdef):
+ def compute(self, translator, cdef):
self.translator = translator
dotgen = DotGen(cdef.cls.__name__, rankdir="LR")
@@ -152,14 +173,14 @@
prevcdef = cdef
cdef = cdef.basedef
- GraphLayout.__init__(self, dotgen.generate(target='plain'))
+ self.source = dotgen.generate(target=None)
-class TranslatorLayout(GraphLayout):
- """A GraphLayout showing a the call graph between functions
+class TranslatorPage(GraphPage):
+ """A GraphPage showing a the call graph between functions
as well as the class hierarchy."""
- def __init__(self, translator):
+ def compute(self, translator):
self.translator = translator
self.object_by_name = {}
self.name_by_object = {}
@@ -168,10 +189,16 @@
# show the call graph
functions = translator.functions
+ blocked_functions = {}
if translator.annotator:
- blocked_functions = translator.annotator.blocked_functions
- else:
- blocked_functions = {}
+ # don't use translator.annotator.blocked_functions here because
+ # it is not populated until the annotator finishes.
+ annotated = translator.annotator.annotated
+ for fn, graph in translator.flowgraphs.items():
+ def visit(node):
+ if annotated.get(node) is False:
+ blocked_functions[fn] = True
+ traverse(visit, graph)
highlight_functions = getattr(translator, 'highlight_functions', {}) # XXX
dotgen.emit_node('entry', fillcolor="green", shape="octagon",
label="Translator\\nEntry Point")
@@ -201,7 +228,7 @@
dotgen.emit_node(nameof(classdef), label=data, shape="box")
dotgen.emit_edge(nameof(classdef.basedef), nameof(classdef))
- GraphLayout.__init__(self, dotgen.generate(target='plain'))
+ self.source = dotgen.generate(target=None)
# link the function names to the individual flow graphs
for name, obj in self.object_by_name.iteritems():
@@ -232,9 +259,9 @@
def followlink(self, name):
obj = self.object_by_name[name]
if isinstance(obj, ClassDef):
- return ClassDefLayout(self.translator, obj)
+ return ClassDefPage(self.translator, obj)
else:
- return FlowGraphLayout(self.translator, [obj], self.name_by_object)
+ return FlowGraphPage(self.translator, [obj], self.name_by_object)
def nameof(obj, cache={}):
@@ -246,22 +273,3 @@
result = '%s__0x%x' % (getattr(obj, '__name__', ''), uid(obj))
cache[obj] = result
return result
-
-# ____________________________________________________________
-
-if __name__ == '__main__':
- from pypy.translator.translator import Translator
- from pypy.translator.test import snippet
- from pypy.translator.tool.pygame.graphdisplay import GraphDisplay
-
- t = Translator(snippet.powerset)
- #t.simplify()
- a = t.annotate([int])
- a.simplify()
- GraphDisplay(FlowGraphLayout(t)).run()
-
-## t = Translator(snippet._methodcall1)
-## t.simplify()
-## a = t.annotate([int])
-## a.simplify()
-## GraphDisplay(TranslatorLayout(t)).run()
Added: pypy/trunk/src/pypy/translator/tool/graphserver.py
==============================================================================
--- (empty file)
+++ pypy/trunk/src/pypy/translator/tool/graphserver.py Sat Dec 4 13:37:58 2004
@@ -0,0 +1,77 @@
+"""
+A socket server for GraphPages.
+"""
+
+import autopath, sys, thread, struct, marshal
+
+
+def run_server(homepage, port=8888, quiet=False, background=False):
+ import socket
+ server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ server_sock.bind(('', port))
+ server_sock.listen(5)
+ if not quiet:
+ print >> sys.stderr, 'Accepting connexions on port %d...' % port
+ def accept_connexions():
+ while True:
+ conn, addr = server_sock.accept()
+ if not quiet:
+ print >> sys.stderr, 'Connected by %r.' % (addr,)
+ thread.start_new_thread(serve_connexion, (conn, homepage))
+ if background:
+ thread.start_new_thread(accept_connexions, ())
+ else:
+ accept_connexions()
+
+
+def recv_all(s, count):
+ buf = ''
+ while len(buf) < count:
+ data = s.recv(count - len(buf))
+ if not data:
+ raise SystemExit # thread exit, rather
+ buf += data
+ return buf
+
+def recv_msg(s):
+ hdr_size = struct.calcsize("!i")
+ msg_size, = struct.unpack("!i", recv_all(s, hdr_size))
+ msg = recv_all(s, msg_size)
+ return marshal.loads(msg)
+
+def send_msg(s, msg):
+ data = marshal.dumps(msg)
+ s.sendall(struct.pack("!i", len(data)) + data)
+
+
+def serve_connexion(s, homepage):
+ pages = {0: homepage}
+ while True:
+ key, link = recv_msg(s)
+ page = pages[key]
+ if link is not None:
+ try:
+ page = page.content().followlink(link)
+ key = len(pages)
+ except KeyError:
+ page = MissingPage()
+ key = -1
+ pages[key] = page
+ page = page.content()
+ reply = {
+ 'key': key,
+ 'dot': page.source,
+ 'links': page.links,
+ }
+ send_msg(s, reply)
+
+
+class MissingPage:
+ links = {}
+ source = '''
+digraph error {
+msg [shape="box", label="Error: a link has gone missing.", color="black", fillcolor="red", style="filled"];
+}
+'''
+ def content(self):
+ return self
Modified: pypy/trunk/src/pypy/translator/tool/make_dot.py
==============================================================================
--- pypy/trunk/src/pypy/translator/tool/make_dot.py (original)
+++ pypy/trunk/src/pypy/translator/tool/make_dot.py Sat Dec 4 13:37:58 2004
@@ -23,6 +23,8 @@
def generate(self, storedir=None, target='ps'):
source = self.get_source()
+ if target is None:
+ return source # unprocessed
if storedir is None:
storedir = udir
pdot = storedir.join('%s.dot' % self.graphname)
Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py
==============================================================================
--- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original)
+++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Sat Dec 4 13:37:58 2004
@@ -79,6 +79,9 @@
from pypy.translator.tool.pygame.graphdisplay import GraphDisplay
GraphDisplay(self).run()
+ def reload(self):
+ return self
+
class Node:
def __init__(self, name, x, y, w, h, label, style, shape, color, fillcolor):
self.name = name
Deleted: /pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py
==============================================================================
--- /pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Sat Dec 4 13:37:58 2004
+++ (empty file)
@@ -1,267 +0,0 @@
-import autopath
-import inspect
-from pypy.translator.tool.pygame.drawgraph import GraphLayout
-from pypy.translator.tool.make_dot import DotGen
-from pypy.interpreter.pycode import CO_VARARGS, CO_VARKEYWORDS
-from pypy.annotation import model
-from pypy.annotation.classdef import ClassDef
-from pypy.tool.uid import uid
-
-
-class SingleGraphLayout(GraphLayout):
- """ A GraphLayout showing a single precomputed FlowGraph."""
-
- def __init__(self, graph):
- from pypy.translator.tool.make_dot import make_dot
- fn = make_dot(graph.name, graph, target='plain')
- GraphLayout.__init__(self, fn)
-
-
-class VariableHistoryGraphLayout(GraphLayout):
- """ A GraphLayout showing the history of variable bindings. """
-
- def __init__(self, translator, name, info, caused_by, history, func_names):
- self.links = {}
- self.linkinfo = {}
- self.translator = translator
- self.func_names = func_names
- dotgen = DotGen('binding')
- label = "Most recent binding of %s\\n\\n%s" % (name, nottoowide(info))
- if info.origin is not None:
- label += "\\n" + self.createlink(info.origin, 'Originated at')
- if caused_by is not None:
- label += '\\n' + self.createlink(caused_by)
- if info.caused_by_merge is not None:
- data = 'unionof%r' % (info.caused_by_merge,)
- label += '\\n%s' % nottoowide(data)
-
- dotgen.emit_node('0', shape="box", color="red", label=label)
- for n, (data, caused_by) in zip(range(len(history)), history):
- label = nottoowide(data)
- if data.origin is not None:
- label += "\\n" + self.createlink(data.origin, 'Originated at')
- if caused_by is not None:
- label += '\\n' + self.createlink(caused_by)
- dotgen.emit_node(str(n+1), shape="box", label=label)
- dotgen.emit_edge(str(n+1), str(n))
- links = self.links # GraphLayout.__init__ will override it with {}
- GraphLayout.__init__(self, dotgen.generate(target='plain'))
- self.links.update(links)
-
- def createlink(self, position_key, wording='Caused by a call from'):
- fn, block, pos = position_key
- basename = self.func_names.get(fn, fn.func_name)
- linkname = basename
- n = 1
- while self.linkinfo.get(linkname, position_key) != position_key:
- n += 1
- linkname = '%s_%d' % (basename, n)
- self.linkinfo[linkname] = position_key
- # It would be nice to get the block name somehow
- blockname = block.__class__.__name__
- self.links[linkname] = '%s, %s, position %r:\n%s' % (basename,
- blockname, pos, block.operations[pos])
- return '%s %s' % (wording, linkname)
-
- def followlink(self, funcname):
- fn, block, pos = self.linkinfo[funcname]
- # It would be nice to focus on the block
- return FlowGraphLayout(self.translator, [fn], self.func_names)
-
-
-class FlowGraphLayout(GraphLayout):
- """ A GraphLayout showing a Flow Graph (or a few flow graphs).
- """
- def __init__(self, translator, functions=None, func_names=None):
- from pypy.translator.tool.make_dot import make_dot_graphs
- self.translator = translator
- self.annotator = translator.annotator
- self.func_names = func_names or {}
- functions = functions or translator.functions
- graphs = [translator.getflowgraph(func) for func in functions]
- gs = [(graph.name, graph) for graph in graphs]
- if self.annotator and self.annotator.blocked_functions:
- for block, was_annotated in self.annotator.annotated.items():
- if not was_annotated:
- block.fillcolor = "red"
- fn = make_dot_graphs(graphs[0].name + "_graph", gs, target='plain')
- GraphLayout.__init__(self, fn)
- # make the dictionary of links -- one per annotated variable
- self.binding_history = {}
- self.current_value = {}
- self.caused_by = {}
- if self.annotator:
- for var in self.annotator.bindings:
- s_value = self.annotator.binding(var)
- info = '%s: %s' % (var.name, s_value)
- self.links[var.name] = info
- self.current_value[var.name] = s_value
- self.caused_by[var.name] = (
- self.annotator.binding_caused_by.get(var))
- for var, history in self.annotator.bindingshistory.items():
- cause_history = (
- self.annotator.binding_cause_history.get(var, []))
- self.binding_history[var.name] = zip(history, cause_history)
-
- def followlink(self, varname):
- # clicking on a variable name shows its binding history
- cur_value = self.current_value[varname]
- caused_by = self.caused_by[varname]
- history = list(self.binding_history.get(varname, []))
- history.reverse()
- return VariableHistoryGraphLayout(self.translator, varname, cur_value,
- caused_by, history, self.func_names)
-
-
-def nottoowide(text, width=72):
- parts = str(text).split(' ')
- lines = []
- line = parts.pop(0)
- for s in parts:
- if len(line)+len(s) < width:
- line = line + ' ' + s
- else:
- lines.append(line)
- line = s
- lines.append(line)
- return '\\n'.join(lines)
-
-
-class ClassDefLayout(GraphLayout):
- """A GraphLayout showing the attributes of a class.
- """
- def __init__(self, translator, cdef):
- self.translator = translator
- dotgen = DotGen(cdef.cls.__name__, rankdir="LR")
-
- def writecdef(cdef):
- dotgen.emit_node(nameof(cdef), color="red", shape="octagon",
- label=repr(cdef.cls))
- attrs = cdef.attrs.items()
- attrs.sort()
- for name, attrdef in attrs:
- s_value = attrdef.s_value
- dotgen.emit_node(name, shape="box", label=nottoowide(s_value))
- dotgen.emit_edge(nameof(cdef), name, label=name)
-
- prevcdef = None
- while cdef is not None:
- writecdef(cdef)
- if prevcdef:
- dotgen.emit_edge(nameof(cdef), nameof(prevcdef), color="red")
- prevcdef = cdef
- cdef = cdef.basedef
-
- GraphLayout.__init__(self, dotgen.generate(target='plain'))
-
-
-class TranslatorLayout(GraphLayout):
- """A GraphLayout showing a the call graph between functions
- as well as the class hierarchy."""
-
- def __init__(self, translator):
- self.translator = translator
- self.object_by_name = {}
- self.name_by_object = {}
- dotgen = DotGen('translator')
- dotgen.emit('mclimit=15.0')
-
- # show the call graph
- functions = translator.functions
- if translator.annotator:
- blocked_functions = translator.annotator.blocked_functions
- else:
- blocked_functions = {}
- highlight_functions = getattr(translator, 'highlight_functions', {}) # XXX
- dotgen.emit_node('entry', fillcolor="green", shape="octagon",
- label="Translator\\nEntry Point")
- 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)
- dotgen.emit_edge('entry', nameof(functions[0]), color="green")
- for f1, f2 in translator.callgraph.itervalues():
- dotgen.emit_edge(nameof(f1), nameof(f2))
-
- # show the class hierarchy
- if self.translator.annotator:
- dotgen.emit_node(nameof(None), color="red", shape="octagon",
- label="Root Class\\nobject")
- for classdef in self.translator.annotator.getuserclassdefinitions():
- data = self.labelof(classdef, classdef.cls.__name__)
- dotgen.emit_node(nameof(classdef), label=data, shape="box")
- dotgen.emit_edge(nameof(classdef.basedef), nameof(classdef))
-
- GraphLayout.__init__(self, dotgen.generate(target='plain'))
-
- # link the function names to the individual flow graphs
- for name, obj in self.object_by_name.iteritems():
- if isinstance(obj, ClassDef):
- #data = '%s.%s' % (obj.cls.__module__, obj.cls.__name__)
- data = repr(obj.cls)
- else:
- func = obj
- try:
- source = inspect.getsource(func)
- except IOError: # e.g. when func is defined interactively
- source = func.func_name
- data = '%s:%d\n%s' % (func.func_globals.get('__name__', '?'),
- func.func_code.co_firstlineno,
- source.split('\n')[0])
- self.links[name] = data
-
- def labelof(self, obj, objname):
- name = objname
- i = 1
- while name in self.object_by_name:
- i += 1
- name = '%s__%d' % (objname, i)
- self.object_by_name[name] = obj
- self.name_by_object[obj] = name
- return name
-
- def followlink(self, name):
- obj = self.object_by_name[name]
- if isinstance(obj, ClassDef):
- return ClassDefLayout(self.translator, obj)
- else:
- return FlowGraphLayout(self.translator, [obj], self.name_by_object)
-
-
-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
- try:
- return cache[obj]
- except KeyError:
- result = '%s__0x%x' % (getattr(obj, '__name__', ''), uid(obj))
- cache[obj] = result
- return result
-
-# ____________________________________________________________
-
-if __name__ == '__main__':
- from pypy.translator.translator import Translator
- from pypy.translator.test import snippet
- from pypy.translator.tool.pygame.graphdisplay import GraphDisplay
-
- t = Translator(snippet.powerset)
- #t.simplify()
- a = t.annotate([int])
- a.simplify()
- GraphDisplay(FlowGraphLayout(t)).run()
-
-## t = Translator(snippet._methodcall1)
-## t.simplify()
-## a = t.annotate([int])
-## a.simplify()
-## GraphDisplay(TranslatorLayout(t)).run()
Added: pypy/trunk/src/pypy/translator/tool/pygame/graphclient.py
==============================================================================
--- (empty file)
+++ pypy/trunk/src/pypy/translator/tool/pygame/graphclient.py Sat Dec 4 13:37:58 2004
@@ -0,0 +1,79 @@
+#! /usr/bin/env python
+"""
+Client for a graph server (either in-process or over a socket).
+"""
+
+import autopath
+from pypy.translator.tool.pygame.drawgraph import GraphLayout
+from pypy.translator.tool.graphserver import send_msg, recv_msg, MissingPage
+from pypy.tool.udir import udir
+from py.process import cmdexec
+
+
+DOT_FILE = udir.join('graph.dot')
+PLAIN_FILE = udir.join('graph.plain')
+
+
+class ClientGraphLayout(GraphLayout):
+
+ def __init__(self, connexion, key, dot, links, **ignored):
+ # generate a temporary .dot file and call dot on it
+ DOT_FILE.write(dot)
+ cmdexec('dot -Tplain %s>%s' % (str(DOT_FILE),str(PLAIN_FILE)))
+ GraphLayout.__init__(self, PLAIN_FILE)
+ self.connexion = connexion
+ self.key = key
+ self.links.update(links)
+
+ def followlink(self, name):
+ return self.connexion.download(self.key, name)
+
+ def reload(self):
+ return self.connexion.download(self.key)
+
+
+class InProcessConnexion:
+
+ def download(self, page, link=None):
+ if link is not None:
+ try:
+ page = page.content().followlink(link)
+ except KeyError:
+ page = MissingPage()
+ key = page
+ page = page.content()
+ return ClientGraphLayout(self, key, page.source, page.links)
+
+
+class SocketConnexion:
+
+ def __init__(self, s):
+ self.s = s
+
+ def download(self, key, link=None):
+ send_msg(self.s, (key, link))
+ data = recv_msg(self.s)
+ return ClientGraphLayout(self, **data)
+
+
+def get_layout(homepage):
+ return InProcessConnexion().download(homepage)
+
+def get_remote_layout(hostname, port=8888):
+ import socket
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.connect((hostname, port))
+ return SocketConnexion(s).download(0)
+
+
+if __name__ == '__main__':
+ import sys
+ if len(sys.argv) != 2 or sys.argv[1].count(':') != 1:
+ print >> sys.stderr, 'Connects to a graph server like goal/translate_pypy.'
+ print >> sys.stderr, 'Usage: %s hostname:port' % (sys.argv[0],)
+ print >> sys.stderr, ' or %s :port' % (sys.argv[0],)
+ sys.exit(2)
+ hostname, port = sys.argv[1].split(':')
+ port = int(port)
+ layout = get_remote_layout(hostname, port)
+ layout.display()
Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py
==============================================================================
--- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original)
+++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Sat Dec 4 13:37:58 2004
@@ -89,6 +89,7 @@
'/': 'search',
'n': 'find_next',
'p': 'find_prev',
+ 'r': 'reload',
'left' : ('pan', (-1, 0)),
'right' : ('pan', (1, 0)),
'up' : ('pan', (0, -1)),
@@ -114,6 +115,7 @@
Backspace Go back in history
Meta Left Go back in history
Meta Right Go forward in history
+ R Reload the page
F or / Search for text
N Find next occurrence
@@ -388,6 +390,12 @@
self.layout = self.viewer.graphlayout
self.updated_viewer()
+ def reload(self):
+ self.setstatusbar('reloading...')
+ self.redraw_now()
+ newlayout = self.layout.reload()
+ self.setlayout(newlayout)
+
def setstatusbar(self, text, fgcolor=None, bgcolor=None):
info = (text, fgcolor or self.STATUSBAR_FGCOLOR, bgcolor or self.STATUSBAR_BGCOLOR)
if info != self.statusbarinfo:
@@ -438,10 +446,13 @@
def notifyclick(self, pos):
word = self.viewer.at_position(pos)
if word in self.layout.links:
+ self.setstatusbar('loading...')
+ self.redraw_now()
newlayout = self.layout.followlink(word)
if newlayout is not None:
self.setlayout(newlayout)
return
+ self.setstatusbar('')
node = self.viewer.node_at_position(pos)
if node:
self.look_at_node(node)
@@ -539,12 +550,7 @@
bumpscale*t*(1-t))
self.viewer.setcenter(cx1*(1-t) + cx2*t, cy1*(1-t) + cy2*t)
self.updated_viewer(keep_highlight=keep_highlight)
- self.viewer.render()
- if self.statusbarinfo:
- self.drawstatusbar()
- else:
- self.status_bar_height = 0
- pygame.display.flip()
+ self.redraw_now()
return moving
def peek(self, typ):
@@ -619,7 +625,16 @@
def quit(self):
raise StopIteration
-
+
+ def redraw_now(self):
+ self.viewer.render()
+ if self.statusbarinfo:
+ self.drawstatusbar()
+ else:
+ self.status_bar_height = 0
+ pygame.display.flip()
+ self.must_redraw = False
+
def run(self):
self.dragging = self.click_origin = self.click_time = None
events = self.events = []
@@ -628,13 +643,7 @@
while True:
if self.must_redraw and not events:
- self.viewer.render()
- if self.statusbarinfo:
- self.drawstatusbar()
- else:
- self.status_bar_height = 0
- pygame.display.flip()
- self.must_redraw = False
+ self.redraw_now()
if not events:
events.append(pygame.event.wait())
Modified: pypy/trunk/src/pypy/translator/translator.py
==============================================================================
--- pypy/trunk/src/pypy/translator/translator.py (original)
+++ pypy/trunk/src/pypy/translator/translator.py Sat Dec 4 13:37:58 2004
@@ -108,8 +108,8 @@
def view(self, *functions):
"""Shows the control flow graph with annotations if computed.
Requires 'dot' and pygame."""
- from pypy.translator.tool.pygame.flowviewer import FlowGraphLayout
- FlowGraphLayout(self).display()
+ from pypy.translator.tool.graphpage import FlowGraphPage
+ FlowGraphPage(self).display()
def simplify(self, func=None):
"""Simplifies the control flow graph (default: for all functions)."""
More information about the Pypy-commit
mailing list