Chromium Code Reviews| Index: tools/ignition/bytecode_dispatches_report.py |
| diff --git a/tools/ignition/bytecode_dispatches_report.py b/tools/ignition/bytecode_dispatches_report.py |
| new file mode 100755 |
| index 0000000000000000000000000000000000000000..7a8ebf856afddb1afffc9e471373b7beb08856aa |
| --- /dev/null |
| +++ b/tools/ignition/bytecode_dispatches_report.py |
| @@ -0,0 +1,188 @@ |
| +#! /usr/bin/python |
| +# |
| +# Copyright 2016 the V8 project authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| +# |
| + |
| +import argparse |
| +import heapq |
| +import json |
| +from matplotlib import colors |
| +from matplotlib import pyplot |
| +import numpy |
| +import struct |
| + |
| + |
| +__DESCRIPTION = """ |
| +Process v8.ignition_dispatches_counters.json and list top counters, |
| +or plot a dispatch heatmap. |
| +""" |
| + |
| + |
| +__HELP_EPILOGUE = """ |
| +examples: |
| + # Print the top 10 counters (default mode), reading from default |
| + # filename v8.ignition_dispatches_counters.json |
| + $ tools/ignition/bytecode_dispatches_report.py |
| + |
| + # Print the top 15 counters reading from data.json |
| + $ tools/ignition/bytecode_dispatches_report.py -t 15 data.json |
| + |
| + # Do not print the top counters and save to default filename |
| + # v8.ignition_dispatches_counters.svg |
| + $ tools/ignition/bytecode_dispatches_report.py -t 0 -p -o data.svg |
|
rmcilroy
2016/04/12 14:08:51
Please update this example if you take the comment
Stefano Sanfilippo
2016/04/12 14:26:26
Done.
|
| + |
| + # Print the top 10 counters and save a heatmap to data.svg |
| + $ tools/ignition/bytecode_dispatches_report.py -p -o data.svg |
| + |
| + # Open the heatmap in an interactive viewer |
| + $ tools/ignition/bytecode_dispatches_report.py -p -i |
| +""" |
| + |
| +__COUNTER_BITS = struct.calcsize("P") * 8 # Size in bits of a pointer |
| + |
| + |
| +__COUNTER_MAX = 2**__COUNTER_BITS - 1 |
|
rmcilroy
2016/04/12 14:08:51
nit - remove newlines between __COUNTER_BITS and _
Stefano Sanfilippo
2016/04/12 14:26:26
Done.
|
| + |
| + |
| +def warn_if_counter_may_have_saturated(dispatches_table): |
| + for source, counters_from_source in dispatches_table.items(): |
| + for destination, counter in counters_from_source.items(): |
| + if counter == __COUNTER_MAX: |
| + print "WARNING: {} -> {} may have saturated.".format(source, |
| + destination) |
| + |
| + |
| +def print_top_counters(dispatches_table, top_number): |
| + flattened_counters = {} |
| + for source, counters_from_source in dispatches_table.items(): |
| + for destination, counter in counters_from_source.items(): |
| + flattened_counters[source, destination] = counter |
| + |
| + top_counters = heapq.nlargest(top_number, flattened_counters.items(), |
| + key=lambda x: x[1]) |
| + |
| + print "Top {} dispatch counters:".format(top_number) |
| + for source_destination_pair, counter in top_counters: |
| + print "{:>12d}\t{}".format(counter, " -> ".join(source_destination_pair)) |
| + |
| + |
| +def plot_dispatches_table(dispatches_table, figure, axis): |
| + labels = sorted(dispatches_table.keys()) |
| + |
| + counters_matrix = numpy.empty([len(labels), len(labels)], dtype=int) |
| + for from_index, from_name in enumerate(labels): |
| + current_row = dispatches_table[from_name]; |
| + for to_index, to_name in enumerate(labels): |
| + counters_matrix[from_index, to_index] = current_row.get(to_name, 0) |
| + |
| + # Reverse y axis for a nicer appeareance |
|
rmcilroy
2016/04/12 14:08:51
appearance
Stefano Sanfilippo
2016/04/12 14:26:26
Done.
|
| + xlabels = labels |
| + ylabels = list(reversed(xlabels)) |
| + counters_matrix = numpy.flipud(counters_matrix) |
| + |
| + image = axis.pcolor( |
| + counters_matrix, |
| + cmap='jet', |
| + norm=colors.LogNorm(), |
| + edgecolor='grey', |
| + linestyle='dotted', |
| + linewidth=0.5 |
| + ) |
| + |
| + axis.xaxis.set( |
| + ticks=numpy.arange(0.5, len(xlabels)), |
| + label="From bytecode handler" |
| + ) |
| + axis.xaxis.tick_top() |
| + axis.set_xlim(0, len(xlabels)) |
| + axis.set_xticklabels(xlabels, rotation='vertical') |
| + |
| + axis.yaxis.set( |
| + ticks=numpy.arange(0.5, len(ylabels)), |
| + label="To bytecode handler", |
| + ticklabels=ylabels |
| + ) |
| + axis.set_ylim(0, len(ylabels)) |
| + |
| + figure.colorbar( |
| + image, |
| + ax=axis, |
| + fraction=0.01, |
| + pad=0.01 |
| + ) |
| + |
| + |
| +def parse_command_line(): |
| + command_line_parser = argparse.ArgumentParser( |
| + formatter_class=argparse.RawDescriptionHelpFormatter, |
| + description=__DESCRIPTION, |
| + epilog=__HELP_EPILOGUE |
| + ) |
| + command_line_parser.add_argument( |
| + "--plot_size", "-s", |
| + metavar="N", |
| + default=30, |
| + help="shorter side, in inches, of the output plot (default 30)" |
| + ) |
| + command_line_parser.add_argument( |
| + "--plot", "-p", |
| + action="store_true", |
| + help="plot dispatches table heatmap" |
| + ) |
| + command_line_parser.add_argument( |
| + "--interactive", "-i", |
| + action="store_true", |
| + help="open an interactive viewer, rather than writing to file" |
| + ) |
| + command_line_parser.add_argument( |
| + "--print_top", "-t", |
|
rmcilroy
2016/04/12 14:08:51
name "top_count"
Stefano Sanfilippo
2016/04/12 14:26:26
Done.
|
| + metavar="N", |
| + type=int, |
| + default=10, |
| + help="print the top N counters (default 10)" |
| + ) |
| + command_line_parser.add_argument( |
| + "--output_filename", "-o", |
| + metavar="<output filename>", |
| + default="v8.ignition_dispatches_table.svg", |
| + help=("file to save the plot file to. File type is deduced from the " |
| + "extension. PDF, SVG, PNG supported") |
| + ) |
| + command_line_parser.add_argument( |
| + "input_filename", |
| + metavar="<input filename>", |
| + default="v8.ignition_dispatches_table.json", |
| + nargs='?', |
| + help="Ignition counters JSON file" |
| + ) |
| + |
| + return command_line_parser.parse_args() |
| + |
| + |
| +def main(): |
| + program_options = parse_command_line() |
| + |
| + with open(program_options.input_filename) as stream: |
| + dispatches_table = json.load(stream) |
| + |
| + warn_if_counter_may_have_saturated(dispatches_table) |
| + |
| + if program_options.print_top > 0: |
|
rmcilroy
2016/04/12 14:08:51
This is default 10, so the only way to avoid it is
Stefano Sanfilippo
2016/04/12 14:26:26
Done.
|
| + print_top_counters(dispatches_table, program_options.print_top) |
| + |
| + if program_options.plot: |
| + figure, axis = pyplot.subplots() |
| + plot_dispatches_table(dispatches_table, figure, axis) |
| + |
| + if program_options.interactive: |
| + pyplot.show() |
| + else: |
| + figure.set_size_inches(program_options.plot_size, |
| + program_options.plot_size) |
| + pyplot.savefig(program_options.output_filename) |
| + |
| + |
| +if __name__ == "__main__": |
| + main() |