summaryrefslogtreecommitdiffstats
path: root/tools/run-bisect-perf-regression.py
blob: 78e570a788c6a1147593ffac1e82324b916f57d8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#!/usr/bin/env python
# Copyright (c) 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Run Performance Test Bisect Tool

This script is used by a trybot to run the src/tools/bisect-perf-regression.py
script with the parameters specified in run-bisect-perf-regression.cfg. It will
check out a copy of the depot in a subdirectory 'bisect' of the working
directory provided, and run the bisect-perf-regression.py script there.

"""

import imp
import optparse
import os
import subprocess
import sys


def LoadConfigFile(path_to_file):
  """Attempts to load the file 'run-bisect-perf-regression.cfg' as a module
  and grab the global config dict.

  Args:
    path_to_file: Path to the run-bisect-perf-regression.cfg file.

  Returns:
    The config dict which should be formatted as follows:
    {'command': string, 'good_revision': string, 'bad_revision': string
     'metric': string}.
    Returns None on failure.
  """
  try:
    local_vars = {}
    execfile(os.path.join(path_to_file, 'run-bisect-perf-regression.cfg'),
             local_vars)

    return local_vars['config']
  except:
    return None


def RunBisectionScript(config, working_directory, path_to_file, path_to_goma):
  """Attempts to execute src/tools/bisect-perf-regression.py with the parameters
  passed in.

  Args:
    config: A dict containing the parameters to pass to the script.
    working_directory: A working directory to provide to the
      bisect-perf-regression.py script, where it will store it's own copy of
      the depot.
    path_to_file: Path to the bisect-perf-regression.py script.
    path_to_goma: Path to goma directory.

  Returns:
    0 on success, otherwise 1.
  """

  cmd = ['python', os.path.join(path_to_file, 'bisect-perf-regression.py'),
         '-c', config['command'],
         '-g', config['good_revision'],
         '-b', config['bad_revision'],
         '-m', config['metric'],
         '--working_directory', working_directory,
         '--output_buildbot_annotations']

  if config['repeat_count']:
    cmd.extend(['-r', config['repeat_count']])

  if config['truncate_percent']:
    cmd.extend(['-t', config['truncate_percent']])

  if config['max_time_minutes']:
    cmd.extend(['--repeat_test_max_time', config['max_time_minutes']])

  if os.name == 'nt':
    cmd.extend(['--build_preference', 'ninja'])
  else:
    cmd.extend(['--build_preference', 'make'])

  goma_file = ''
  if path_to_goma:
    path_to_goma = os.path.abspath(path_to_goma)

    if os.name == 'nt':
      os.environ['CC'] = os.path.join(path_to_goma, 'gomacc.exe') + ' cl.exe'
      os.environ['CXX'] = os.path.join(path_to_goma, 'gomacc.exe') + ' cl.exe'
      goma_file = os.path.join(path_to_goma, 'goma_ctl.bat')
    else:
      os.environ['PATH'] = os.pathsep.join([path_to_goma, os.environ['PATH']])
      goma_file = os.path.join(path_to_goma, 'goma_ctl.sh')

    cmd.append('--use_goma')

    # Sometimes goma is lingering around if something went bad on a previous
    # run. Stop it before starting a new process. Can ignore the return code
    # since it will return an error if it wasn't running.
    subprocess.call([goma_file, 'stop'])

    return_code = subprocess.call([goma_file, 'start'])
    if return_code:
      print 'Error: goma failed to start.'
      print
      return return_code

  cmd = [str(c) for c in cmd]

  return_code = subprocess.call(cmd)

  if path_to_goma:
    subprocess.call([goma_file, 'stop'])

  if return_code:
    print 'Error: bisect-perf-regression.py returned with error %d' %\
        return_code
    print

  return return_code


def main():

  usage = ('%prog [options] [-- chromium-options]\n'
           'Used by a trybot to run the bisection script using the parameters'
           ' provided in the run-bisect-perf-regression.cfg file.')

  parser = optparse.OptionParser(usage=usage)
  parser.add_option('-w', '--working_directory',
                    type='str',
                    help='A working directory to supply to the bisection '
                    'script, which will use it as the location to checkout '
                    'a copy of the chromium depot.')
  parser.add_option('-p', '--path_to_goma',
                    type='str',
                    help='Path to goma directory. If this is supplied, goma '
                    'builds will be enabled.')
  (opts, args) = parser.parse_args()

  if not opts.working_directory:
    print 'Error: missing required parameter: --working_directory'
    print
    parser.print_help()
    return 1

  path_to_file = os.path.abspath(os.path.dirname(sys.argv[0]))

  config = LoadConfigFile(path_to_file)
  if not config:
    print 'Error: Could not load config file.'
    print
    return 1

  return RunBisectionScript(config, opts.working_directory, path_to_file,
                            opts.path_to_goma)


if __name__ == '__main__':
  sys.exit(main())