-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvisualize_callchains.py
More file actions
145 lines (124 loc) · 4.29 KB
/
visualize_callchains.py
File metadata and controls
145 lines (124 loc) · 4.29 KB
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
import json
import re
import networkx as nx
import plotly.graph_objects as go
from collections import deque, defaultdict
def convert_method_name(method: str) -> str:
return re.sub(r'\.(\w+)\[(\w+)\]', lambda m: f'.{m.group(2)}_{m.group(1)}', method)
def compute_top_down_positions(G):
levels = defaultdict(list)
indegree = {node: 0 for node in G.nodes()}
for u, v in G.edges():
indegree[v] += 1
queue = deque()
for node, deg in indegree.items():
if deg == 0:
queue.append((node, 0))
visited = set()
while queue:
node, level = queue.popleft()
if node in visited:
continue
visited.add(node)
levels[level].append(node)
for neighbor in G.successors(node):
queue.append((neighbor, level + 1.8))
pos = {}
max_width = max(len(nodes) for nodes in levels.values())
for level, nodes in levels.items():
count = len(nodes)
spacing = 1.0 / (count + 1)
for i, node in enumerate(nodes):
x = (i + 1) * spacing
y = -level * 0.5
if i % 2 == 1:
y -= 0.15
pos[node] = (x, y)
return pos
def create_figure(G, pos, title_text, filename):
edge_x = []
edge_y = []
for edge in G.edges():
x0, y0 = pos[edge[0]]
x1, y1 = pos[edge[1]]
edge_x += [x0, x1, None]
edge_y += [y0, y1, None]
edge_trace = go.Scatter(
x=edge_x, y=edge_y,
line=dict(width=1.2, color='#888'),
hoverinfo='text',
mode='lines')
node_x = []
node_y = []
node_text = []
for node in G.nodes():
x, y = pos[node]
node_x.append(x)
node_y.append(y)
node_text.append(node)
node_trace = go.Scatter(
x=node_x, y=node_y,
mode='markers+text',
text=node_text,
textposition="top center",
hoverinfo='text',
marker=dict(
showscale=False,
color='lightblue',
size=20,
line_width=2))
fig = go.Figure(data=[edge_trace, node_trace],
layout=go.Layout(
title=dict(text=title_text, font=dict(size=20)),
showlegend=False,
hovermode='closest',
margin=dict(b=20, l=5, r=5, t=40),
xaxis=dict(showgrid=False, zeroline=False),
yaxis=dict(showgrid=False, zeroline=False)
))
fig.write_html(filename)
with open("callchains.json") as f:
callchains = json.load(f)
G = nx.DiGraph()
for test_name, chains in callchains.items():
for chain in chains:
src = test_name
dst = chain[0]
G.add_edge(src, dst, test=test_name)
for i in range(len(chain) - 1):
G.add_edge(chain[i], chain[i + 1], test=test_name)
pos = compute_top_down_positions(G)
create_figure(G, pos, "Call chains", "html/callchains.html")
for test_name, chains in callchains.items():
G_test = nx.DiGraph()
for chain in chains:
src = test_name
dst = chain[0]
G_test.add_edge(src, dst, test=test_name)
for i in range(len(chain) - 1):
G_test.add_edge(chain[i], chain[i + 1], test=test_name)
pos_test = compute_top_down_positions(G_test)
filename = f"html/tests/{test_name}_call_chain.html"
create_figure(G_test, pos_test, f"{test_name} call chain", filename)
all_methods = set()
for chains in callchains.values():
for chain in chains:
all_methods.update(chain)
for method in all_methods:
relevant_chains = []
for test_name, chains in callchains.items():
for chain in chains:
if method in chain:
relevant_chains.append((test_name, chain))
G_method = nx.DiGraph()
for test_name, chain in relevant_chains:
if not chain:
continue
G_method.add_edge(test_name, chain[0], test=test_name)
for i in range(len(chain) - 1):
G_method.add_edge(chain[i], chain[i + 1], test=test_name)
if len(G_method) == 0:
continue
pos_method = compute_top_down_positions(G_method)
filename = f"html/methods/{convert_method_name(method)}_call_chain.html"
create_figure(G_method, pos_method, f"{convert_method_name(method)} call chain", filename)