1*288bf522SAndroid Build Coastguard Worker# 2*288bf522SAndroid Build Coastguard Worker# Copyright (C) 2024 The Android Open Source Project 3*288bf522SAndroid Build Coastguard Worker# 4*288bf522SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 5*288bf522SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 6*288bf522SAndroid Build Coastguard Worker# You may obtain a copy of the License at 7*288bf522SAndroid Build Coastguard Worker# 8*288bf522SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 9*288bf522SAndroid Build Coastguard Worker# 10*288bf522SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 11*288bf522SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 12*288bf522SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*288bf522SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 14*288bf522SAndroid Build Coastguard Worker# limitations under the License. 15*288bf522SAndroid Build Coastguard Worker# 16*288bf522SAndroid Build Coastguard Worker 17*288bf522SAndroid Build Coastguard Workerimport argparse 18*288bf522SAndroid Build Coastguard Workerimport os 19*288bf522SAndroid Build Coastguard Workerfrom command import ProfilerCommand, ConfigCommand, OpenCommand 20*288bf522SAndroid Build Coastguard Workerfrom device import AdbDevice 21*288bf522SAndroid Build Coastguard Workerfrom validation_error import ValidationError 22*288bf522SAndroid Build Coastguard Workerfrom config_builder import PREDEFINED_PERFETTO_CONFIGS 23*288bf522SAndroid Build Coastguard Workerfrom utils import path_exists 24*288bf522SAndroid Build Coastguard Workerfrom validate_simpleperf import verify_simpleperf_args 25*288bf522SAndroid Build Coastguard Worker 26*288bf522SAndroid Build Coastguard WorkerDEFAULT_DUR_MS = 10000 27*288bf522SAndroid Build Coastguard WorkerMIN_DURATION_MS = 3000 28*288bf522SAndroid Build Coastguard WorkerDEFAULT_OUT_DIR = "." 29*288bf522SAndroid Build Coastguard Worker 30*288bf522SAndroid Build Coastguard Worker 31*288bf522SAndroid Build Coastguard Workerdef create_parser(): 32*288bf522SAndroid Build Coastguard Worker parser = argparse.ArgumentParser(prog='torq command', 33*288bf522SAndroid Build Coastguard Worker description=('Torq CLI tool for performance' 34*288bf522SAndroid Build Coastguard Worker ' tests.')) 35*288bf522SAndroid Build Coastguard Worker parser.add_argument('-e', '--event', 36*288bf522SAndroid Build Coastguard Worker choices=['boot', 'user-switch', 'app-startup', 'custom'], 37*288bf522SAndroid Build Coastguard Worker default='custom', help='The event to trace/profile.') 38*288bf522SAndroid Build Coastguard Worker parser.add_argument('-p', '--profiler', choices=['perfetto', 'simpleperf'], 39*288bf522SAndroid Build Coastguard Worker default='perfetto', help='The performance data source.') 40*288bf522SAndroid Build Coastguard Worker parser.add_argument('-o', '--out-dir', default=DEFAULT_OUT_DIR, 41*288bf522SAndroid Build Coastguard Worker help='The path to the output directory.') 42*288bf522SAndroid Build Coastguard Worker parser.add_argument('-d', '--dur-ms', type=int, default=DEFAULT_DUR_MS, 43*288bf522SAndroid Build Coastguard Worker help=('The duration (ms) of the event. Determines when' 44*288bf522SAndroid Build Coastguard Worker ' to stop collecting performance data.')) 45*288bf522SAndroid Build Coastguard Worker parser.add_argument('-a', '--app', 46*288bf522SAndroid Build Coastguard Worker help='The package name of the app we want to start.') 47*288bf522SAndroid Build Coastguard Worker parser.add_argument('-r', '--runs', type=int, default=1, 48*288bf522SAndroid Build Coastguard Worker help=('The number of times to run the event and' 49*288bf522SAndroid Build Coastguard Worker ' capture the perf data.')) 50*288bf522SAndroid Build Coastguard Worker parser.add_argument('-s', '--simpleperf-event', action='append', 51*288bf522SAndroid Build Coastguard Worker help=('Simpleperf supported events to be collected.' 52*288bf522SAndroid Build Coastguard Worker ' e.g. cpu-cycles, instructions')) 53*288bf522SAndroid Build Coastguard Worker parser.add_argument('--perfetto-config', default='default', 54*288bf522SAndroid Build Coastguard Worker help=('Predefined perfetto configs can be used:' 55*288bf522SAndroid Build Coastguard Worker ' %s. A filepath with a custom config could' 56*288bf522SAndroid Build Coastguard Worker ' also be provided.' 57*288bf522SAndroid Build Coastguard Worker % (", ".join(PREDEFINED_PERFETTO_CONFIGS.keys())))) 58*288bf522SAndroid Build Coastguard Worker parser.add_argument('--between-dur-ms', type=int, default=DEFAULT_DUR_MS, 59*288bf522SAndroid Build Coastguard Worker help='Time (ms) to wait before executing the next event.') 60*288bf522SAndroid Build Coastguard Worker parser.add_argument('--ui', action=argparse.BooleanOptionalAction, 61*288bf522SAndroid Build Coastguard Worker help=('Specifies opening of UI visualization tool' 62*288bf522SAndroid Build Coastguard Worker ' after profiling is complete.')) 63*288bf522SAndroid Build Coastguard Worker parser.add_argument('--excluded-ftrace-events', action='append', 64*288bf522SAndroid Build Coastguard Worker help=('Excludes specified ftrace event from the perfetto' 65*288bf522SAndroid Build Coastguard Worker ' config events.')) 66*288bf522SAndroid Build Coastguard Worker parser.add_argument('--included-ftrace-events', action='append', 67*288bf522SAndroid Build Coastguard Worker help=('Includes specified ftrace event in the perfetto' 68*288bf522SAndroid Build Coastguard Worker ' config events.')) 69*288bf522SAndroid Build Coastguard Worker parser.add_argument('--from-user', type=int, 70*288bf522SAndroid Build Coastguard Worker help='The user id from which to start the user switch') 71*288bf522SAndroid Build Coastguard Worker parser.add_argument('--to-user', type=int, 72*288bf522SAndroid Build Coastguard Worker help='The user id of user that system is switching to.') 73*288bf522SAndroid Build Coastguard Worker parser.add_argument('--serial', 74*288bf522SAndroid Build Coastguard Worker help=(('Specifies serial of the device that will be' 75*288bf522SAndroid Build Coastguard Worker ' used.'))) 76*288bf522SAndroid Build Coastguard Worker parser.add_argument('--symbols', 77*288bf522SAndroid Build Coastguard Worker help='Specifies path to symbols library.') 78*288bf522SAndroid Build Coastguard Worker subparsers = parser.add_subparsers(dest='subcommands', help='Subcommands') 79*288bf522SAndroid Build Coastguard Worker config_parser = subparsers.add_parser('config', 80*288bf522SAndroid Build Coastguard Worker help=('The config subcommand used' 81*288bf522SAndroid Build Coastguard Worker ' to list and show the' 82*288bf522SAndroid Build Coastguard Worker ' predefined perfetto configs.')) 83*288bf522SAndroid Build Coastguard Worker config_subparsers = config_parser.add_subparsers(dest='config_subcommand', 84*288bf522SAndroid Build Coastguard Worker help=('torq config' 85*288bf522SAndroid Build Coastguard Worker ' subcommands')) 86*288bf522SAndroid Build Coastguard Worker config_subparsers.add_parser('list', 87*288bf522SAndroid Build Coastguard Worker help=('Command to list the predefined' 88*288bf522SAndroid Build Coastguard Worker ' perfetto configs')) 89*288bf522SAndroid Build Coastguard Worker config_show_parser = config_subparsers.add_parser('show', 90*288bf522SAndroid Build Coastguard Worker help=('Command to print' 91*288bf522SAndroid Build Coastguard Worker ' the ' 92*288bf522SAndroid Build Coastguard Worker ' perfetto config' 93*288bf522SAndroid Build Coastguard Worker ' in the terminal.')) 94*288bf522SAndroid Build Coastguard Worker config_show_parser.add_argument('config_name', 95*288bf522SAndroid Build Coastguard Worker choices=['lightweight', 'default', 'memory'], 96*288bf522SAndroid Build Coastguard Worker help=('Name of the predefined perfetto' 97*288bf522SAndroid Build Coastguard Worker ' config to print.')) 98*288bf522SAndroid Build Coastguard Worker config_pull_parser = config_subparsers.add_parser('pull', 99*288bf522SAndroid Build Coastguard Worker help=('Command to copy' 100*288bf522SAndroid Build Coastguard Worker ' a predefined config' 101*288bf522SAndroid Build Coastguard Worker ' to the specified' 102*288bf522SAndroid Build Coastguard Worker ' file path.')) 103*288bf522SAndroid Build Coastguard Worker config_pull_parser.add_argument('config_name', 104*288bf522SAndroid Build Coastguard Worker choices=['lightweight', 'default', 'memory'], 105*288bf522SAndroid Build Coastguard Worker help='Name of the predefined config to copy') 106*288bf522SAndroid Build Coastguard Worker config_pull_parser.add_argument('file_path', nargs='?', 107*288bf522SAndroid Build Coastguard Worker help=('File path to copy the predefined' 108*288bf522SAndroid Build Coastguard Worker ' config to')) 109*288bf522SAndroid Build Coastguard Worker open_parser = subparsers.add_parser('open', 110*288bf522SAndroid Build Coastguard Worker help=('The open subcommand is used ' 111*288bf522SAndroid Build Coastguard Worker 'to open trace files in the ' 112*288bf522SAndroid Build Coastguard Worker 'perfetto ui.')) 113*288bf522SAndroid Build Coastguard Worker open_parser.add_argument('file_path', help='Path to trace file.') 114*288bf522SAndroid Build Coastguard Worker return parser 115*288bf522SAndroid Build Coastguard Worker 116*288bf522SAndroid Build Coastguard Worker 117*288bf522SAndroid Build Coastguard Workerdef user_changed_default_arguments(args): 118*288bf522SAndroid Build Coastguard Worker return any([args.event != "custom", 119*288bf522SAndroid Build Coastguard Worker args.profiler != "perfetto", 120*288bf522SAndroid Build Coastguard Worker args.out_dir != DEFAULT_OUT_DIR, 121*288bf522SAndroid Build Coastguard Worker args.dur_ms != DEFAULT_DUR_MS, 122*288bf522SAndroid Build Coastguard Worker args.app is not None, 123*288bf522SAndroid Build Coastguard Worker args.runs != 1, 124*288bf522SAndroid Build Coastguard Worker args.simpleperf_event is not None, 125*288bf522SAndroid Build Coastguard Worker args.perfetto_config != "default", 126*288bf522SAndroid Build Coastguard Worker args.between_dur_ms != DEFAULT_DUR_MS, 127*288bf522SAndroid Build Coastguard Worker args.ui is not None, 128*288bf522SAndroid Build Coastguard Worker args.excluded_ftrace_events is not None, 129*288bf522SAndroid Build Coastguard Worker args.included_ftrace_events is not None, 130*288bf522SAndroid Build Coastguard Worker args.from_user is not None, 131*288bf522SAndroid Build Coastguard Worker args.to_user is not None, 132*288bf522SAndroid Build Coastguard Worker args.serial is not None]) 133*288bf522SAndroid Build Coastguard Worker 134*288bf522SAndroid Build Coastguard Worker 135*288bf522SAndroid Build Coastguard Workerdef verify_args(args): 136*288bf522SAndroid Build Coastguard Worker if (args.subcommands is not None and 137*288bf522SAndroid Build Coastguard Worker user_changed_default_arguments(args)): 138*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 139*288bf522SAndroid Build Coastguard Worker ("Command is invalid because profiler command is followed by a config" 140*288bf522SAndroid Build Coastguard Worker " command."), 141*288bf522SAndroid Build Coastguard Worker "Remove the 'config' subcommand to profile the device instead.") 142*288bf522SAndroid Build Coastguard Worker 143*288bf522SAndroid Build Coastguard Worker if args.out_dir != DEFAULT_OUT_DIR and not os.path.isdir(args.out_dir): 144*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 145*288bf522SAndroid Build Coastguard Worker ("Command is invalid because --out-dir is not a valid directory" 146*288bf522SAndroid Build Coastguard Worker " path: %s." % args.out_dir), None) 147*288bf522SAndroid Build Coastguard Worker 148*288bf522SAndroid Build Coastguard Worker if args.dur_ms < MIN_DURATION_MS: 149*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 150*288bf522SAndroid Build Coastguard Worker ("Command is invalid because --dur-ms cannot be set to a value smaller" 151*288bf522SAndroid Build Coastguard Worker " than %d." % MIN_DURATION_MS), 152*288bf522SAndroid Build Coastguard Worker ("Set --dur-ms %d to capture a trace for %d seconds." 153*288bf522SAndroid Build Coastguard Worker % (MIN_DURATION_MS, (MIN_DURATION_MS / 1000)))) 154*288bf522SAndroid Build Coastguard Worker 155*288bf522SAndroid Build Coastguard Worker if args.from_user is not None and args.event != "user-switch": 156*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 157*288bf522SAndroid Build Coastguard Worker ("Command is invalid because --from-user is passed, but --event is not" 158*288bf522SAndroid Build Coastguard Worker " set to user-switch."), 159*288bf522SAndroid Build Coastguard Worker ("Set --event user-switch --from-user %s to perform a user-switch from" 160*288bf522SAndroid Build Coastguard Worker " user %s." % (args.from_user, args.from_user))) 161*288bf522SAndroid Build Coastguard Worker 162*288bf522SAndroid Build Coastguard Worker if args.to_user is not None and args.event != "user-switch": 163*288bf522SAndroid Build Coastguard Worker return None, ValidationError(( 164*288bf522SAndroid Build Coastguard Worker "Command is invalid because --to-user is passed, but --event is not set" 165*288bf522SAndroid Build Coastguard Worker " to user-switch."), 166*288bf522SAndroid Build Coastguard Worker ("Set --event user-switch --to-user %s to perform a user-switch to user" 167*288bf522SAndroid Build Coastguard Worker " %s." % (args.to_user, args.to_user))) 168*288bf522SAndroid Build Coastguard Worker 169*288bf522SAndroid Build Coastguard Worker if args.event == "user-switch" and args.to_user is None: 170*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 171*288bf522SAndroid Build Coastguard Worker "Command is invalid because --to-user is not passed.", 172*288bf522SAndroid Build Coastguard Worker ("Set --event %s --to-user <user-id> to perform a %s." 173*288bf522SAndroid Build Coastguard Worker % (args.event, args.event))) 174*288bf522SAndroid Build Coastguard Worker 175*288bf522SAndroid Build Coastguard Worker # TODO(b/374313202): Support for simpleperf boot event will 176*288bf522SAndroid Build Coastguard Worker # be added in the future 177*288bf522SAndroid Build Coastguard Worker if args.event == "boot" and args.profiler == "simpleperf": 178*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 179*288bf522SAndroid Build Coastguard Worker "Boot event is not yet implemented for simpleperf.", 180*288bf522SAndroid Build Coastguard Worker "Please try another event.") 181*288bf522SAndroid Build Coastguard Worker 182*288bf522SAndroid Build Coastguard Worker if args.app is not None and args.event != "app-startup": 183*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 184*288bf522SAndroid Build Coastguard Worker ("Command is invalid because --app is passed and --event is not set" 185*288bf522SAndroid Build Coastguard Worker " to app-startup."), 186*288bf522SAndroid Build Coastguard Worker ("To profile an app startup run:" 187*288bf522SAndroid Build Coastguard Worker " torq --event app-startup --app <package-name>")) 188*288bf522SAndroid Build Coastguard Worker 189*288bf522SAndroid Build Coastguard Worker if args.event == "app-startup" and args.app is None: 190*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 191*288bf522SAndroid Build Coastguard Worker "Command is invalid because --app is not passed.", 192*288bf522SAndroid Build Coastguard Worker ("Set --event %s --app <package> to perform an %s." 193*288bf522SAndroid Build Coastguard Worker % (args.event, args.event))) 194*288bf522SAndroid Build Coastguard Worker 195*288bf522SAndroid Build Coastguard Worker if args.runs < 1: 196*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 197*288bf522SAndroid Build Coastguard Worker ("Command is invalid because --runs cannot be set to a value smaller" 198*288bf522SAndroid Build Coastguard Worker " than 1."), None) 199*288bf522SAndroid Build Coastguard Worker 200*288bf522SAndroid Build Coastguard Worker if args.runs > 1 and args.ui: 201*288bf522SAndroid Build Coastguard Worker return None, ValidationError(("Command is invalid because --ui cannot be" 202*288bf522SAndroid Build Coastguard Worker " passed if --runs is set to a value greater" 203*288bf522SAndroid Build Coastguard Worker " than 1."), 204*288bf522SAndroid Build Coastguard Worker ("Set torq -r %d --no-ui to perform %d runs." 205*288bf522SAndroid Build Coastguard Worker % (args.runs, args.runs))) 206*288bf522SAndroid Build Coastguard Worker 207*288bf522SAndroid Build Coastguard Worker if args.simpleperf_event is not None and args.profiler != "simpleperf": 208*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 209*288bf522SAndroid Build Coastguard Worker ("Command is invalid because --simpleperf-event cannot be passed" 210*288bf522SAndroid Build Coastguard Worker " if --profiler is not set to simpleperf."), 211*288bf522SAndroid Build Coastguard Worker ("To capture the simpleperf event run:" 212*288bf522SAndroid Build Coastguard Worker " torq --profiler simpleperf --simpleperf-event %s" 213*288bf522SAndroid Build Coastguard Worker % " --simpleperf-event ".join(args.simpleperf_event))) 214*288bf522SAndroid Build Coastguard Worker 215*288bf522SAndroid Build Coastguard Worker if (args.simpleperf_event is not None and 216*288bf522SAndroid Build Coastguard Worker len(args.simpleperf_event) != len(set(args.simpleperf_event))): 217*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 218*288bf522SAndroid Build Coastguard Worker ("Command is invalid because redundant calls to --simpleperf-event" 219*288bf522SAndroid Build Coastguard Worker " cannot be made."), 220*288bf522SAndroid Build Coastguard Worker ("Only set --simpleperf-event cpu-cycles once if you want" 221*288bf522SAndroid Build Coastguard Worker " to collect cpu-cycles.")) 222*288bf522SAndroid Build Coastguard Worker 223*288bf522SAndroid Build Coastguard Worker if args.perfetto_config != "default": 224*288bf522SAndroid Build Coastguard Worker if args.profiler != "perfetto": 225*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 226*288bf522SAndroid Build Coastguard Worker ("Command is invalid because --perfetto-config cannot be passed" 227*288bf522SAndroid Build Coastguard Worker " if --profiler is not set to perfetto."), 228*288bf522SAndroid Build Coastguard Worker ("Set --profiler perfetto to choose a perfetto-config" 229*288bf522SAndroid Build Coastguard Worker " to use.")) 230*288bf522SAndroid Build Coastguard Worker 231*288bf522SAndroid Build Coastguard Worker if (args.perfetto_config not in PREDEFINED_PERFETTO_CONFIGS and 232*288bf522SAndroid Build Coastguard Worker not os.path.isfile(args.perfetto_config)): 233*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 234*288bf522SAndroid Build Coastguard Worker ("Command is invalid because --perfetto-config is not a valid" 235*288bf522SAndroid Build Coastguard Worker " file path: %s" % args.perfetto_config), 236*288bf522SAndroid Build Coastguard Worker ("Predefined perfetto configs can be used:\n" 237*288bf522SAndroid Build Coastguard Worker "\t torq --perfetto-config %s\n" 238*288bf522SAndroid Build Coastguard Worker "\t A filepath with a config can also be used:\n" 239*288bf522SAndroid Build Coastguard Worker "\t torq --perfetto-config <config-filepath>" 240*288bf522SAndroid Build Coastguard Worker % ("\n\t torq --perfetto-config" 241*288bf522SAndroid Build Coastguard Worker " ".join(PREDEFINED_PERFETTO_CONFIGS.keys())))) 242*288bf522SAndroid Build Coastguard Worker 243*288bf522SAndroid Build Coastguard Worker if args.between_dur_ms < MIN_DURATION_MS: 244*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 245*288bf522SAndroid Build Coastguard Worker ("Command is invalid because --between-dur-ms cannot be set to a" 246*288bf522SAndroid Build Coastguard Worker " smaller value than %d." % MIN_DURATION_MS), 247*288bf522SAndroid Build Coastguard Worker ("Set --between-dur-ms %d to wait %d seconds between" 248*288bf522SAndroid Build Coastguard Worker " each run." % (MIN_DURATION_MS, (MIN_DURATION_MS / 1000)))) 249*288bf522SAndroid Build Coastguard Worker 250*288bf522SAndroid Build Coastguard Worker if args.between_dur_ms != DEFAULT_DUR_MS and args.runs == 1: 251*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 252*288bf522SAndroid Build Coastguard Worker ("Command is invalid because --between-dur-ms cannot be passed" 253*288bf522SAndroid Build Coastguard Worker " if --runs is not a value greater than 1."), 254*288bf522SAndroid Build Coastguard Worker "Set --runs 2 to run 2 tests.") 255*288bf522SAndroid Build Coastguard Worker 256*288bf522SAndroid Build Coastguard Worker if args.excluded_ftrace_events is not None and args.profiler != "perfetto": 257*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 258*288bf522SAndroid Build Coastguard Worker ("Command is invalid because --excluded-ftrace-events cannot be passed" 259*288bf522SAndroid Build Coastguard Worker " if --profiler is not set to perfetto."), 260*288bf522SAndroid Build Coastguard Worker ("Set --profiler perfetto to exclude an ftrace event" 261*288bf522SAndroid Build Coastguard Worker " from perfetto config.")) 262*288bf522SAndroid Build Coastguard Worker 263*288bf522SAndroid Build Coastguard Worker if (args.excluded_ftrace_events is not None and 264*288bf522SAndroid Build Coastguard Worker len(args.excluded_ftrace_events) != len(set( 265*288bf522SAndroid Build Coastguard Worker args.excluded_ftrace_events))): 266*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 267*288bf522SAndroid Build Coastguard Worker ("Command is invalid because duplicate ftrace events cannot be" 268*288bf522SAndroid Build Coastguard Worker " included in --excluded-ftrace-events."), 269*288bf522SAndroid Build Coastguard Worker ("--excluded-ftrace-events should only include one instance of an" 270*288bf522SAndroid Build Coastguard Worker " ftrace event.")) 271*288bf522SAndroid Build Coastguard Worker 272*288bf522SAndroid Build Coastguard Worker if args.included_ftrace_events is not None and args.profiler != "perfetto": 273*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 274*288bf522SAndroid Build Coastguard Worker ("Command is invalid because --included-ftrace-events cannot be passed" 275*288bf522SAndroid Build Coastguard Worker " if --profiler is not set to perfetto."), 276*288bf522SAndroid Build Coastguard Worker ("Set --profiler perfetto to include an ftrace event" 277*288bf522SAndroid Build Coastguard Worker " in perfetto config.")) 278*288bf522SAndroid Build Coastguard Worker 279*288bf522SAndroid Build Coastguard Worker if (args.included_ftrace_events is not None and 280*288bf522SAndroid Build Coastguard Worker len(args.included_ftrace_events) != len(set( 281*288bf522SAndroid Build Coastguard Worker args.included_ftrace_events))): 282*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 283*288bf522SAndroid Build Coastguard Worker ("Command is invalid because duplicate ftrace events cannot be" 284*288bf522SAndroid Build Coastguard Worker " included in --included-ftrace-events."), 285*288bf522SAndroid Build Coastguard Worker ("--included-ftrace-events should only include one instance of an" 286*288bf522SAndroid Build Coastguard Worker " ftrace event.")) 287*288bf522SAndroid Build Coastguard Worker 288*288bf522SAndroid Build Coastguard Worker if (args.included_ftrace_events is not None and 289*288bf522SAndroid Build Coastguard Worker args.excluded_ftrace_events is not None): 290*288bf522SAndroid Build Coastguard Worker ftrace_event_intersection = sorted((set(args.excluded_ftrace_events) & 291*288bf522SAndroid Build Coastguard Worker set(args.included_ftrace_events))) 292*288bf522SAndroid Build Coastguard Worker if len(ftrace_event_intersection): 293*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 294*288bf522SAndroid Build Coastguard Worker ("Command is invalid because ftrace event(s): %s cannot be both" 295*288bf522SAndroid Build Coastguard Worker " included and excluded." % ", ".join(ftrace_event_intersection)), 296*288bf522SAndroid Build Coastguard Worker ("\n\t ".join("Only set --excluded-ftrace-events %s if you want to" 297*288bf522SAndroid Build Coastguard Worker " exclude %s from the config or" 298*288bf522SAndroid Build Coastguard Worker " --included-ftrace-events %s if you want to include %s" 299*288bf522SAndroid Build Coastguard Worker " in the config." 300*288bf522SAndroid Build Coastguard Worker % (event, event, event, event) 301*288bf522SAndroid Build Coastguard Worker for event in ftrace_event_intersection))) 302*288bf522SAndroid Build Coastguard Worker 303*288bf522SAndroid Build Coastguard Worker if args.subcommands == "config" and args.config_subcommand is None: 304*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 305*288bf522SAndroid Build Coastguard Worker ("Command is invalid because torq config cannot be called" 306*288bf522SAndroid Build Coastguard Worker " without a subcommand."), 307*288bf522SAndroid Build Coastguard Worker ("Use one of the following subcommands:\n" 308*288bf522SAndroid Build Coastguard Worker "\t torq config list\n" 309*288bf522SAndroid Build Coastguard Worker "\t torq config show\n" 310*288bf522SAndroid Build Coastguard Worker "\t torq config pull\n")) 311*288bf522SAndroid Build Coastguard Worker 312*288bf522SAndroid Build Coastguard Worker if args.profiler == "simpleperf" and args.simpleperf_event is None: 313*288bf522SAndroid Build Coastguard Worker args.simpleperf_event = ['cpu-cycles'] 314*288bf522SAndroid Build Coastguard Worker 315*288bf522SAndroid Build Coastguard Worker if args.ui is None: 316*288bf522SAndroid Build Coastguard Worker args.ui = args.runs == 1 317*288bf522SAndroid Build Coastguard Worker 318*288bf522SAndroid Build Coastguard Worker if args.subcommands == "config" and args.config_subcommand == "pull": 319*288bf522SAndroid Build Coastguard Worker if args.file_path is None: 320*288bf522SAndroid Build Coastguard Worker args.file_path = "./" + args.config_name + ".pbtxt" 321*288bf522SAndroid Build Coastguard Worker elif not os.path.isfile(args.file_path): 322*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 323*288bf522SAndroid Build Coastguard Worker ("Command is invalid because %s is not a valid filepath." 324*288bf522SAndroid Build Coastguard Worker % args.file_path), 325*288bf522SAndroid Build Coastguard Worker ("A default filepath can be used if you do not specify a file-path:\n" 326*288bf522SAndroid Build Coastguard Worker "\t torq pull default to copy to ./default.pbtxt\n" 327*288bf522SAndroid Build Coastguard Worker "\t torq pull lightweight to copy to ./lightweight.pbtxt\n" 328*288bf522SAndroid Build Coastguard Worker "\t torq pull memory to copy to ./memory.pbtxt")) 329*288bf522SAndroid Build Coastguard Worker 330*288bf522SAndroid Build Coastguard Worker if args.subcommands == "open" and not path_exists(args.file_path): 331*288bf522SAndroid Build Coastguard Worker return None, ValidationError( 332*288bf522SAndroid Build Coastguard Worker "Command is invalid because %s is an invalid file path." 333*288bf522SAndroid Build Coastguard Worker % args.file_path, "Make sure your file exists.") 334*288bf522SAndroid Build Coastguard Worker 335*288bf522SAndroid Build Coastguard Worker if args.profiler == "simpleperf": 336*288bf522SAndroid Build Coastguard Worker args, error = verify_simpleperf_args(args) 337*288bf522SAndroid Build Coastguard Worker if error is not None: 338*288bf522SAndroid Build Coastguard Worker return None, error 339*288bf522SAndroid Build Coastguard Worker else: 340*288bf522SAndroid Build Coastguard Worker args.scripts_path = None 341*288bf522SAndroid Build Coastguard Worker 342*288bf522SAndroid Build Coastguard Worker return args, None 343*288bf522SAndroid Build Coastguard Worker 344*288bf522SAndroid Build Coastguard Worker 345*288bf522SAndroid Build Coastguard Workerdef create_profiler_command(args): 346*288bf522SAndroid Build Coastguard Worker return ProfilerCommand("profiler", args.event, args.profiler, args.out_dir, 347*288bf522SAndroid Build Coastguard Worker args.dur_ms, 348*288bf522SAndroid Build Coastguard Worker args.app, args.runs, args.simpleperf_event, 349*288bf522SAndroid Build Coastguard Worker args.perfetto_config, args.between_dur_ms, 350*288bf522SAndroid Build Coastguard Worker args.ui, args.excluded_ftrace_events, 351*288bf522SAndroid Build Coastguard Worker args.included_ftrace_events, args.from_user, 352*288bf522SAndroid Build Coastguard Worker args.to_user) 353*288bf522SAndroid Build Coastguard Worker 354*288bf522SAndroid Build Coastguard Worker 355*288bf522SAndroid Build Coastguard Workerdef create_config_command(args): 356*288bf522SAndroid Build Coastguard Worker type = "config " + args.config_subcommand 357*288bf522SAndroid Build Coastguard Worker config_name = None 358*288bf522SAndroid Build Coastguard Worker file_path = None 359*288bf522SAndroid Build Coastguard Worker dur_ms = None 360*288bf522SAndroid Build Coastguard Worker excluded_ftrace_events = None 361*288bf522SAndroid Build Coastguard Worker included_ftrace_events = None 362*288bf522SAndroid Build Coastguard Worker if args.config_subcommand == "pull" or args.config_subcommand == "show": 363*288bf522SAndroid Build Coastguard Worker config_name = args.config_name 364*288bf522SAndroid Build Coastguard Worker dur_ms = args.dur_ms 365*288bf522SAndroid Build Coastguard Worker excluded_ftrace_events = args.excluded_ftrace_events 366*288bf522SAndroid Build Coastguard Worker included_ftrace_events = args.included_ftrace_events 367*288bf522SAndroid Build Coastguard Worker if args.config_subcommand == "pull": 368*288bf522SAndroid Build Coastguard Worker file_path = args.file_path 369*288bf522SAndroid Build Coastguard Worker 370*288bf522SAndroid Build Coastguard Worker command = ConfigCommand(type, config_name, file_path, dur_ms, 371*288bf522SAndroid Build Coastguard Worker excluded_ftrace_events, included_ftrace_events) 372*288bf522SAndroid Build Coastguard Worker return command 373*288bf522SAndroid Build Coastguard Worker 374*288bf522SAndroid Build Coastguard Worker 375*288bf522SAndroid Build Coastguard Workerdef get_command_type(args): 376*288bf522SAndroid Build Coastguard Worker command = None 377*288bf522SAndroid Build Coastguard Worker if args.subcommands is None: 378*288bf522SAndroid Build Coastguard Worker command = create_profiler_command(args) 379*288bf522SAndroid Build Coastguard Worker if args.subcommands == "config": 380*288bf522SAndroid Build Coastguard Worker command = create_config_command(args) 381*288bf522SAndroid Build Coastguard Worker if args.subcommands == "open": 382*288bf522SAndroid Build Coastguard Worker command = OpenCommand(args.file_path) 383*288bf522SAndroid Build Coastguard Worker return command 384*288bf522SAndroid Build Coastguard Worker 385*288bf522SAndroid Build Coastguard Worker 386*288bf522SAndroid Build Coastguard Workerdef print_error(error): 387*288bf522SAndroid Build Coastguard Worker print(error.message) 388*288bf522SAndroid Build Coastguard Worker if error.suggestion is not None: 389*288bf522SAndroid Build Coastguard Worker print("Suggestion:\n\t", error.suggestion) 390*288bf522SAndroid Build Coastguard Worker 391*288bf522SAndroid Build Coastguard Worker 392*288bf522SAndroid Build Coastguard Workerdef main(): 393*288bf522SAndroid Build Coastguard Worker parser = create_parser() 394*288bf522SAndroid Build Coastguard Worker args = parser.parse_args() 395*288bf522SAndroid Build Coastguard Worker args, error = verify_args(args) 396*288bf522SAndroid Build Coastguard Worker if error is not None: 397*288bf522SAndroid Build Coastguard Worker print_error(error) 398*288bf522SAndroid Build Coastguard Worker return 399*288bf522SAndroid Build Coastguard Worker command = get_command_type(args) 400*288bf522SAndroid Build Coastguard Worker device = AdbDevice(args.serial) 401*288bf522SAndroid Build Coastguard Worker error = command.execute(device) 402*288bf522SAndroid Build Coastguard Worker if error is not None: 403*288bf522SAndroid Build Coastguard Worker print_error(error) 404*288bf522SAndroid Build Coastguard Worker return 405*288bf522SAndroid Build Coastguard Worker 406*288bf522SAndroid Build Coastguard Worker 407*288bf522SAndroid Build Coastguard Workerif __name__ == '__main__': 408*288bf522SAndroid Build Coastguard Worker main() 409