OLD | NEW |
---|---|
1 #! /usr/bin/python | 1 #! /usr/bin/python |
2 # | 2 # |
3 # Copyright 2016 the V8 project authors. All rights reserved. | 3 # Copyright 2016 the V8 project authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 # | 6 # |
7 | 7 |
8 import argparse | 8 import argparse |
9 import heapq | 9 import heapq |
10 import json | 10 import json |
11 from matplotlib import colors | 11 from matplotlib import colors |
12 from matplotlib import pyplot | 12 from matplotlib import pyplot |
13 import numpy | 13 import numpy |
14 import struct | 14 import struct |
15 import sys | |
15 | 16 |
16 | 17 |
17 __DESCRIPTION = """ | 18 __DESCRIPTION = """ |
18 Process v8.ignition_dispatches_counters.json and list top counters, | 19 Process v8.ignition_dispatches_counters.json and list top counters, |
19 or plot a dispatch heatmap. | 20 or plot a dispatch heatmap. |
20 | 21 |
21 Please note that those handlers that may not or will never dispatch | 22 Please note that those handlers that may not or will never dispatch |
22 (e.g. Return or Throw) do not show up in the results. | 23 (e.g. Return or Throw) do not show up in the results. |
23 """ | 24 """ |
24 | 25 |
(...skipping 18 matching lines...) Expand all Loading... | |
43 | 44 |
44 # Display the top 5 sources and destinations of dispatches to/from LdaZero | 45 # Display the top 5 sources and destinations of dispatches to/from LdaZero |
45 $ tools/ignition/bytecode_dispatches_report.py -f LdaZero -n 5 | 46 $ tools/ignition/bytecode_dispatches_report.py -f LdaZero -n 5 |
46 """ | 47 """ |
47 | 48 |
48 __COUNTER_BITS = struct.calcsize("P") * 8 # Size in bits of a pointer | 49 __COUNTER_BITS = struct.calcsize("P") * 8 # Size in bits of a pointer |
49 __COUNTER_MAX = 2**__COUNTER_BITS - 1 | 50 __COUNTER_MAX = 2**__COUNTER_BITS - 1 |
50 | 51 |
51 | 52 |
52 def warn_if_counter_may_have_saturated(dispatches_table): | 53 def warn_if_counter_may_have_saturated(dispatches_table): |
53 for source, counters_from_source in dispatches_table.items(): | 54 for source, counters_from_source in iteritems(dispatches_table): |
54 for destination, counter in counters_from_source.items(): | 55 for destination, counter in iteritems(counters_from_source): |
55 if counter == __COUNTER_MAX: | 56 if counter == __COUNTER_MAX: |
56 print "WARNING: {} -> {} may have saturated.".format(source, | 57 print "WARNING: {} -> {} may have saturated.".format(source, |
57 destination) | 58 destination) |
58 | 59 |
59 | 60 |
60 def find_top_bytecode_dispatch_pairs(dispatches_table, top_count): | 61 def find_top_bytecode_dispatch_pairs(dispatches_table, top_count): |
61 def flattened_counters_generator(): | 62 def flattened_counters_generator(): |
62 for source, counters_from_source in dispatches_table.items(): | 63 for source, counters_from_source in iteritems(dispatches_table): |
63 for destination, counter in counters_from_source.items(): | 64 for destination, counter in iteritems(counters_from_source): |
64 yield source, destination, counter | 65 yield source, destination, counter |
65 | 66 |
66 return heapq.nlargest(top_count, flattened_counters_generator(), | 67 return heapq.nlargest(top_count, flattened_counters_generator(), |
67 key=lambda x: x[2]) | 68 key=lambda x: x[2]) |
68 | 69 |
69 | 70 |
70 def print_top_bytecode_dispatch_pairs(dispatches_table, top_count): | 71 def print_top_bytecode_dispatch_pairs(dispatches_table, top_count): |
71 top_bytecode_dispatch_pairs = ( | 72 top_bytecode_dispatch_pairs = ( |
72 find_top_bytecode_dispatch_pairs(dispatches_table, top_count)) | 73 find_top_bytecode_dispatch_pairs(dispatches_table, top_count)) |
73 print "Top {} bytecode dispatch pairs:".format(top_count) | 74 print "Top {} bytecode dispatch pairs:".format(top_count) |
74 for source, destination, counter in top_bytecode_dispatch_pairs: | 75 for source, destination, counter in top_bytecode_dispatch_pairs: |
75 print "{:>12d}\t{} -> {}".format(counter, source, destination) | 76 print "{:>12d}\t{} -> {}".format(counter, source, destination) |
76 | 77 |
77 | 78 |
78 def find_top_bytecodes(dispatches_table): | 79 def find_top_bytecodes(dispatches_table): |
79 top_bytecodes = [] | 80 top_bytecodes = [] |
80 for bytecode, counters_from_bytecode in dispatches_table.items(): | 81 for bytecode, counters_from_bytecode in iteritems(dispatches_table): |
81 top_bytecodes.append((bytecode, sum(counters_from_bytecode.values()))) | 82 top_bytecodes.append((bytecode, sum(itervalues(counters_from_bytecode)))) |
83 | |
82 top_bytecodes.sort(key=lambda x: x[1], reverse=True) | 84 top_bytecodes.sort(key=lambda x: x[1], reverse=True) |
83 return top_bytecodes | 85 return top_bytecodes |
84 | 86 |
85 | 87 |
86 def print_top_bytecodes(dispatches_table): | 88 def print_top_bytecodes(dispatches_table): |
87 top_bytecodes = find_top_bytecodes(dispatches_table) | 89 top_bytecodes = find_top_bytecodes(dispatches_table) |
88 print "Top bytecodes:" | 90 print "Top bytecodes:" |
89 for bytecode, counter in top_bytecodes: | 91 for bytecode, counter in top_bytecodes: |
90 print "{:>12d}\t{}".format(counter, bytecode) | 92 print "{:>12d}\t{}".format(counter, bytecode) |
91 | 93 |
92 | 94 |
93 def find_top_dispatch_sources(dispatches_table, destination, top_count): | 95 def find_top_dispatch_sources(dispatches_table, bytecode, top_count, |
rmcilroy
2016/07/19 11:33:15
update name (find_top_dispatch_sources_and_destina
klaasb
2016/07/19 13:52:28
Done.
| |
96 sort_source_relative): | |
97 relative_table = {} | |
98 for source, destinations in iteritems(dispatches_table): | |
99 total = float(sum(itervalues(destinations))) | |
100 relative_destinations = {} | |
101 relative_table[source] = relative_destinations | |
102 for destination, count in iteritems(destinations): | |
103 relative_destinations[destination] = (count, count / total) | |
104 | |
94 def source_counters_generator(): | 105 def source_counters_generator(): |
95 for source, table_row in dispatches_table.items(): | 106 for source, table_row in iteritems(relative_table): |
rmcilroy
2016/07/19 11:33:15
It seems a bit strange to have an inner function p
klaasb
2016/07/19 13:52:28
Done.
| |
96 if destination in table_row: | 107 if bytecode in table_row: |
97 yield source, table_row[destination] | 108 yield source, table_row[bytecode] |
98 | 109 |
99 return heapq.nlargest(top_count, source_counters_generator(), | 110 return (heapq.nlargest(top_count, source_counters_generator(), |
100 key=lambda x: x[1]) | 111 key=lambda x: x[1][1 if sort_source_relative else 0]), |
112 heapq.nlargest(top_count, iteritems(relative_table[bytecode]), | |
113 key=lambda x: x[1][0])) | |
101 | 114 |
102 | 115 |
103 def print_top_dispatch_sources_and_destinations(dispatches_table, bytecode, | 116 def print_top_dispatch_sources_and_destinations(dispatches_table, bytecode, |
104 top_count): | 117 top_count, sort_relative): |
105 top_sources = find_top_dispatch_sources(dispatches_table, bytecode, top_count) | 118 top_sources, top_destinations = find_top_dispatch_sources( |
106 top_destinations = heapq.nlargest(top_count, | 119 dispatches_table, bytecode, top_count, sort_relative) |
107 dispatches_table[bytecode].items(), | |
108 key=lambda x: x[1]) | |
109 | |
110 print "Top sources of dispatches to {}:".format(bytecode) | 120 print "Top sources of dispatches to {}:".format(bytecode) |
111 for source_name, counter in top_sources: | 121 for source_name, (counter, ratio) in top_sources: |
112 print "{:>12d}\t{}".format(counter, source_name) | 122 print "{:>12d}\t{:>5.1f}%\t{}".format(counter, ratio * 100, source_name) |
113 | 123 |
114 print "\nTop destinations of dispatches from {}:".format(bytecode) | 124 print "\nTop destinations of dispatches from {}:".format(bytecode) |
115 for destination_name, counter in top_destinations: | 125 for destination_name, (counter, ratio) in top_destinations: |
116 print "{:>12d}\t{}".format(counter, destination_name) | 126 print "{:>12d}\t{:>5.1f}%\t{}".format(counter, ratio * 100, destination_name ) |
117 | 127 |
118 | 128 |
119 def build_counters_matrix(dispatches_table): | 129 def build_counters_matrix(dispatches_table): |
120 labels = sorted(dispatches_table.keys()) | 130 labels = sorted(dispatches_table.keys()) |
121 | 131 |
122 counters_matrix = numpy.empty([len(labels), len(labels)], dtype=int) | 132 counters_matrix = numpy.empty([len(labels), len(labels)], dtype=int) |
123 for from_index, from_name in enumerate(labels): | 133 for from_index, from_name in enumerate(labels): |
124 current_row = dispatches_table[from_name]; | 134 current_row = dispatches_table[from_name]; |
125 for to_index, to_name in enumerate(labels): | 135 for to_index, to_name in enumerate(labels): |
126 counters_matrix[from_index, to_index] = current_row.get(to_name, 0) | 136 counters_matrix[from_index, to_index] = current_row.get(to_name, 0) |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
208 help="print top dispatch sources and destinations to the specified bytecode" | 218 help="print top dispatch sources and destinations to the specified bytecode" |
209 ) | 219 ) |
210 command_line_parser.add_argument( | 220 command_line_parser.add_argument( |
211 "--output-filename", "-o", | 221 "--output-filename", "-o", |
212 metavar="<output filename>", | 222 metavar="<output filename>", |
213 default="v8.ignition_dispatches_table.svg", | 223 default="v8.ignition_dispatches_table.svg", |
214 help=("file to save the plot file to. File type is deduced from the " | 224 help=("file to save the plot file to. File type is deduced from the " |
215 "extension. PDF, SVG, PNG supported") | 225 "extension. PDF, SVG, PNG supported") |
216 ) | 226 ) |
217 command_line_parser.add_argument( | 227 command_line_parser.add_argument( |
228 "--sort-sources-relative", "-r", | |
229 action="store_true", | |
230 help=("print top sources in order to how often they dispatch to the " | |
231 "specified bytecode, only applied when using -f") | |
232 ) | |
233 command_line_parser.add_argument( | |
218 "input_filename", | 234 "input_filename", |
219 metavar="<input filename>", | 235 metavar="<input filename>", |
220 default="v8.ignition_dispatches_table.json", | 236 default="v8.ignition_dispatches_table.json", |
221 nargs='?', | 237 nargs='?', |
222 help="Ignition counters JSON file" | 238 help="Ignition counters JSON file" |
223 ) | 239 ) |
224 | 240 |
225 return command_line_parser.parse_args() | 241 return command_line_parser.parse_args() |
226 | 242 |
227 | 243 |
244 def itervalues(d): | |
245 return d.values() if sys.version_info[0] > 2 else d.itervalues() | |
246 | |
247 | |
248 def iteritems(d): | |
249 return d.items() if sys.version_info[0] > 2 else d.iteritems() | |
250 | |
251 | |
228 def main(): | 252 def main(): |
229 program_options = parse_command_line() | 253 program_options = parse_command_line() |
230 | 254 |
231 with open(program_options.input_filename) as stream: | 255 with open(program_options.input_filename) as stream: |
232 dispatches_table = json.load(stream) | 256 dispatches_table = json.load(stream) |
233 | 257 |
234 warn_if_counter_may_have_saturated(dispatches_table) | 258 warn_if_counter_may_have_saturated(dispatches_table) |
235 | 259 |
236 if program_options.plot: | 260 if program_options.plot: |
237 figure, axis = pyplot.subplots() | 261 figure, axis = pyplot.subplots() |
238 plot_dispatches_table(dispatches_table, figure, axis) | 262 plot_dispatches_table(dispatches_table, figure, axis) |
239 | 263 |
240 if program_options.interactive: | 264 if program_options.interactive: |
241 pyplot.show() | 265 pyplot.show() |
242 else: | 266 else: |
243 figure.set_size_inches(program_options.plot_size, | 267 figure.set_size_inches(program_options.plot_size, |
244 program_options.plot_size) | 268 program_options.plot_size) |
245 pyplot.savefig(program_options.output_filename) | 269 pyplot.savefig(program_options.output_filename) |
246 elif program_options.top_bytecode_dispatch_pairs: | 270 elif program_options.top_bytecode_dispatch_pairs: |
247 print_top_bytecode_dispatch_pairs( | 271 print_top_bytecode_dispatch_pairs( |
248 dispatches_table, program_options.top_entries_count) | 272 dispatches_table, program_options.top_entries_count) |
249 elif program_options.top_dispatches_for_bytecode: | 273 elif program_options.top_dispatches_for_bytecode: |
250 print_top_dispatch_sources_and_destinations( | 274 print_top_dispatch_sources_and_destinations( |
251 dispatches_table, program_options.top_dispatches_for_bytecode, | 275 dispatches_table, program_options.top_dispatches_for_bytecode, |
252 program_options.top_entries_count) | 276 program_options.top_entries_count, program_options.sort_sources_relative) |
253 else: | 277 else: |
254 print_top_bytecodes(dispatches_table) | 278 print_top_bytecodes(dispatches_table) |
255 | 279 |
256 | 280 |
257 if __name__ == "__main__": | 281 if __name__ == "__main__": |
258 main() | 282 main() |
OLD | NEW |