Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(163)

Side by Side Diff: tools/telemetry/telemetry/test_runner.py

Issue 432543003: Add usage message with available page_sets and benchmarks. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: address comments Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright 2013 The Chromium Authors. All rights reserved. 1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """Parses the command line, discovers the appropriate tests, and runs them. 5 """Parses the command line, discovers the appropriate tests, and runs them.
6 6
7 Handles test configuration, but all the logic for 7 Handles test configuration, but all the logic for
8 actually running the test is in Test and PageRunner.""" 8 actually running the test is in Test and PageRunner."""
9 9
10 import hashlib 10 import hashlib
11 import inspect 11 import inspect
12 import json 12 import json
13 import os 13 import os
14 import sys 14 import sys
15 15
16 from telemetry import benchmark 16 from telemetry import benchmark
17 from telemetry import decorators 17 from telemetry import decorators
18 from telemetry.core import browser_finder 18 from telemetry.core import browser_finder
19 from telemetry.core import browser_options 19 from telemetry.core import browser_options
20 from telemetry.core import command_line 20 from telemetry.core import command_line
21 from telemetry.core import discover 21 from telemetry.core import discover
22 from telemetry.core import environment
23 from telemetry.core import util
24 from telemetry.page import page_set 22 from telemetry.page import page_set
25 from telemetry.page import page_test 23 from telemetry.page import page_test
26 from telemetry.page import profile_creator
27 from telemetry.util import find_dependencies 24 from telemetry.util import find_dependencies
28 25
29 26
27 test_class_types = [benchmark.Benchmark, page_test.PageTest]
nednguyen 2014/09/04 03:31:37 May better be explicit about this: _BENCHMARK_AND_
28
29
30 class Deps(find_dependencies.FindDependenciesCommand): 30 class Deps(find_dependencies.FindDependenciesCommand):
31 """Prints all dependencies""" 31 """Prints all dependencies"""
32 32
33 def Run(self, args): 33 def Run(self, args):
34 main_module = sys.modules['__main__'] 34 main_module = sys.modules['__main__']
35 args.positional_args.append(os.path.realpath(main_module.__file__)) 35 args.positional_args.append(os.path.realpath(main_module.__file__))
36 return super(Deps, self).Run(args) 36 return super(Deps, self).Run(args)
37 37
38 38
39 class Help(command_line.OptparseCommand): 39 class Help(command_line.OptparseCommand):
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 return parser 73 return parser
74 74
75 @classmethod 75 @classmethod
76 def AddCommandLineArgs(cls, parser): 76 def AddCommandLineArgs(cls, parser):
77 parser.add_option('-j', '--json-output-file', type='string') 77 parser.add_option('-j', '--json-output-file', type='string')
78 parser.add_option('-n', '--num-shards', type='int', default=1) 78 parser.add_option('-n', '--num-shards', type='int', default=1)
79 79
80 @classmethod 80 @classmethod
81 def ProcessCommandLineArgs(cls, parser, args): 81 def ProcessCommandLineArgs(cls, parser, args):
82 if not args.positional_args: 82 if not args.positional_args:
83 args.tests = _Tests() 83 args.tests = _GetAllTests()
84 elif len(args.positional_args) == 1: 84 elif len(args.positional_args) == 1:
85 args.tests = _MatchTestName(args.positional_args[0], exact_matches=False) 85 args.tests = _MatchTestName(args.positional_args[0], exact_matches=False)
86 else: 86 else:
87 parser.error('Must provide at most one test name.') 87 parser.error('Must provide at most one test name.')
88 88
89 def Run(self, args): 89 def Run(self, args):
90 if args.json_output_file: 90 if args.json_output_file:
91 possible_browser = browser_finder.FindBrowser(args) 91 possible_browser = browser_finder.FindBrowser(args)
92 with open(args.json_output_file, 'w') as f: 92 with open(args.json_output_file, 'w') as f:
93 f.write(_GetJsonTestList(possible_browser, args.tests, args.num_shards)) 93 f.write(_GetJsonTestList(possible_browser, args.tests, args.num_shards))
(...skipping 26 matching lines...) Expand all
120 # TODO(dtu): After move to argparse, add command-line args for all tests 120 # TODO(dtu): After move to argparse, add command-line args for all tests
121 # to subparser. Using subparsers will avoid duplicate arguments. 121 # to subparser. Using subparsers will avoid duplicate arguments.
122 matching_test = matching_tests.pop() 122 matching_test = matching_tests.pop()
123 matching_test.AddCommandLineArgs(parser) 123 matching_test.AddCommandLineArgs(parser)
124 # The test's options override the defaults! 124 # The test's options override the defaults!
125 matching_test.SetArgumentDefaults(parser) 125 matching_test.SetArgumentDefaults(parser)
126 126
127 @classmethod 127 @classmethod
128 def ProcessCommandLineArgs(cls, parser, args): 128 def ProcessCommandLineArgs(cls, parser, args):
129 if not args.positional_args: 129 if not args.positional_args:
130 _PrintTestList(_Tests()) 130 _PrintTestList(output_stream=sys.stderr)
131 sys.exit(-1) 131 sys.exit(-1)
132 132
133 input_test_name = args.positional_args[0] 133 input_test_name = args.positional_args[0]
134 matching_tests = _MatchTestName(input_test_name) 134 matching_tests = _MatchTestName(input_test_name)
135 if not matching_tests: 135 if not matching_tests:
136 print >> sys.stderr, 'No test named "%s".' % input_test_name 136 print >> sys.stderr, 'No test named "%s".' % input_test_name
137 print >> sys.stderr 137 print >> sys.stderr
138 _PrintTestList(_Tests()) 138 _PrintTestList(output_stream=sys.stderr)
139 sys.exit(-1) 139 sys.exit(-1)
140 140
141 if len(matching_tests) > 1: 141 if len(matching_tests) > 1:
142 print >> sys.stderr, 'Multiple tests named "%s".' % input_test_name 142 print >> sys.stderr, 'Multiple tests named "%s".' % input_test_name
143 print >> sys.stderr, 'Did you mean one of these?' 143 print >> sys.stderr, 'Did you mean one of these?'
144 print >> sys.stderr 144 print >> sys.stderr
145 _PrintTestList(matching_tests) 145 _PrintTestList(matching_tests, output_stream=sys.stderr)
146 sys.exit(-1) 146 sys.exit(-1)
147 147
148 test_class = matching_tests.pop() 148 test_class = matching_tests.pop()
149 if issubclass(test_class, page_test.PageTest): 149 if issubclass(test_class, page_test.PageTest):
150 if len(args.positional_args) < 2: 150 if len(args.positional_args) < 2:
151 parser.error('Need to specify a page set for "%s".' % test_class.Name()) 151 parser.error('Need to specify a page set for "%s".' % test_class.Name())
152 if len(args.positional_args) > 2: 152 if len(args.positional_args) > 2:
153 parser.error('Too many arguments.') 153 parser.error('Too many arguments.')
154 page_set_path = args.positional_args[1] 154 page_set_path = args.positional_args[1]
155 if not os.path.exists(page_set_path): 155 if not os.path.exists(page_set_path):
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
188 188
189 def _Commands(): 189 def _Commands():
190 """Generates a list of all classes in this file that subclass Command.""" 190 """Generates a list of all classes in this file that subclass Command."""
191 for _, cls in inspect.getmembers(sys.modules[__name__]): 191 for _, cls in inspect.getmembers(sys.modules[__name__]):
192 if not inspect.isclass(cls): 192 if not inspect.isclass(cls):
193 continue 193 continue
194 if not issubclass(cls, command_line.Command): 194 if not issubclass(cls, command_line.Command):
195 continue 195 continue
196 yield cls 196 yield cls
197 197
198
198 def _MatchingCommands(string): 199 def _MatchingCommands(string):
199 return [command for command in _Commands() 200 return [command for command in _Commands()
200 if command.Name().startswith(string)] 201 if command.Name().startswith(string)]
201 202
202 @decorators.Cache 203
203 def _Tests(): 204 def _GetAllTests():
204 tests = [] 205 return discover.GetValidSubclassesOfClasses(test_class_types)
205 for base_dir in config.base_paths:
206 tests += discover.DiscoverClasses(base_dir, base_dir, benchmark.Benchmark,
207 index_by_class_name=True).values()
208 page_tests = discover.DiscoverClasses(base_dir, base_dir,
209 page_test.PageTest,
210 index_by_class_name=True).values()
211 tests += [test_class for test_class in page_tests
212 if not issubclass(test_class, profile_creator.ProfileCreator)]
213 return tests
214 206
215 207
216 def _MatchTestName(input_test_name, exact_matches=True): 208 def _MatchTestName(input_name, exact_matches=True):
217 def _Matches(input_string, search_string): 209 return discover.MatchName(test_class_types, input_name, exact_matches)
218 if search_string.startswith(input_string):
219 return True
220 for part in search_string.split('.'):
221 if part.startswith(input_string):
222 return True
223 return False
224 210
225 # Exact matching.
226 if exact_matches:
227 # Don't add aliases to search dict, only allow exact matching for them.
228 if input_test_name in config.test_aliases:
229 exact_match = config.test_aliases[input_test_name]
230 else:
231 exact_match = input_test_name
232 211
233 for test_class in _Tests(): 212 def _PrintTestList(class_list=None, output_stream=sys.stdout):
234 if exact_match == test_class.Name(): 213 discover.PrintAvailableClasses(test_class_types, class_list, output_stream)
235 return [test_class]
236
237 # Fuzzy matching.
238 return [test_class for test_class in _Tests()
239 if _Matches(input_test_name, test_class.Name())]
240 214
241 215
242 def _GetJsonTestList(possible_browser, test_classes, num_shards): 216 def _GetJsonTestList(possible_browser, test_classes, num_shards):
243 """Returns a list of all enabled tests in a JSON format expected by buildbots. 217 """Returns a list of all enabled tests in a JSON format expected by buildbots.
244 218
245 JSON format (see build/android/pylib/perf/test_runner.py): 219 JSON format (see build/android/pylib/perf/test_runner.py):
246 { "version": int, 220 { "version": int,
247 "steps": { 221 "steps": {
248 "foo": { 222 "foo": {
249 "device_affinity": int, 223 "device_affinity": int,
(...skipping 24 matching lines...) Expand all
274 # TODO(tonyg): Currently we set the device affinity to a stable hash of 248 # TODO(tonyg): Currently we set the device affinity to a stable hash of
275 # the test name. This somewhat evenly distributes benchmarks among the 249 # the test name. This somewhat evenly distributes benchmarks among the
276 # requested number of shards. However, it is far from optimal in terms of 250 # requested number of shards. However, it is far from optimal in terms of
277 # cycle time. We should add a test size decorator (e.g. small, medium, 251 # cycle time. We should add a test size decorator (e.g. small, medium,
278 # large) and let that inform sharding. 252 # large) and let that inform sharding.
279 'device_affinity': int(hashlib.sha1(name).hexdigest(), 16) % num_shards 253 'device_affinity': int(hashlib.sha1(name).hexdigest(), 16) % num_shards
280 } 254 }
281 return json.dumps(output, indent=2, sort_keys=True) 255 return json.dumps(output, indent=2, sort_keys=True)
282 256
283 257
284 def _PrintTestList(tests):
285 if not tests:
286 print >> sys.stderr, 'No tests found!'
287 return
288
289 # Align the test names to the longest one.
290 format_string = ' %%-%ds %%s' % max(len(t.Name()) for t in tests)
291
292 filtered_tests = [test_class for test_class in tests
293 if issubclass(test_class, benchmark.Benchmark)]
294 if filtered_tests:
295 print >> sys.stderr, 'Available tests are:'
296 for test_class in sorted(filtered_tests, key=lambda t: t.Name()):
297 print >> sys.stderr, format_string % (
298 test_class.Name(), test_class.Description())
299 print >> sys.stderr
300
301 filtered_tests = [test_class for test_class in tests
302 if issubclass(test_class, page_test.PageTest)]
303 if filtered_tests:
304 print >> sys.stderr, 'Available page tests are:'
305 for test_class in sorted(filtered_tests, key=lambda t: t.Name()):
306 print >> sys.stderr, format_string % (
307 test_class.Name(), test_class.Description())
308 print >> sys.stderr
309
310
311 config = environment.Environment([util.GetBaseDir()])
312
313
314 def main(): 258 def main():
315 # Get the command name from the command line. 259 # Get the command name from the command line.
316 if len(sys.argv) > 1 and sys.argv[1] == '--help': 260 if len(sys.argv) > 1 and sys.argv[1] == '--help':
317 sys.argv[1] = 'help' 261 sys.argv[1] = 'help'
318 262
319 command_name = 'run' 263 command_name = 'run'
320 for arg in sys.argv[1:]: 264 for arg in sys.argv[1:]:
321 if not arg.startswith('-'): 265 if not arg.startswith('-'):
322 command_name = arg 266 command_name = arg
323 break 267 break
(...skipping 14 matching lines...) Expand all
338 282
339 # Parse and run the command. 283 # Parse and run the command.
340 parser = command.CreateParser() 284 parser = command.CreateParser()
341 command.AddCommandLineArgs(parser) 285 command.AddCommandLineArgs(parser)
342 options, args = parser.parse_args() 286 options, args = parser.parse_args()
343 if commands: 287 if commands:
344 args = args[1:] 288 args = args[1:]
345 options.positional_args = args 289 options.positional_args = args
346 command.ProcessCommandLineArgs(parser, options) 290 command.ProcessCommandLineArgs(parser, options)
347 return command().Run(options) 291 return command().Run(options)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698