Chromium Code Reviews| 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 |