1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# Copyright 2011 The ChromiumOS Authors 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7"""The driver script for running performance benchmarks on ChromeOS.""" 8 9 10import argparse 11import atexit 12import os 13import signal 14import sys 15 16# This import causes pylint to warn about "No name 'logger' in module 17# 'cros_utils'". I do not understand why. The import works fine in python. 18# pylint: disable=no-name-in-module 19from cros_utils import logger 20from experiment_factory import ExperimentFactory 21from experiment_file import ExperimentFile 22from experiment_runner import ExperimentRunner 23from experiment_runner import MockExperimentRunner 24from settings_factory import GlobalSettings 25import test_flag 26 27 28HAS_FAILURE = 1 29ALL_FAILED = 2 30 31 32def SetupParserOptions(parser): 33 """Add all options to the parser.""" 34 parser.add_argument( 35 "--dry_run", 36 dest="dry_run", 37 help=("Parse the experiment file and " "show what will be done"), 38 action="store_true", 39 default=False, 40 ) 41 # Allow each of the global fields to be overridden by passing in 42 # options. Add each global field as an option. 43 option_settings = GlobalSettings("") 44 for field_name in option_settings.fields: 45 field = option_settings.fields[field_name] 46 parser.add_argument( 47 "--%s" % field.name, 48 dest=field.name, 49 help=field.description, 50 action="store", 51 ) 52 53 54def ConvertOptionsToSettings(options): 55 """Convert options passed in into global settings.""" 56 option_settings = GlobalSettings("option_settings") 57 for option_name in options.__dict__: 58 if ( 59 options.__dict__[option_name] is not None 60 and option_name in option_settings.fields 61 ): 62 option_settings.SetField(option_name, options.__dict__[option_name]) 63 return option_settings 64 65 66def Cleanup(experiment): 67 """Handler function which is registered to the atexit handler.""" 68 experiment.Cleanup() 69 70 71def CallExitHandler(signum, _): 72 """Signal handler that transforms a signal into a call to exit. 73 74 This is useful because functionality registered by "atexit" will 75 be called. It also means you can "catch" the signal by catching 76 the SystemExit exception. 77 """ 78 sys.exit(128 + signum) 79 80 81def RunCrosperf(argv): 82 parser = argparse.ArgumentParser() 83 84 parser.add_argument( 85 "--noschedv2", 86 dest="noschedv2", 87 default=False, 88 action="store_true", 89 help=("Do not use new scheduler. " "Use original scheduler instead."), 90 ) 91 parser.add_argument( 92 "-l", 93 "--log_dir", 94 dest="log_dir", 95 default="", 96 help="The log_dir, default is under <crosperf_logs>/logs", 97 ) 98 99 SetupParserOptions(parser) 100 options, args = parser.parse_known_args(argv) 101 102 # Convert the relevant options that are passed in into a settings 103 # object which will override settings in the experiment file. 104 option_settings = ConvertOptionsToSettings(options) 105 log_dir = os.path.abspath(os.path.expanduser(options.log_dir)) 106 logger.GetLogger(log_dir) 107 108 if len(args) == 2: 109 experiment_filename = args[1] 110 else: 111 parser.error("Invalid number arguments.") 112 113 working_directory = os.getcwd() 114 if options.dry_run: 115 test_flag.SetTestMode(True) 116 117 experiment_file = ExperimentFile( 118 open(experiment_filename, encoding="utf-8"), option_settings 119 ) 120 if not experiment_file.GetGlobalSettings().GetField("name"): 121 experiment_name = os.path.basename(experiment_filename) 122 experiment_file.GetGlobalSettings().SetField("name", experiment_name) 123 experiment = ExperimentFactory().GetExperiment( 124 experiment_file, working_directory, log_dir 125 ) 126 127 json_report = experiment_file.GetGlobalSettings().GetField("json_report") 128 129 signal.signal(signal.SIGTERM, CallExitHandler) 130 atexit.register(Cleanup, experiment) 131 132 if options.dry_run: 133 runner = MockExperimentRunner(experiment, json_report) 134 else: 135 runner = ExperimentRunner( 136 experiment, json_report, using_schedv2=(not options.noschedv2) 137 ) 138 139 ret = runner.Run() 140 if ret == HAS_FAILURE: 141 raise RuntimeError("One or more benchmarks failed.") 142 if ret == ALL_FAILED: 143 raise RuntimeError("All benchmarks failed to run.") 144 145 146def Main(argv): 147 try: 148 RunCrosperf(argv) 149 except Exception: 150 # Flush buffers before exiting to avoid out of order printing 151 sys.stdout.flush() 152 # Raise exception prints out traceback 153 raise 154 155 156if __name__ == "__main__": 157 Main(sys.argv) 158