1*7594170eSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*7594170eSAndroid Build Coastguard Worker# 3*7594170eSAndroid Build Coastguard Worker# Copyright (C) 2022 The Android Open Source Project 4*7594170eSAndroid Build Coastguard Worker# 5*7594170eSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*7594170eSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*7594170eSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*7594170eSAndroid Build Coastguard Worker# 9*7594170eSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*7594170eSAndroid Build Coastguard Worker# 11*7594170eSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*7594170eSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*7594170eSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*7594170eSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*7594170eSAndroid Build Coastguard Worker# limitations under the License. 16*7594170eSAndroid Build Coastguard Worker"""A tool to print human-readable metrics information regarding the last build. 17*7594170eSAndroid Build Coastguard Worker 18*7594170eSAndroid Build Coastguard WorkerBy default, the consumed files will be located in $ANDROID_BUILD_TOP/out/. You 19*7594170eSAndroid Build Coastguard Workermay pass in a different directory instead using the metrics_files_dir flag. 20*7594170eSAndroid Build Coastguard Worker""" 21*7594170eSAndroid Build Coastguard Worker 22*7594170eSAndroid Build Coastguard Workerimport argparse 23*7594170eSAndroid Build Coastguard Workerimport json 24*7594170eSAndroid Build Coastguard Workerimport os 25*7594170eSAndroid Build Coastguard Workerimport shutil 26*7594170eSAndroid Build Coastguard Workerimport subprocess 27*7594170eSAndroid Build Coastguard Workerimport sys 28*7594170eSAndroid Build Coastguard Workerimport tarfile 29*7594170eSAndroid Build Coastguard Worker 30*7594170eSAndroid Build Coastguard Workerfrom bazel_metrics_proto.bazel_metrics_pb2 import BazelMetrics 31*7594170eSAndroid Build Coastguard Workerfrom bp2build_metrics_proto.bp2build_metrics_pb2 import Bp2BuildMetrics, UnconvertedReasonType 32*7594170eSAndroid Build Coastguard Workerfrom google.protobuf import json_format 33*7594170eSAndroid Build Coastguard Workerfrom metrics_proto.metrics_pb2 import MetricsBase, SoongBuildMetrics 34*7594170eSAndroid Build Coastguard Worker 35*7594170eSAndroid Build Coastguard Worker 36*7594170eSAndroid Build Coastguard Workerclass Event(object): 37*7594170eSAndroid Build Coastguard Worker """Contains nested event data. 38*7594170eSAndroid Build Coastguard Worker 39*7594170eSAndroid Build Coastguard Worker Fields: 40*7594170eSAndroid Build Coastguard Worker name: The short name of this event e.g. the 'b' in an event called a.b. 41*7594170eSAndroid Build Coastguard Worker start_time_relative_ns: Time since the epoch that the event started 42*7594170eSAndroid Build Coastguard Worker duration_ns: Duration of this event, including time spent in children. 43*7594170eSAndroid Build Coastguard Worker """ 44*7594170eSAndroid Build Coastguard Worker 45*7594170eSAndroid Build Coastguard Worker def __init__(self, name, start_time_relative_ns, duration_ns): 46*7594170eSAndroid Build Coastguard Worker self.name = name 47*7594170eSAndroid Build Coastguard Worker self.start_time_relative_ns = start_time_relative_ns 48*7594170eSAndroid Build Coastguard Worker self.duration_ns = duration_ns 49*7594170eSAndroid Build Coastguard Worker 50*7594170eSAndroid Build Coastguard Worker 51*7594170eSAndroid Build Coastguard Workerdef _get_output_file(output_dir, filename): 52*7594170eSAndroid Build Coastguard Worker file_base = os.path.splitext(filename)[0] 53*7594170eSAndroid Build Coastguard Worker return os.path.join(output_dir, file_base + ".json") 54*7594170eSAndroid Build Coastguard Worker 55*7594170eSAndroid Build Coastguard Worker 56*7594170eSAndroid Build Coastguard Workerdef _get_default_out_dir(metrics_dir): 57*7594170eSAndroid Build Coastguard Worker return os.path.join(metrics_dir, "analyze_build_output") 58*7594170eSAndroid Build Coastguard Worker 59*7594170eSAndroid Build Coastguard Worker 60*7594170eSAndroid Build Coastguard Workerdef _get_default_metrics_dir(): 61*7594170eSAndroid Build Coastguard Worker """Returns the filepath for the build output.""" 62*7594170eSAndroid Build Coastguard Worker out_dir = os.getenv("OUT_DIR") 63*7594170eSAndroid Build Coastguard Worker if out_dir: 64*7594170eSAndroid Build Coastguard Worker return out_dir 65*7594170eSAndroid Build Coastguard Worker build_top = os.getenv("ANDROID_BUILD_TOP") 66*7594170eSAndroid Build Coastguard Worker if not build_top: 67*7594170eSAndroid Build Coastguard Worker raise Exception( 68*7594170eSAndroid Build Coastguard Worker "$ANDROID_BUILD_TOP not found in environment. Have you run lunch?" 69*7594170eSAndroid Build Coastguard Worker ) 70*7594170eSAndroid Build Coastguard Worker return os.path.join(build_top, "out") 71*7594170eSAndroid Build Coastguard Worker 72*7594170eSAndroid Build Coastguard Worker 73*7594170eSAndroid Build Coastguard Workerdef _write_event(out, event): 74*7594170eSAndroid Build Coastguard Worker """Writes an event. See _write_events for args.""" 75*7594170eSAndroid Build Coastguard Worker out.write( 76*7594170eSAndroid Build Coastguard Worker "%(start)9s %(duration)9s %(name)s\n" 77*7594170eSAndroid Build Coastguard Worker % { 78*7594170eSAndroid Build Coastguard Worker "start": _format_ns(event.start_time_relative_ns), 79*7594170eSAndroid Build Coastguard Worker "duration": _format_ns(event.duration_ns), 80*7594170eSAndroid Build Coastguard Worker "name": event.name, 81*7594170eSAndroid Build Coastguard Worker } 82*7594170eSAndroid Build Coastguard Worker ) 83*7594170eSAndroid Build Coastguard Worker 84*7594170eSAndroid Build Coastguard Worker 85*7594170eSAndroid Build Coastguard Workerdef _print_metrics_event_times(description, metrics): 86*7594170eSAndroid Build Coastguard Worker # Bail if there are no events 87*7594170eSAndroid Build Coastguard Worker raw_events = metrics.events 88*7594170eSAndroid Build Coastguard Worker if not raw_events: 89*7594170eSAndroid Build Coastguard Worker print("%s: No events to display" % description) 90*7594170eSAndroid Build Coastguard Worker return 91*7594170eSAndroid Build Coastguard Worker print("-- %s events --" % description) 92*7594170eSAndroid Build Coastguard Worker 93*7594170eSAndroid Build Coastguard Worker # Update the start times to be based on the first event 94*7594170eSAndroid Build Coastguard Worker first_time_ns = min([event.start_time for event in raw_events]) 95*7594170eSAndroid Build Coastguard Worker events = [ 96*7594170eSAndroid Build Coastguard Worker Event( 97*7594170eSAndroid Build Coastguard Worker getattr(e, "description", e.name), 98*7594170eSAndroid Build Coastguard Worker e.start_time - first_time_ns, 99*7594170eSAndroid Build Coastguard Worker e.real_time, 100*7594170eSAndroid Build Coastguard Worker ) 101*7594170eSAndroid Build Coastguard Worker for e in raw_events 102*7594170eSAndroid Build Coastguard Worker ] 103*7594170eSAndroid Build Coastguard Worker 104*7594170eSAndroid Build Coastguard Worker # Sort by start time so the nesting also is sorted by time 105*7594170eSAndroid Build Coastguard Worker events.sort(key=lambda x: x.start_time_relative_ns) 106*7594170eSAndroid Build Coastguard Worker 107*7594170eSAndroid Build Coastguard Worker # Output the results 108*7594170eSAndroid Build Coastguard Worker print(" start duration") 109*7594170eSAndroid Build Coastguard Worker 110*7594170eSAndroid Build Coastguard Worker for event in events: 111*7594170eSAndroid Build Coastguard Worker _write_event(sys.stdout, event) 112*7594170eSAndroid Build Coastguard Worker print() 113*7594170eSAndroid Build Coastguard Worker 114*7594170eSAndroid Build Coastguard Worker 115*7594170eSAndroid Build Coastguard Workerdef _format_ns(duration_ns): 116*7594170eSAndroid Build Coastguard Worker "Pretty print duration in nanoseconds" 117*7594170eSAndroid Build Coastguard Worker return "%.02fs" % (duration_ns / 1_000_000_000) 118*7594170eSAndroid Build Coastguard Worker 119*7594170eSAndroid Build Coastguard Worker 120*7594170eSAndroid Build Coastguard Workerdef _read_data(filepath, proto): 121*7594170eSAndroid Build Coastguard Worker with open(filepath, "rb") as f: 122*7594170eSAndroid Build Coastguard Worker proto.ParseFromString(f.read()) 123*7594170eSAndroid Build Coastguard Worker f.close() 124*7594170eSAndroid Build Coastguard Worker 125*7594170eSAndroid Build Coastguard Worker 126*7594170eSAndroid Build Coastguard Workerdef _maybe_save_data(proto, filename, args): 127*7594170eSAndroid Build Coastguard Worker if args.skip_metrics: 128*7594170eSAndroid Build Coastguard Worker return 129*7594170eSAndroid Build Coastguard Worker json_out = json_format.MessageToJson(proto) 130*7594170eSAndroid Build Coastguard Worker output_filepath = _get_output_file(args.output_dir, filename) 131*7594170eSAndroid Build Coastguard Worker _save_file(json_out, output_filepath) 132*7594170eSAndroid Build Coastguard Worker 133*7594170eSAndroid Build Coastguard Worker 134*7594170eSAndroid Build Coastguard Workerdef _save_file(data, file): 135*7594170eSAndroid Build Coastguard Worker with open(file, "w") as f: 136*7594170eSAndroid Build Coastguard Worker f.write(data) 137*7594170eSAndroid Build Coastguard Worker f.close() 138*7594170eSAndroid Build Coastguard Worker 139*7594170eSAndroid Build Coastguard Worker 140*7594170eSAndroid Build Coastguard Workerdef _handle_missing_metrics(args, filename): 141*7594170eSAndroid Build Coastguard Worker """Handles cleanup for a metrics file that doesn't exist. 142*7594170eSAndroid Build Coastguard Worker 143*7594170eSAndroid Build Coastguard Worker This will delete any output files under the tool's output directory that 144*7594170eSAndroid Build Coastguard Worker would have been generated as a result of a metrics file from a previous 145*7594170eSAndroid Build Coastguard Worker build. This prevents stale analysis files from polluting the output dir. 146*7594170eSAndroid Build Coastguard Worker """ 147*7594170eSAndroid Build Coastguard Worker if args.skip_metrics: 148*7594170eSAndroid Build Coastguard Worker # If skip_metrics is enabled, then don't write or delete any data. 149*7594170eSAndroid Build Coastguard Worker return 150*7594170eSAndroid Build Coastguard Worker output_filepath = _get_output_file(args.output_dir, filename) 151*7594170eSAndroid Build Coastguard Worker if os.path.exists(output_filepath): 152*7594170eSAndroid Build Coastguard Worker os.remove(output_filepath) 153*7594170eSAndroid Build Coastguard Worker 154*7594170eSAndroid Build Coastguard Worker 155*7594170eSAndroid Build Coastguard Workerdef process_timing_mode(args): 156*7594170eSAndroid Build Coastguard Worker metrics_files_dir = args.metrics_files_dir 157*7594170eSAndroid Build Coastguard Worker if not args.skip_metrics: 158*7594170eSAndroid Build Coastguard Worker os.makedirs(args.output_dir, exist_ok=True) 159*7594170eSAndroid Build Coastguard Worker print("Writing build analysis files to " + args.output_dir, file=sys.stderr) 160*7594170eSAndroid Build Coastguard Worker 161*7594170eSAndroid Build Coastguard Worker bp2build_file = os.path.join(metrics_files_dir, "bp2build_metrics.pb") 162*7594170eSAndroid Build Coastguard Worker if os.path.exists(bp2build_file): 163*7594170eSAndroid Build Coastguard Worker bp2build_metrics = Bp2BuildMetrics() 164*7594170eSAndroid Build Coastguard Worker _read_data(bp2build_file, bp2build_metrics) 165*7594170eSAndroid Build Coastguard Worker _print_metrics_event_times("bp2build", bp2build_metrics) 166*7594170eSAndroid Build Coastguard Worker _maybe_save_data(bp2build_metrics, "bp2build_metrics.pb", args) 167*7594170eSAndroid Build Coastguard Worker else: 168*7594170eSAndroid Build Coastguard Worker _handle_missing_metrics(args, "bp2build_metrics.pb") 169*7594170eSAndroid Build Coastguard Worker 170*7594170eSAndroid Build Coastguard Worker soong_build_file = os.path.join(metrics_files_dir, "soong_build_metrics.pb") 171*7594170eSAndroid Build Coastguard Worker if os.path.exists(soong_build_file): 172*7594170eSAndroid Build Coastguard Worker soong_build_metrics = SoongBuildMetrics() 173*7594170eSAndroid Build Coastguard Worker _read_data(soong_build_file, soong_build_metrics) 174*7594170eSAndroid Build Coastguard Worker _print_metrics_event_times("soong_build", soong_build_metrics) 175*7594170eSAndroid Build Coastguard Worker _maybe_save_data(soong_build_metrics, "soong_build_metrics.pb", args) 176*7594170eSAndroid Build Coastguard Worker else: 177*7594170eSAndroid Build Coastguard Worker _handle_missing_metrics(args, "soong_build_metrics.pb") 178*7594170eSAndroid Build Coastguard Worker 179*7594170eSAndroid Build Coastguard Worker soong_metrics_file = os.path.join(metrics_files_dir, "soong_metrics") 180*7594170eSAndroid Build Coastguard Worker if os.path.exists(soong_metrics_file): 181*7594170eSAndroid Build Coastguard Worker metrics_base = MetricsBase() 182*7594170eSAndroid Build Coastguard Worker _read_data(soong_metrics_file, metrics_base) 183*7594170eSAndroid Build Coastguard Worker _maybe_save_data(metrics_base, "soong_metrics", args) 184*7594170eSAndroid Build Coastguard Worker else: 185*7594170eSAndroid Build Coastguard Worker _handle_missing_metrics(args, "soong_metrics") 186*7594170eSAndroid Build Coastguard Worker 187*7594170eSAndroid Build Coastguard Worker bazel_metrics_file = os.path.join(metrics_files_dir, "bazel_metrics.pb") 188*7594170eSAndroid Build Coastguard Worker if os.path.exists(bazel_metrics_file): 189*7594170eSAndroid Build Coastguard Worker bazel_metrics = BazelMetrics() 190*7594170eSAndroid Build Coastguard Worker _read_data(bazel_metrics_file, bazel_metrics) 191*7594170eSAndroid Build Coastguard Worker _maybe_save_data(bazel_metrics, "bazel_metrics.pb", args) 192*7594170eSAndroid Build Coastguard Worker else: 193*7594170eSAndroid Build Coastguard Worker _handle_missing_metrics(args, "bazel_metrics.pb") 194*7594170eSAndroid Build Coastguard Worker 195*7594170eSAndroid Build Coastguard Worker 196*7594170eSAndroid Build Coastguard Workerdef process_build_files_mode(args): 197*7594170eSAndroid Build Coastguard Worker if args.skip_metrics: 198*7594170eSAndroid Build Coastguard Worker raise Exception("build_files mode incompatible with --skip-metrics") 199*7594170eSAndroid Build Coastguard Worker os.makedirs(args.output_dir, exist_ok=True) 200*7594170eSAndroid Build Coastguard Worker tar_out = os.path.join(args.output_dir, "build_files.tar.gz") 201*7594170eSAndroid Build Coastguard Worker 202*7594170eSAndroid Build Coastguard Worker os.chdir(args.metrics_files_dir) 203*7594170eSAndroid Build Coastguard Worker 204*7594170eSAndroid Build Coastguard Worker if os.path.exists(tar_out): 205*7594170eSAndroid Build Coastguard Worker os.remove(tar_out) 206*7594170eSAndroid Build Coastguard Worker print("adding build files to", tar_out, "...", file=sys.stderr) 207*7594170eSAndroid Build Coastguard Worker 208*7594170eSAndroid Build Coastguard Worker with tarfile.open(tar_out, "w:gz", dereference=True) as tar: 209*7594170eSAndroid Build Coastguard Worker for root, dirs, files in os.walk("."): 210*7594170eSAndroid Build Coastguard Worker for file in files: 211*7594170eSAndroid Build Coastguard Worker if ( 212*7594170eSAndroid Build Coastguard Worker file.endswith(".bzl") 213*7594170eSAndroid Build Coastguard Worker or file.endswith("BUILD") 214*7594170eSAndroid Build Coastguard Worker or file.endswith("BUILD.bazel") 215*7594170eSAndroid Build Coastguard Worker ): 216*7594170eSAndroid Build Coastguard Worker tar.add(os.path.join(root, file), arcname=os.path.join(root, file)) 217*7594170eSAndroid Build Coastguard Worker 218*7594170eSAndroid Build Coastguard Worker 219*7594170eSAndroid Build Coastguard Workerdef process_bp2build_mode(args): 220*7594170eSAndroid Build Coastguard Worker metrics_files_dir = args.metrics_files_dir 221*7594170eSAndroid Build Coastguard Worker if not args.skip_metrics: 222*7594170eSAndroid Build Coastguard Worker os.makedirs(args.output_dir, exist_ok=True) 223*7594170eSAndroid Build Coastguard Worker print("Writing build analysis files to " + args.output_dir, file=sys.stderr) 224*7594170eSAndroid Build Coastguard Worker 225*7594170eSAndroid Build Coastguard Worker bp2build_file = os.path.join(metrics_files_dir, "bp2build_metrics.pb") 226*7594170eSAndroid Build Coastguard Worker if not os.path.exists(bp2build_file): 227*7594170eSAndroid Build Coastguard Worker raise Exception("bp2build mode requires that the last build ran bp2build") 228*7594170eSAndroid Build Coastguard Worker 229*7594170eSAndroid Build Coastguard Worker bp2build_metrics = Bp2BuildMetrics() 230*7594170eSAndroid Build Coastguard Worker _read_data(bp2build_file, bp2build_metrics) 231*7594170eSAndroid Build Coastguard Worker _maybe_save_data(bp2build_metrics, "bp2build_metrics.pb", args) 232*7594170eSAndroid Build Coastguard Worker converted_modules = {} 233*7594170eSAndroid Build Coastguard Worker for module in bp2build_metrics.convertedModules: 234*7594170eSAndroid Build Coastguard Worker converted_modules[module] = True 235*7594170eSAndroid Build Coastguard Worker 236*7594170eSAndroid Build Coastguard Worker if len(args.module_names) > 0: 237*7594170eSAndroid Build Coastguard Worker modules_to_report = args.module_names 238*7594170eSAndroid Build Coastguard Worker else: 239*7594170eSAndroid Build Coastguard Worker all_modules = {} 240*7594170eSAndroid Build Coastguard Worker for m in converted_modules: 241*7594170eSAndroid Build Coastguard Worker all_modules[m] = True 242*7594170eSAndroid Build Coastguard Worker for m in bp2build_metrics.unconvertedModules: 243*7594170eSAndroid Build Coastguard Worker all_modules[m] = True 244*7594170eSAndroid Build Coastguard Worker modules_to_report = sorted(all_modules) 245*7594170eSAndroid Build Coastguard Worker 246*7594170eSAndroid Build Coastguard Worker for name in modules_to_report: 247*7594170eSAndroid Build Coastguard Worker if name in converted_modules: 248*7594170eSAndroid Build Coastguard Worker print(name, "converted successfully.") 249*7594170eSAndroid Build Coastguard Worker elif name in bp2build_metrics.unconvertedModules: 250*7594170eSAndroid Build Coastguard Worker unconverted_summary = name + " not converted: " 251*7594170eSAndroid Build Coastguard Worker t = bp2build_metrics.unconvertedModules[name].type 252*7594170eSAndroid Build Coastguard Worker if t > -1 and t < len(UnconvertedReasonType.keys()): 253*7594170eSAndroid Build Coastguard Worker unconverted_summary += UnconvertedReasonType.keys()[t] 254*7594170eSAndroid Build Coastguard Worker else: 255*7594170eSAndroid Build Coastguard Worker unconverted_summary += "UNKNOWN_TYPE" 256*7594170eSAndroid Build Coastguard Worker if len(bp2build_metrics.unconvertedModules[name].detail) > 0: 257*7594170eSAndroid Build Coastguard Worker unconverted_summary += ( 258*7594170eSAndroid Build Coastguard Worker " detail: " + bp2build_metrics.unconvertedModules[name].detail 259*7594170eSAndroid Build Coastguard Worker ) 260*7594170eSAndroid Build Coastguard Worker print(unconverted_summary) 261*7594170eSAndroid Build Coastguard Worker else: 262*7594170eSAndroid Build Coastguard Worker print(name, "does not exist.") 263*7594170eSAndroid Build Coastguard Worker 264*7594170eSAndroid Build Coastguard Worker 265*7594170eSAndroid Build Coastguard Workerdef _define_global_flags(parser, suppress_default=False): 266*7594170eSAndroid Build Coastguard Worker """Adds global flags to the given parser object. 267*7594170eSAndroid Build Coastguard Worker 268*7594170eSAndroid Build Coastguard Worker Global flags should be added to both the global args parser and subcommand 269*7594170eSAndroid Build Coastguard Worker parsers. This allows global flags to be specified before or after the 270*7594170eSAndroid Build Coastguard Worker subcommand. 271*7594170eSAndroid Build Coastguard Worker 272*7594170eSAndroid Build Coastguard Worker Subcommand parser binding should pass suppress_default=True. This uses the 273*7594170eSAndroid Build Coastguard Worker default value specified in the global parser. 274*7594170eSAndroid Build Coastguard Worker """ 275*7594170eSAndroid Build Coastguard Worker parser.add_argument( 276*7594170eSAndroid Build Coastguard Worker "--metrics_files_dir", 277*7594170eSAndroid Build Coastguard Worker default=( 278*7594170eSAndroid Build Coastguard Worker argparse.SUPPRESS if suppress_default else _get_default_metrics_dir() 279*7594170eSAndroid Build Coastguard Worker ), 280*7594170eSAndroid Build Coastguard Worker help="The directory contained metrics files to analyze." 281*7594170eSAndroid Build Coastguard Worker + " Defaults to $OUT_DIR if set, $ANDROID_BUILD_TOP/out otherwise.", 282*7594170eSAndroid Build Coastguard Worker ) 283*7594170eSAndroid Build Coastguard Worker parser.add_argument( 284*7594170eSAndroid Build Coastguard Worker "--skip-metrics", 285*7594170eSAndroid Build Coastguard Worker action="store_true", 286*7594170eSAndroid Build Coastguard Worker default=(argparse.SUPPRESS if suppress_default else None), 287*7594170eSAndroid Build Coastguard Worker help="If set, do not save the output of printproto commands.", 288*7594170eSAndroid Build Coastguard Worker ) 289*7594170eSAndroid Build Coastguard Worker parser.add_argument( 290*7594170eSAndroid Build Coastguard Worker "--output_dir", 291*7594170eSAndroid Build Coastguard Worker default=(argparse.SUPPRESS if suppress_default else None), 292*7594170eSAndroid Build Coastguard Worker help="The directory to save analyzed proto output to. " 293*7594170eSAndroid Build Coastguard Worker + "If unspecified, will default to the directory specified with" 294*7594170eSAndroid Build Coastguard Worker " --metrics_files_dir + '/analyze_build_output/'", 295*7594170eSAndroid Build Coastguard Worker ) 296*7594170eSAndroid Build Coastguard Worker 297*7594170eSAndroid Build Coastguard Worker 298*7594170eSAndroid Build Coastguard Workerdef main(): 299*7594170eSAndroid Build Coastguard Worker # Parse args 300*7594170eSAndroid Build Coastguard Worker parser = argparse.ArgumentParser( 301*7594170eSAndroid Build Coastguard Worker description=( 302*7594170eSAndroid Build Coastguard Worker "Analyzes build artifacts from the user's most recent build. Prints" 303*7594170eSAndroid Build Coastguard Worker " and/or saves data in a user-friendly format. See" 304*7594170eSAndroid Build Coastguard Worker " subcommand-specific help for analysis options." 305*7594170eSAndroid Build Coastguard Worker ), 306*7594170eSAndroid Build Coastguard Worker prog="analyze_build", 307*7594170eSAndroid Build Coastguard Worker ) 308*7594170eSAndroid Build Coastguard Worker _define_global_flags(parser) 309*7594170eSAndroid Build Coastguard Worker subparsers = parser.add_subparsers( 310*7594170eSAndroid Build Coastguard Worker title="subcommands", 311*7594170eSAndroid Build Coastguard Worker help='types of analysis to run, "timing" by default.', 312*7594170eSAndroid Build Coastguard Worker dest="mode", 313*7594170eSAndroid Build Coastguard Worker ) 314*7594170eSAndroid Build Coastguard Worker timing_parser = subparsers.add_parser( 315*7594170eSAndroid Build Coastguard Worker "timing", help="print per-phase build timing information" 316*7594170eSAndroid Build Coastguard Worker ) 317*7594170eSAndroid Build Coastguard Worker _define_global_flags(timing_parser, True) 318*7594170eSAndroid Build Coastguard Worker build_files_parser = subparsers.add_parser( 319*7594170eSAndroid Build Coastguard Worker "build_files", 320*7594170eSAndroid Build Coastguard Worker help="create a tar containing all bazel-related build files", 321*7594170eSAndroid Build Coastguard Worker ) 322*7594170eSAndroid Build Coastguard Worker _define_global_flags(build_files_parser, True) 323*7594170eSAndroid Build Coastguard Worker bp2build_parser = subparsers.add_parser( 324*7594170eSAndroid Build Coastguard Worker "bp2build", 325*7594170eSAndroid Build Coastguard Worker help="print whether a module was generated by bp2build", 326*7594170eSAndroid Build Coastguard Worker ) 327*7594170eSAndroid Build Coastguard Worker _define_global_flags(bp2build_parser, True) 328*7594170eSAndroid Build Coastguard Worker bp2build_parser.add_argument( 329*7594170eSAndroid Build Coastguard Worker "module_names", 330*7594170eSAndroid Build Coastguard Worker metavar="module_name", 331*7594170eSAndroid Build Coastguard Worker nargs="*", 332*7594170eSAndroid Build Coastguard Worker help="print conversion info about these modules", 333*7594170eSAndroid Build Coastguard Worker ) 334*7594170eSAndroid Build Coastguard Worker 335*7594170eSAndroid Build Coastguard Worker args = parser.parse_args() 336*7594170eSAndroid Build Coastguard Worker 337*7594170eSAndroid Build Coastguard Worker # Use `timing` as the default build mode. 338*7594170eSAndroid Build Coastguard Worker if not args.mode: 339*7594170eSAndroid Build Coastguard Worker args.mode = "timing" 340*7594170eSAndroid Build Coastguard Worker # Check the metrics dir. 341*7594170eSAndroid Build Coastguard Worker if not os.path.exists(args.metrics_files_dir): 342*7594170eSAndroid Build Coastguard Worker raise Exception( 343*7594170eSAndroid Build Coastguard Worker "Directory " 344*7594170eSAndroid Build Coastguard Worker + arg.metrics_files_dir 345*7594170eSAndroid Build Coastguard Worker + " not found. Did you run a build?" 346*7594170eSAndroid Build Coastguard Worker ) 347*7594170eSAndroid Build Coastguard Worker 348*7594170eSAndroid Build Coastguard Worker args.output_dir = args.output_dir or _get_default_out_dir( 349*7594170eSAndroid Build Coastguard Worker args.metrics_files_dir 350*7594170eSAndroid Build Coastguard Worker ) 351*7594170eSAndroid Build Coastguard Worker 352*7594170eSAndroid Build Coastguard Worker if args.mode == "timing": 353*7594170eSAndroid Build Coastguard Worker process_timing_mode(args) 354*7594170eSAndroid Build Coastguard Worker elif args.mode == "build_files": 355*7594170eSAndroid Build Coastguard Worker process_build_files_mode(args) 356*7594170eSAndroid Build Coastguard Worker elif args.mode == "bp2build": 357*7594170eSAndroid Build Coastguard Worker process_bp2build_mode(args) 358*7594170eSAndroid Build Coastguard Worker 359*7594170eSAndroid Build Coastguard Worker 360*7594170eSAndroid Build Coastguard Workerif __name__ == "__main__": 361*7594170eSAndroid Build Coastguard Worker main() 362