Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Unified Diff: tools/ignition_perf_report.py

Issue 1783503002: [Interpreter] Add Ignition profile visualization tool. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@run-perf
Patch Set: Test symbol name regex w/ template instantiations. Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tools/ignition_perf_report.py
diff --git a/tools/ignition_perf_report.py b/tools/ignition_perf_report.py
new file mode 100755
index 0000000000000000000000000000000000000000..7679084ddb49e3febbd275371bd3c3e87ad315ee
--- /dev/null
+++ b/tools/ignition_perf_report.py
@@ -0,0 +1,140 @@
+#! /usr/bin/python2
+#
+# 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 collections
+import re
+import subprocess
+import sys
+
+
+DESCRIPTION = """
+Processes a perf.data sample file and reports the hottest Ignition bytecodes,
+or write an input file for flamegraph.pl.
+"""
+
+
+EPILOGUE = """
rmcilroy 2016/03/11 11:26:49 HELP_EPILOGUE. Also make these all private by addi
Stefano Sanfilippo 2016/03/11 16:33:51 Done.
rmcilroy 2016/03/14 12:26:52 You never made the fields private.
Stefano Sanfilippo 2016/03/14 13:14:20 Wooops, sorry about that. Done for the help string
rmcilroy 2016/03/14 14:48:00 This is fine, thanks.
+examples:
+ # Get a flamegraph for Ignition bytecode handlers on Octane benchmark,
+ # without considering time spent compiling JS code.
+ #
+ $ tools/run-perf.sh out/x64.release/d8 --ignition octane/run.js
+ $ tools/ignition_perf_report.py --flamegraph --hide-compile -o out.collapsed
+ $ flamegraph.pl --colors js out.collapsed > out.svg
+
+ # See the hottest bytecodes on Octane benchmark, by number of samples.
+ #
+ $ tools/run-perf.sh out/x64.release/d8 --ignition octane/run.js
+ $ tools/ignition_perf_report.py
+"""
+
+
+COMPILER_SYMBOLS_RE = re.compile(r"Builtin:Compile(?:Lazy|OptimizedConcurrent)"
+ "$|LazyCompile:|v8::internal::Compile")
+
+
+# Function name, strip parameters
+SYMBOL_NAME_RE = re.compile(r"((?:\(anonymous namespace\)|[^(])+)")
+
+
+def yield_collapsed_callchains(perf_stream, hide_compile_time=False):
rmcilroy 2016/03/11 11:26:48 Probably better named collapsed_callchains_generat
Stefano Sanfilippo 2016/03/11 16:33:51 Done.
+ current_chain = []
+ keep_parsing_chain = True
+ for line in perf_stream:
+ if line[0] == "#":
rmcilroy 2016/03/11 11:26:49 Add some comments (e.g., # Skip comments, # Empty
Stefano Sanfilippo 2016/03/11 16:33:51 Done.
+ continue
+ line = line.strip()
+ if not line:
+ keep_parsing_chain = True
+ current_chain = []
+ continue
+ if not keep_parsing_chain:
+ continue
+ symbol = SYMBOL_NAME_RE.match(line.split(" ", 1)[1]).group(1)
rmcilroy 2016/03/11 11:26:49 nit newline above
Stefano Sanfilippo 2016/03/11 16:33:51 Done.
+ current_chain.append(symbol)
+ if hide_compile_time and COMPILER_SYMBOLS_RE.match(symbol):
+ keep_parsing_chain = False
+ elif symbol.startswith("BytecodeHandler:"):
+ keep_parsing_chain = False
+ yield current_chain
+
+
+def count_callchains(callchains):
rmcilroy 2016/03/11 11:26:49 get_callchain_sample_counts ?
Stefano Sanfilippo 2016/03/11 16:33:51 I think calculate_* better conveys the idea that t
+ chain_counters = collections.defaultdict(int)
+ for callchain in callchains:
+ key = ";".join(reversed(callchain))
+ chain_counters[key] += 1
+ return chain_counters.items()
+
+
+def count_handler_samples(callchains):
rmcilroy 2016/03/11 11:26:49 get_bytecode_handler_sample_counts ?
Stefano Sanfilippo 2016/03/11 16:33:51 Same as above.
+ handler_counters = collections.defaultdict(int)
+ for callchain in callchains:
+ # Strip the "BytecodeHandler:" prefix
+ handler = callchain[-1].split(":", 1)[1]
+ handler_counters[handler] += 1
+ # Sort by decreasing number of samples
+ return sorted(handler_counters.items(),
rmcilroy 2016/03/11 11:26:49 Maybe just do the sort in main below, to keep thes
Stefano Sanfilippo 2016/03/11 16:33:51 Done.
+ key=lambda entry: entry[1], reverse=True)
+
+
+def parse_command_line():
+ command_line_parser = argparse.ArgumentParser(
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ description=DESCRIPTION,
+ epilog=EPILOGUE)
+
+ command_line_parser.add_argument(
+ "perf_filename",
+ help="perf sample file to process (default: perf.data)",
+ nargs="?",
+ default="perf.data",
+ metavar="<perf filename>")
+ command_line_parser.add_argument(
+ "--flamegraph", "-f",
+ help="output an input file for flamegraph.pl, not a report",
+ action="store_true",
+ dest="output_flamegraph")
+ command_line_parser.add_argument(
+ "--hide-compile", "-c",
+ help="do not count samples inside compiler routines",
+ action="store_true",
+ dest="hide_compile_time")
+ command_line_parser.add_argument(
+ "--output", "-o",
+ help="output file name (stdout if omitted)",
+ type=argparse.FileType('wt'),
+ default=sys.stdout,
+ metavar="<output filename>",
+ dest="output_stream")
+
+ return command_line_parser.parse_args()
+
+
+def main():
+ program_options = parse_command_line()
+ output_stream = program_options.output_stream
+ perf = subprocess.Popen(["perf", "script", "-f", "ip,sym",
+ "-i", program_options.perf_filename],
+ stdout=subprocess.PIPE)
+ callchains = yield_collapsed_callchains(perf.stdout,
+ program_options.hide_compile_time)
+ if program_options.output_flamegraph:
+ for callchain, count in count_callchains(callchains):
+ output_stream.write("{} {}\n".format(callchain, count))
rmcilroy 2016/03/11 11:26:49 nit - move to a seperate function (for clarity) an
Stefano Sanfilippo 2016/03/11 16:33:51 Done.
+ else:
+ handler_counters = count_handler_samples(callchains)
+ samples_num = sum(counter for _, counter in handler_counters)
+ for bytecode_name, count in handler_counters:
+ output_stream.write(
+ "{}\t{}\t{:.3f}%\n".format(bytecode_name, count,
+ 100. * count / samples_num))
+
+
+if __name__ == "__main__":
+ main()
« no previous file with comments | « no previous file | tools/unittests/ignition_perf_report_test.py » ('j') | tools/unittests/ignition_perf_report_test.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698