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