File: graphpage.py

package info (click to toggle)
pypy 5.6.0%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 97,040 kB
  • ctags: 185,069
  • sloc: python: 1,147,862; ansic: 49,642; cpp: 5,245; asm: 5,169; makefile: 529; sh: 481; xml: 232; lisp: 45
file content (219 lines) | stat: -rw-r--r-- 8,841 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219

from rpython.translator.tool.graphpage import GraphPage
from rpython.translator.tool.make_dot import DotGen
from rpython.jit.metainterp.resoperation import rop

class SubGraph:
    def __init__(self, op):
        self.failargs = op.getfailargs()
        self.subinputargs = op.getdescr()._debug_subinputargs
        self.suboperations = op.getdescr()._debug_suboperations
    def get_operations(self):
        return self.suboperations
    def get_display_text(self, memo):
        # copy the display of variables in this subgraph (a bridge)
        # so that they match variables in the parent graph across the
        # guard failure
        for failarg, inputarg in zip(self.failargs, self.subinputargs):
            try:
                memo[inputarg] = memo[failarg]
            except KeyError:
                pass
        return None

def display_procedures(procedures, errmsg=None, highlight_procedures={}, metainterp_sd=None):
    graphs = [(procedure, highlight_procedures.get(procedure, 0))
              for procedure in procedures]
    for graph, highlight in graphs:
        for op in graph.get_operations():
            if is_interesting_guard(op):
                graphs.append((SubGraph(op), highlight))
    graphpage = ResOpGraphPage(graphs, errmsg, metainterp_sd)
    graphpage.display()

def is_interesting_guard(op):
    return hasattr(op.getdescr(), '_debug_suboperations')

def getdescr(op):
    if op._descr is not None:
        return op._descr
    if hasattr(op, '_descr_wref'):
        return op._descr_wref()
    return None


class ResOpGraphPage(GraphPage):

    def compute(self, graphs, errmsg=None, metainterp_sd=None):
        resopgen = ResOpGen(metainterp_sd)
        for graph, highlight in graphs:
            resopgen.add_graph(graph, highlight)
        if errmsg:
            resopgen.set_errmsg(errmsg)
        self.source = resopgen.getsource()
        self.links = resopgen.getlinks()


