From 34d90bebd8ba4a01d221dbd6fa0d12253c77d13c Mon Sep 17 00:00:00 2001 From: Bruce Dawson Date: Mon, 16 Mar 2020 23:08:05 +0000 Subject: [PATCH] Allow customizable build-type grouping The post_build_ninja_summary.py script, which autoninja automatically runs if NINJA_SUMMARIZE_BUILD=1 is set, summarizes build time by file extension. This is a good default summary but it can be handy to create additional output categories. This change allows using fn_match style wildcards to create additional categories which will then be summarized. For instance: python post_build_ninja_summary.py -C out/Def -s prec*.obj;blink*.obj In addition the chromium_step_types environment variable can be set so that when autoninja runs this script there will be additional summary categories. This has been used most recently when measuring the cost of creating and using blink precompiled header files. Bug: 1061326 Change-Id: I080b4ddd06d045a2351220e202cd9eec111bf00e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/2093145 Auto-Submit: Bruce Dawson Reviewed-by: Edward Lesmes Commit-Queue: Bruce Dawson --- post_build_ninja_summary.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/post_build_ninja_summary.py b/post_build_ninja_summary.py index b55a93b3b..5fd01d8e3 100644 --- a/post_build_ninja_summary.py +++ b/post_build_ninja_summary.py @@ -55,6 +55,7 @@ from __future__ import print_function import argparse import errno +import fnmatch import os import sys @@ -163,13 +164,17 @@ def ReadTargets(log, show_all): return targets_dict.values() -def GetExtension(target): +def GetExtension(target, extra_patterns): """Return the file extension that best represents a target. For targets that generate multiple outputs it is important to return a consistent 'canonical' extension. Ultimately the goal is to group build steps by type.""" for output in target.targets: + if extra_patterns: + for fn_pattern in extra_patterns.split(';'): + if fnmatch.fnmatch(output, '*' + fn_pattern + '*'): + return fn_pattern # Not a true extension, but a good grouping. if output.endswith('type_mappings'): extension = 'type_mappings' @@ -196,7 +201,7 @@ def GetExtension(target): return extension -def SummarizeEntries(entries): +def SummarizeEntries(entries, extra_step_types): """Print a summary of the passed in list of Target objects.""" # Create a list that is in order by time stamp and has entries for the @@ -273,7 +278,7 @@ def SummarizeEntries(entries): weighted_time_by_ext = {} # Scan through all of the targets to build up per-extension statistics. for target in entries: - extension = GetExtension(target) + extension = GetExtension(target, extra_step_types) time_by_ext[extension] = time_by_ext.get(extension, 0) + target.Duration() weighted_time_by_ext[extension] = weighted_time_by_ext.get(extension, 0) + target.WeightedDuration() @@ -301,6 +306,10 @@ def main(): parser = argparse.ArgumentParser() parser.add_argument('-C', dest='build_directory', help='Build directory.') + parser.add_argument( + '-s', + '--step-types', + help='semicolon separated fnmatch patterns for build-step grouping') parser.add_argument('--log-file', help="specific ninja log file to analyze.") args, _extra_args = parser.parse_known_args() @@ -308,11 +317,20 @@ def main(): log_file = os.path.join(args.build_directory, log_file) if args.log_file: log_file = args.log_file + if not args.step_types: + # Offer a convenient way to add extra step types automatically, including + # when this script is run by autoninja. get() returns None if the variable + # isn't set. + args.step_types = os.environ.get('chromium_step_types') + if args.step_types: + # Make room for the extra build types. + global long_ext_count + long_ext_count += len(args.step_types.split(';')) try: with open(log_file, 'r') as log: entries = ReadTargets(log, False) - SummarizeEntries(entries) + SummarizeEntries(entries, args.step_types) except IOError: print('Log file %r not found, no build summary created.' % log_file) return errno.ENOENT