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