OLD | NEW |
| (Empty) |
1 # Copyright 2016 The Chromium Authors. All rights reserved. | |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 """Utilities for displaying a ResourceSack. | |
6 | |
7 When run standalone, takes traces on the command line and produces a dot file to | |
8 stdout. | |
9 """ | |
10 | |
11 | |
12 def ToDot(sack, output, prune=-1, long_edge_msec=2000): | |
13 """Output as a dot file. | |
14 | |
15 Args: | |
16 sack: (ResourceSack) the sack to convert to dot. | |
17 output: a file-like output stream. | |
18 prune: if positive, prune & coalesce nodes under the specified threshold | |
19 of repeated views, as fraction node views / total graphs. All pruned | |
20 nodes are represented by a single node, and an edge is connected only if | |
21 the view count is greater than 1. | |
22 long_edge_msec: if positive, the definition of a long edge. Long edges are | |
23 distinguished in graph. | |
24 """ | |
25 output.write("""digraph dependencies { | |
26 rankdir = LR; | |
27 """) | |
28 | |
29 pruned = set() | |
30 num_graphs = len(sack.graph_info) | |
31 for bag in sack.bags: | |
32 if prune > 0 and float(len(bag.graphs)) / num_graphs < prune: | |
33 pruned.add(bag) | |
34 continue | |
35 output.write('%d [label="%s (%d)\n(%d, %d)\n(%.2f, %.2f)" shape=%s; ' | |
36 'style=filled; fillcolor=%s];\n' % ( | |
37 bag.Index(), bag.label, len(bag.graphs), | |
38 min(bag.total_costs), max(bag.total_costs), | |
39 min(bag.relative_costs), max(bag.relative_costs), | |
40 _CriticalToShape(bag), | |
41 _AmountToNodeColor(len(bag.graphs), num_graphs))) | |
42 | |
43 if pruned: | |
44 pruned_index = num_graphs | |
45 output.write('%d [label="Pruned at %.0f%%\n(%d)"; ' | |
46 'shape=polygon; style=dotted];\n' % | |
47 (pruned_index, 100 * prune, len(pruned))) | |
48 | |
49 for bag in sack.bags: | |
50 if bag in pruned: | |
51 for succ in bag.Successors(): | |
52 if succ not in pruned: | |
53 output.write('%d -> %d [style=dashed];\n' % ( | |
54 pruned_index, succ.Index())) | |
55 for succ in bag.Successors(): | |
56 if succ in pruned: | |
57 if len(bag.successor_sources[succ]) > 1: | |
58 output.write('%d -> %d [label="%d"; style=dashed];\n' % ( | |
59 bag.Index(), pruned_index, len(bag.successor_sources[succ]))) | |
60 else: | |
61 num_succ = len(bag.successor_sources[succ]) | |
62 num_long = 0 | |
63 for graph, source, target in bag.successor_sources[succ]: | |
64 if graph.EdgeCost(source, target) > long_edge_msec: | |
65 num_long += 1 | |
66 if num_long > 0: | |
67 long_frac = float(num_long) / num_succ | |
68 long_edge_style = '; penwidth=%f' % (2 + 6.0 * long_frac) | |
69 if long_frac < 0.75: | |
70 long_edge_style += '; style=dashed' | |
71 else: | |
72 long_edge_style = '' | |
73 min_edge = min(bag.successor_edge_costs[succ]) | |
74 max_edge = max(bag.successor_edge_costs[succ]) | |
75 output.write('%d -> %d [label="%d\n(%f,%f)"; color=%s %s];\n' % ( | |
76 bag.Index(), succ.Index(), num_succ, min_edge, max_edge, | |
77 _AmountToEdgeColor(num_succ, len(bag.graphs)), | |
78 long_edge_style)) | |
79 | |
80 output.write('}') | |
81 | |
82 | |
83 def _CriticalToShape(bag): | |
84 frac = float(bag.num_critical) / bag.num_nodes | |
85 if frac < 0.4: | |
86 return 'oval' | |
87 elif frac < 0.7: | |
88 return 'polygon' | |
89 elif frac < 0.9: | |
90 return 'trapezium' | |
91 return 'box' | |
92 | |
93 | |
94 def _AmountToNodeColor(numer, denom): | |
95 if denom <= 0: | |
96 return 'grey72' | |
97 ratio = 1.0 * numer / denom | |
98 if ratio < .3: | |
99 return 'white' | |
100 elif ratio < .6: | |
101 return 'yellow' | |
102 elif ratio < .8: | |
103 return 'orange' | |
104 return 'green' | |
105 | |
106 | |
107 def _AmountToEdgeColor(numer, denom): | |
108 color = _AmountToNodeColor(numer, denom) | |
109 if color == 'white' or color == 'grey72': | |
110 return 'black' | |
111 return color | |
112 | |
113 | |
114 def _Main(): | |
115 import json | |
116 import logging | |
117 import sys | |
118 | |
119 import loading_model | |
120 import loading_trace | |
121 import resource_sack | |
122 | |
123 sack = resource_sack.GraphSack() | |
124 for fname in sys.argv[1:]: | |
125 trace = loading_trace.LoadingTrace.FromJsonDict( | |
126 json.load(open(fname))) | |
127 logging.info('Making graph from %s', fname) | |
128 model = loading_model.ResourceGraph(trace, content_lens=None) | |
129 sack.ConsumeGraph(model) | |
130 logging.info('Finished %s', fname) | |
131 ToDot(sack, sys.stdout, prune=.1) | |
132 | |
133 | |
134 if __name__ == '__main__': | |
135 _Main() | |
OLD | NEW |