class ResOpGen(object):
    CLUSTERING = True
    BOX_COLOR = (128, 0, 96)

    def __init__(self, metainterp_sd=None):
        self.graphs = []
        self.highlight_graphs = {}
        self.block_starters = {}    # {graphindex: {set-of-operation-indices}}
        self.all_operations = {}
        self.errmsg = None
        self.target_tokens = {}
        self.metainterp_sd = metainterp_sd
        self.memo = {}

    def op_name(self, graphindex, opindex):
        return 'g%dop%d' % (graphindex, opindex)

    def mark_starter(self, graphindex, opindex):
        self.block_starters[graphindex][opindex] = True

    def add_graph(self, graph, highlight=False):
        graphindex = len(self.graphs)
        self.graphs.append(graph)
        self.highlight_graphs[graph] = highlight
        for i, op in enumerate(graph.get_operations()):
            self.all_operations[op] = graphindex, i

    def find_starters(self):
        for graphindex in range(len(self.graphs)):
            self.block_starters[graphindex] = {0: True}
        for graphindex, graph in enumerate(self.graphs):
            mergepointblock = None
            for i, op in enumerate(graph.get_operations()):
                if is_interesting_guard(op):
                    self.mark_starter(graphindex, i+1)
                if op.getopnum() == rop.DEBUG_MERGE_POINT:
                    if mergepointblock is None:
                        mergepointblock = i
                elif op.getopnum() == rop.LABEL:
                    self.mark_starter(graphindex, i)
                    self.target_tokens[getdescr(op)] = (graphindex, i)
                    mergepointblock = i
                else:
                    if mergepointblock is not None:
                        self.mark_starter(graphindex, mergepointblock)
                        mergepointblock = None

    def set_errmsg(self, errmsg):
        self.errmsg = errmsg

    def getsource(self):
        self.find_starters()
        self.pendingedges = []
        self.dotgen = DotGen('resop')
        self.dotgen.emit('clusterrank="local"')
        self.generrmsg()
        for i, graph in enumerate(self.graphs):
            self.gengraph(graph, i)
        # we generate the edges at the end of the file; otherwise, and edge
        # could mention a node before it's declared, and this can cause the
        # node declaration to occur too early -- in the wrong subgraph.
        for frm, to, kwds in self.pendingedges:
            self.dotgen.emit_edge(frm, to, **kwds)
        return self.dotgen.generate(target=None)

    def generrmsg(self):
        if self.errmsg:
            self.dotgen.emit_node('errmsg', label=self.errmsg,
                                  shape="box", fillcolor="red")
            if self.graphs and self.block_starters[0]:
                opindex = max(self.block_starters[0])
                blockname = self.op_name(0, opindex)
                self.pendingedges.append((blockname, 'errmsg', {}))

    def getgraphname(self, graphindex):
        return 'graph%d' % graphindex

    def gengraph(self, graph, graphindex):
        graphname = self.getgraphname(graphindex)
        if self.CLUSTERING:
            self.dotgen.emit('subgraph cluster%d {' % graphindex)
        label = graph.get_display_text(self.memo)
        if label is not None:
            colorindex = self.highlight_graphs.get(graph, 0)
            if colorindex == 1:
                fillcolor = '#f084c2'    # highlighted graph
            elif colorindex == 2:
                fillcolor = '#808080'    # invalidated graph
            else:
                fillcolor = '#84f0c2'    # normal color
            self.dotgen.emit_node(graphname, shape="octagon",
                                  label=label, fillcolor=fillcolor)
            self.pendingedges.append((graphname,
                                      self.op_name(graphindex, 0),
                                      {}))
        operations = graph.get_operations()
        for opindex in self.block_starters[graphindex]:
            self.genblock(operations, graphindex, opindex)
        if self.CLUSTERING:
            self.dotgen.emit('}')   # closes the subgraph

    def genedge(self, frm, to, **kwds):
        self.pendingedges.append((self.op_name(*frm),
                                  self.op_name(*to),
                                  kwds))

    def genblock(self, operations, graphindex, opstartindex):
        if opstartindex >= len(operations):
            return
        blockname = self.op_name(graphindex, opstartindex)
        block_starters = self.block_starters[graphindex]
        lines = []
        opindex = opstartindex
        while True:
            op = operations[opindex]
            op_repr = op.repr(self.memo, graytext=True)
            if (op.getopnum() == rop.DEBUG_MERGE_POINT and
                    self.metainterp_sd is not None):
                jd_sd = self.metainterp_sd.jitdrivers_sd[op.getarg(0).getint()]
                if jd_sd._get_printable_location_ptr:
                    s = jd_sd.warmstate.get_location_str(op.getarglist()[3:])
                    s = s.replace(',', '.') # we use comma for argument splitting
                    op_repr = "debug_merge_point(%d, %d, '%s')" % (op.getarg(1).getint(), op.getarg(2).getint(), s)
            lines.append(op_repr)
            if is_interesting_guard(op):
                tgt = op.getdescr()._debug_suboperations[0]
                tgt_g, tgt_i = self.all_operations[tgt]
                self.genedge((graphindex, opstartindex),
                             (tgt_g, tgt_i),
                             color='red')
            opindex += 1
            if opindex >= len(operations):
                break
            if opindex in block_starters:
                self.genedge((graphindex, opstartindex),
                             (graphindex, opindex))
                break
        if op.getopnum() == rop.JUMP:
            tgt_descr = getdescr(op)
            if tgt_descr is not None and tgt_descr in self.target_tokens:
                self.genedge((graphindex, opstartindex),
                             self.target_tokens[tgt_descr],
                             weight="0")
        lines.append("")
        label = "\\l".join(lines)
        kwds = {}
        #if op in self.highlightops:
        #    kwds['color'] = 'red'
        #    kwds['fillcolor'] = '#ffe8e8'
        self.dotgen.emit_node(blockname, shape="box", label=label, **kwds)

    def getlinks(self):
        boxes = {}
        for op in self.all_operations:
            args = op.getarglist() + [op]
            for box in args:
                s = box.repr_short(self.memo)
                if len(s) > 1 and s[0] in 'irf' and s[1:].isdigit():
                    boxes[box] = s
        links = {}
        for box, s in boxes.items():
            links.setdefault(s, (box.repr(self.memo), self.BOX_COLOR))
        return links