OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2014 the V8 project authors. All rights reserved. | 2 # Copyright 2014 the V8 project authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """ | 6 """ |
7 Performance runner for d8. | 7 Performance runner for d8. |
8 | 8 |
9 Call e.g. with tools/run-perf.py --arch ia32 some_suite.json | 9 Call e.g. with tools/run-perf.py --arch ia32 some_suite.json |
10 | 10 |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
162 | 162 |
163 def __add__(self, other): | 163 def __add__(self, other): |
164 self.traces += other.traces | 164 self.traces += other.traces |
165 self.errors += other.errors | 165 self.errors += other.errors |
166 return self | 166 return self |
167 | 167 |
168 def __str__(self): # pragma: no cover | 168 def __str__(self): # pragma: no cover |
169 return str(self.ToDict()) | 169 return str(self.ToDict()) |
170 | 170 |
171 | 171 |
| 172 class Measurement(object): |
| 173 """Represents a series of results of one trace. |
| 174 |
| 175 The results are from repetitive runs of the same executable. They are |
| 176 gathered by repeated calls to ConsumeOutput. |
| 177 """ |
| 178 def __init__(self, graphs, units, results_regexp, stddev_regexp): |
| 179 self.name = graphs[-1] |
| 180 self.graphs = graphs |
| 181 self.units = units |
| 182 self.results_regexp = results_regexp |
| 183 self.stddev_regexp = stddev_regexp |
| 184 self.results = [] |
| 185 self.errors = [] |
| 186 self.stddev = "" |
| 187 |
| 188 def ConsumeOutput(self, stdout): |
| 189 try: |
| 190 result = re.search(self.results_regexp, stdout, re.M).group(1) |
| 191 self.results.append(str(float(result))) |
| 192 except ValueError: |
| 193 self.errors.append("Regexp \"%s\" returned a non-numeric for test %s." |
| 194 % (self.results_regexp, self.name)) |
| 195 except: |
| 196 self.errors.append("Regexp \"%s\" didn't match for test %s." |
| 197 % (self.results_regexp, self.name)) |
| 198 |
| 199 try: |
| 200 if self.stddev_regexp and self.stddev: |
| 201 self.errors.append("Test %s should only run once since a stddev " |
| 202 "is provided by the test." % self.name) |
| 203 if self.stddev_regexp: |
| 204 self.stddev = re.search(self.stddev_regexp, stdout, re.M).group(1) |
| 205 except: |
| 206 self.errors.append("Regexp \"%s\" didn't match for test %s." |
| 207 % (self.stddev_regexp, self.name)) |
| 208 |
| 209 def GetResults(self): |
| 210 return Results([{ |
| 211 "graphs": self.graphs, |
| 212 "units": self.units, |
| 213 "results": self.results, |
| 214 "stddev": self.stddev, |
| 215 }], self.errors) |
| 216 |
| 217 |
| 218 def AccumulateResults(graph_names, trace_configs, iter_output, calc_total): |
| 219 """Iterates over the output of multiple benchmark reruns and accumulates |
| 220 results for a configured list of traces. |
| 221 |
| 222 Args: |
| 223 graph_names: List of names that configure the base path of the traces. E.g. |
| 224 ['v8', 'Octane']. |
| 225 trace_configs: List of "TraceConfig" instances. Each trace config defines |
| 226 how to perform a measurement. |
| 227 iter_output: Iterator over the standard output of each test run. |
| 228 calc_total: Boolean flag to speficy the calculation of a summary trace. |
| 229 Returns: A "Results" object. |
| 230 """ |
| 231 measurements = [trace.CreateMeasurement() for trace in trace_configs] |
| 232 for stdout in iter_output(): |
| 233 for measurement in measurements: |
| 234 measurement.ConsumeOutput(stdout) |
| 235 |
| 236 res = reduce(lambda r, m: r + m.GetResults(), measurements, Results()) |
| 237 |
| 238 if not res.traces or not calc_total: |
| 239 return res |
| 240 |
| 241 # Assume all traces have the same structure. |
| 242 if len(set(map(lambda t: len(t["results"]), res.traces))) != 1: |
| 243 res.errors.append("Not all traces have the same number of results.") |
| 244 return res |
| 245 |
| 246 # Calculate the geometric means for all traces. Above we made sure that |
| 247 # there is at least one trace and that the number of results is the same |
| 248 # for each trace. |
| 249 n_results = len(res.traces[0]["results"]) |
| 250 total_results = [GeometricMean(t["results"][i] for t in res.traces) |
| 251 for i in range(0, n_results)] |
| 252 res.traces.append({ |
| 253 "graphs": graph_names + ["Total"], |
| 254 "units": res.traces[0]["units"], |
| 255 "results": total_results, |
| 256 "stddev": "", |
| 257 }) |
| 258 return res |
| 259 |
| 260 |
| 261 def AccumulateGenericResults(graph_names, suite_units, iter_output): |
| 262 """Iterates over the output of multiple benchmark reruns and accumulates |
| 263 generic results. |
| 264 |
| 265 Args: |
| 266 graph_names: List of names that configure the base path of the traces. E.g. |
| 267 ['v8', 'Octane']. |
| 268 suite_units: Measurement default units as defined by the benchmark suite. |
| 269 iter_output: Iterator over the standard output of each test run. |
| 270 Returns: A "Results" object. |
| 271 """ |
| 272 traces = OrderedDict() |
| 273 for stdout in iter_output(): |
| 274 for line in stdout.strip().splitlines(): |
| 275 match = GENERIC_RESULTS_RE.match(line) |
| 276 if match: |
| 277 stddev = "" |
| 278 graph = match.group(1) |
| 279 trace = match.group(2) |
| 280 body = match.group(3) |
| 281 units = match.group(4) |
| 282 match_stddev = RESULT_STDDEV_RE.match(body) |
| 283 match_list = RESULT_LIST_RE.match(body) |
| 284 errors = [] |
| 285 if match_stddev: |
| 286 result, stddev = map(str.strip, match_stddev.group(1).split(",")) |
| 287 results = [result] |
| 288 elif match_list: |
| 289 results = map(str.strip, match_list.group(1).split(",")) |
| 290 else: |
| 291 results = [body.strip()] |
| 292 |
| 293 try: |
| 294 results = map(lambda r: str(float(r)), results) |
| 295 except ValueError: |
| 296 results = [] |
| 297 errors = ["Found non-numeric in %s" % |
| 298 "/".join(graph_names + [graph, trace])] |
| 299 |
| 300 trace_result = traces.setdefault(trace, Results([{ |
| 301 "graphs": graph_names + [graph, trace], |
| 302 "units": (units or suite_units).strip(), |
| 303 "results": [], |
| 304 "stddev": "", |
| 305 }], errors)) |
| 306 trace_result.traces[0]["results"].extend(results) |
| 307 trace_result.traces[0]["stddev"] = stddev |
| 308 |
| 309 return reduce(lambda r, t: r + t, traces.itervalues(), Results()) |
| 310 |
| 311 |
172 class Node(object): | 312 class Node(object): |
173 """Represents a node in the suite tree structure.""" | 313 """Represents a node in the suite tree structure.""" |
174 def __init__(self, *args): | 314 def __init__(self, *args): |
175 self._children = [] | 315 self._children = [] |
176 | 316 |
177 def AppendChild(self, child): | 317 def AppendChild(self, child): |
178 self._children.append(child) | 318 self._children.append(child) |
179 | 319 |
180 | 320 |
181 class DefaultSentinel(Node): | 321 class DefaultSentinel(Node): |
182 """Fake parent node with all default values.""" | 322 """Fake parent node with all default values.""" |
183 def __init__(self): | 323 def __init__(self): |
184 super(DefaultSentinel, self).__init__() | 324 super(DefaultSentinel, self).__init__() |
185 self.binary = "d8" | 325 self.binary = "d8" |
186 self.run_count = 10 | 326 self.run_count = 10 |
187 self.timeout = 60 | 327 self.timeout = 60 |
188 self.path = [] | 328 self.path = [] |
189 self.graphs = [] | 329 self.graphs = [] |
190 self.flags = [] | 330 self.flags = [] |
191 self.test_flags = [] | 331 self.test_flags = [] |
192 self.resources = [] | 332 self.resources = [] |
193 self.results_regexp = None | 333 self.results_regexp = None |
194 self.stddev_regexp = None | 334 self.stddev_regexp = None |
195 self.units = "score" | 335 self.units = "score" |
196 self.total = False | 336 self.total = False |
197 | 337 |
198 | 338 |
199 class Graph(Node): | 339 class GraphConfig(Node): |
200 """Represents a suite definition. | 340 """Represents a suite definition. |
201 | 341 |
202 Can either be a leaf or an inner node that provides default values. | 342 Can either be a leaf or an inner node that provides default values. |
203 """ | 343 """ |
204 def __init__(self, suite, parent, arch): | 344 def __init__(self, suite, parent, arch): |
205 super(Graph, self).__init__() | 345 super(GraphConfig, self).__init__() |
206 self._suite = suite | 346 self._suite = suite |
207 | 347 |
208 assert isinstance(suite.get("path", []), list) | 348 assert isinstance(suite.get("path", []), list) |
209 assert isinstance(suite["name"], basestring) | 349 assert isinstance(suite["name"], basestring) |
210 assert isinstance(suite.get("flags", []), list) | 350 assert isinstance(suite.get("flags", []), list) |
211 assert isinstance(suite.get("test_flags", []), list) | 351 assert isinstance(suite.get("test_flags", []), list) |
212 assert isinstance(suite.get("resources", []), list) | 352 assert isinstance(suite.get("resources", []), list) |
213 | 353 |
214 # Accumulated values. | 354 # Accumulated values. |
215 self.path = parent.path[:] + suite.get("path", []) | 355 self.path = parent.path[:] + suite.get("path", []) |
(...skipping 25 matching lines...) Expand all Loading... |
241 self.results_regexp = suite.get("results_regexp", regexp_default) | 381 self.results_regexp = suite.get("results_regexp", regexp_default) |
242 | 382 |
243 # A similar regular expression for the standard deviation (optional). | 383 # A similar regular expression for the standard deviation (optional). |
244 if parent.stddev_regexp: | 384 if parent.stddev_regexp: |
245 stddev_default = parent.stddev_regexp % re.escape(suite["name"]) | 385 stddev_default = parent.stddev_regexp % re.escape(suite["name"]) |
246 else: | 386 else: |
247 stddev_default = None | 387 stddev_default = None |
248 self.stddev_regexp = suite.get("stddev_regexp", stddev_default) | 388 self.stddev_regexp = suite.get("stddev_regexp", stddev_default) |
249 | 389 |
250 | 390 |
251 class Trace(Graph): | 391 class TraceConfig(GraphConfig): |
252 """Represents a leaf in the suite tree structure. | 392 """Represents a leaf in the suite tree structure.""" |
| 393 def __init__(self, suite, parent, arch): |
| 394 super(TraceConfig, self).__init__(suite, parent, arch) |
| 395 assert self.results_regexp |
253 | 396 |
254 Handles collection of measurements. | 397 def CreateMeasurement(self): |
255 """ | 398 return Measurement( |
256 def __init__(self, suite, parent, arch): | 399 self.graphs, |
257 super(Trace, self).__init__(suite, parent, arch) | 400 self.units, |
258 assert self.results_regexp | 401 self.results_regexp, |
259 self.results = [] | 402 self.stddev_regexp, |
260 self.errors = [] | 403 ) |
261 self.stddev = "" | |
262 | |
263 def ConsumeOutput(self, stdout): | |
264 try: | |
265 result = re.search(self.results_regexp, stdout, re.M).group(1) | |
266 self.results.append(str(float(result))) | |
267 except ValueError: | |
268 self.errors.append("Regexp \"%s\" returned a non-numeric for test %s." | |
269 % (self.results_regexp, self.graphs[-1])) | |
270 except: | |
271 self.errors.append("Regexp \"%s\" didn't match for test %s." | |
272 % (self.results_regexp, self.graphs[-1])) | |
273 | |
274 try: | |
275 if self.stddev_regexp and self.stddev: | |
276 self.errors.append("Test %s should only run once since a stddev " | |
277 "is provided by the test." % self.graphs[-1]) | |
278 if self.stddev_regexp: | |
279 self.stddev = re.search(self.stddev_regexp, stdout, re.M).group(1) | |
280 except: | |
281 self.errors.append("Regexp \"%s\" didn't match for test %s." | |
282 % (self.stddev_regexp, self.graphs[-1])) | |
283 | |
284 def GetResults(self): | |
285 return Results([{ | |
286 "graphs": self.graphs, | |
287 "units": self.units, | |
288 "results": self.results, | |
289 "stddev": self.stddev, | |
290 }], self.errors) | |
291 | 404 |
292 | 405 |
293 class Runnable(Graph): | 406 class RunnableConfig(GraphConfig): |
294 """Represents a runnable suite definition (i.e. has a main file). | 407 """Represents a runnable suite definition (i.e. has a main file). |
295 """ | 408 """ |
296 @property | 409 @property |
297 def main(self): | 410 def main(self): |
298 return self._suite.get("main", "") | 411 return self._suite.get("main", "") |
299 | 412 |
300 def ChangeCWD(self, suite_path): | 413 def ChangeCWD(self, suite_path): |
301 """Changes the cwd to to path defined in the current graph. | 414 """Changes the cwd to to path defined in the current graph. |
302 | 415 |
303 The tests are supposed to be relative to the suite configuration. | 416 The tests are supposed to be relative to the suite configuration. |
304 """ | 417 """ |
305 suite_dir = os.path.abspath(os.path.dirname(suite_path)) | 418 suite_dir = os.path.abspath(os.path.dirname(suite_path)) |
306 bench_dir = os.path.normpath(os.path.join(*self.path)) | 419 bench_dir = os.path.normpath(os.path.join(*self.path)) |
307 os.chdir(os.path.join(suite_dir, bench_dir)) | 420 os.chdir(os.path.join(suite_dir, bench_dir)) |
308 | 421 |
309 def GetCommandFlags(self, extra_flags=None): | 422 def GetCommandFlags(self, extra_flags=None): |
310 suffix = ["--"] + self.test_flags if self.test_flags else [] | 423 suffix = ["--"] + self.test_flags if self.test_flags else [] |
311 return self.flags + (extra_flags or []) + [self.main] + suffix | 424 return self.flags + (extra_flags or []) + [self.main] + suffix |
312 | 425 |
313 def GetCommand(self, shell_dir, extra_flags=None): | 426 def GetCommand(self, shell_dir, extra_flags=None): |
314 # TODO(machenbach): This requires +.exe if run on windows. | 427 # TODO(machenbach): This requires +.exe if run on windows. |
315 cmd = [os.path.join(shell_dir, self.binary)] | 428 cmd = [os.path.join(shell_dir, self.binary)] |
316 return cmd + self.GetCommandFlags(extra_flags=extra_flags) | 429 return cmd + self.GetCommandFlags(extra_flags=extra_flags) |
317 | 430 |
318 def Run(self, runner): | 431 def Run(self, runner): |
319 """Iterates over several runs and handles the output for all traces.""" | 432 """Iterates over several runs and handles the output for all traces.""" |
320 for stdout in runner(): | 433 return AccumulateResults(self.graphs, self._children, runner, self.total) |
321 for trace in self._children: | |
322 trace.ConsumeOutput(stdout) | |
323 res = reduce(lambda r, t: r + t.GetResults(), self._children, Results()) | |
324 | 434 |
325 if not res.traces or not self.total: | |
326 return res | |
327 | 435 |
328 # Assume all traces have the same structure. | 436 class RunnableTraceConfig(TraceConfig, RunnableConfig): |
329 if len(set(map(lambda t: len(t["results"]), res.traces))) != 1: | |
330 res.errors.append("Not all traces have the same number of results.") | |
331 return res | |
332 | |
333 # Calculate the geometric means for all traces. Above we made sure that | |
334 # there is at least one trace and that the number of results is the same | |
335 # for each trace. | |
336 n_results = len(res.traces[0]["results"]) | |
337 total_results = [GeometricMean(t["results"][i] for t in res.traces) | |
338 for i in range(0, n_results)] | |
339 res.traces.append({ | |
340 "graphs": self.graphs + ["Total"], | |
341 "units": res.traces[0]["units"], | |
342 "results": total_results, | |
343 "stddev": "", | |
344 }) | |
345 return res | |
346 | |
347 class RunnableTrace(Trace, Runnable): | |
348 """Represents a runnable suite definition that is a leaf.""" | 437 """Represents a runnable suite definition that is a leaf.""" |
349 def __init__(self, suite, parent, arch): | 438 def __init__(self, suite, parent, arch): |
350 super(RunnableTrace, self).__init__(suite, parent, arch) | 439 super(RunnableTraceConfig, self).__init__(suite, parent, arch) |
351 | 440 |
352 def Run(self, runner): | 441 def Run(self, runner): |
353 """Iterates over several runs and handles the output.""" | 442 """Iterates over several runs and handles the output.""" |
| 443 measurement = self.CreateMeasurement() |
354 for stdout in runner(): | 444 for stdout in runner(): |
355 self.ConsumeOutput(stdout) | 445 measurement.ConsumeOutput(stdout) |
356 return self.GetResults() | 446 return measurement.GetResults() |
357 | 447 |
358 | 448 |
359 class RunnableGeneric(Runnable): | 449 class RunnableGenericConfig(RunnableConfig): |
360 """Represents a runnable suite definition with generic traces.""" | 450 """Represents a runnable suite definition with generic traces.""" |
361 def __init__(self, suite, parent, arch): | 451 def __init__(self, suite, parent, arch): |
362 super(RunnableGeneric, self).__init__(suite, parent, arch) | 452 super(RunnableGenericConfig, self).__init__(suite, parent, arch) |
363 | 453 |
364 def Run(self, runner): | 454 def Run(self, runner): |
365 """Iterates over several runs and handles the output.""" | 455 return AccumulateGenericResults(self.graphs, self.units, runner) |
366 traces = OrderedDict() | |
367 for stdout in runner(): | |
368 for line in stdout.strip().splitlines(): | |
369 match = GENERIC_RESULTS_RE.match(line) | |
370 if match: | |
371 stddev = "" | |
372 graph = match.group(1) | |
373 trace = match.group(2) | |
374 body = match.group(3) | |
375 units = match.group(4) | |
376 match_stddev = RESULT_STDDEV_RE.match(body) | |
377 match_list = RESULT_LIST_RE.match(body) | |
378 errors = [] | |
379 if match_stddev: | |
380 result, stddev = map(str.strip, match_stddev.group(1).split(",")) | |
381 results = [result] | |
382 elif match_list: | |
383 results = map(str.strip, match_list.group(1).split(",")) | |
384 else: | |
385 results = [body.strip()] | |
386 | |
387 try: | |
388 results = map(lambda r: str(float(r)), results) | |
389 except ValueError: | |
390 results = [] | |
391 errors = ["Found non-numeric in %s" % | |
392 "/".join(self.graphs + [graph, trace])] | |
393 | |
394 trace_result = traces.setdefault(trace, Results([{ | |
395 "graphs": self.graphs + [graph, trace], | |
396 "units": (units or self.units).strip(), | |
397 "results": [], | |
398 "stddev": "", | |
399 }], errors)) | |
400 trace_result.traces[0]["results"].extend(results) | |
401 trace_result.traces[0]["stddev"] = stddev | |
402 | |
403 return reduce(lambda r, t: r + t, traces.itervalues(), Results()) | |
404 | 456 |
405 | 457 |
406 def MakeGraph(suite, arch, parent): | 458 def MakeGraphConfig(suite, arch, parent): |
407 """Factory method for making graph objects.""" | 459 """Factory method for making graph configuration objects.""" |
408 if isinstance(parent, Runnable): | 460 if isinstance(parent, RunnableConfig): |
409 # Below a runnable can only be traces. | 461 # Below a runnable can only be traces. |
410 return Trace(suite, parent, arch) | 462 return TraceConfig(suite, parent, arch) |
411 elif suite.get("main") is not None: | 463 elif suite.get("main") is not None: |
412 # A main file makes this graph runnable. Empty strings are accepted. | 464 # A main file makes this graph runnable. Empty strings are accepted. |
413 if suite.get("tests"): | 465 if suite.get("tests"): |
414 # This graph has subgraphs (traces). | 466 # This graph has subgraphs (traces). |
415 return Runnable(suite, parent, arch) | 467 return RunnableConfig(suite, parent, arch) |
416 else: | 468 else: |
417 # This graph has no subgraphs, it's a leaf. | 469 # This graph has no subgraphs, it's a leaf. |
418 return RunnableTrace(suite, parent, arch) | 470 return RunnableTraceConfig(suite, parent, arch) |
419 elif suite.get("generic"): | 471 elif suite.get("generic"): |
420 # This is a generic suite definition. It is either a runnable executable | 472 # This is a generic suite definition. It is either a runnable executable |
421 # or has a main js file. | 473 # or has a main js file. |
422 return RunnableGeneric(suite, parent, arch) | 474 return RunnableGenericConfig(suite, parent, arch) |
423 elif suite.get("tests"): | 475 elif suite.get("tests"): |
424 # This is neither a leaf nor a runnable. | 476 # This is neither a leaf nor a runnable. |
425 return Graph(suite, parent, arch) | 477 return GraphConfig(suite, parent, arch) |
426 else: # pragma: no cover | 478 else: # pragma: no cover |
427 raise Exception("Invalid suite configuration.") | 479 raise Exception("Invalid suite configuration.") |
428 | 480 |
429 | 481 |
430 def BuildGraphs(suite, arch, parent=None): | 482 def BuildGraphConfigs(suite, arch, parent=None): |
431 """Builds a tree structure of graph objects that corresponds to the suite | 483 """Builds a tree structure of graph objects that corresponds to the suite |
432 configuration. | 484 configuration. |
433 """ | 485 """ |
434 parent = parent or DefaultSentinel() | 486 parent = parent or DefaultSentinel() |
435 | 487 |
436 # TODO(machenbach): Implement notion of cpu type? | 488 # TODO(machenbach): Implement notion of cpu type? |
437 if arch not in suite.get("archs", SUPPORTED_ARCHS): | 489 if arch not in suite.get("archs", SUPPORTED_ARCHS): |
438 return None | 490 return None |
439 | 491 |
440 graph = MakeGraph(suite, arch, parent) | 492 graph = MakeGraphConfig(suite, arch, parent) |
441 for subsuite in suite.get("tests", []): | 493 for subsuite in suite.get("tests", []): |
442 BuildGraphs(subsuite, arch, graph) | 494 BuildGraphConfigs(subsuite, arch, graph) |
443 parent.AppendChild(graph) | 495 parent.AppendChild(graph) |
444 return graph | 496 return graph |
445 | 497 |
446 | 498 |
447 def FlattenRunnables(node, node_cb): | 499 def FlattenRunnables(node, node_cb): |
448 """Generator that traverses the tree structure and iterates over all | 500 """Generator that traverses the tree structure and iterates over all |
449 runnables. | 501 runnables. |
450 """ | 502 """ |
451 node_cb(node) | 503 node_cb(node) |
452 if isinstance(node, Runnable): | 504 if isinstance(node, RunnableConfig): |
453 yield node | 505 yield node |
454 elif isinstance(node, Node): | 506 elif isinstance(node, Node): |
455 for child in node._children: | 507 for child in node._children: |
456 for result in FlattenRunnables(child, node_cb): | 508 for result in FlattenRunnables(child, node_cb): |
457 yield result | 509 yield result |
458 else: # pragma: no cover | 510 else: # pragma: no cover |
459 raise Exception("Invalid suite configuration.") | 511 raise Exception("Invalid suite configuration.") |
460 | 512 |
461 | 513 |
462 class Platform(object): | 514 class Platform(object): |
(...skipping 13 matching lines...) Expand all Loading... |
476 def __init__(self, options): | 528 def __init__(self, options): |
477 super(DesktopPlatform, self).__init__(options) | 529 super(DesktopPlatform, self).__init__(options) |
478 | 530 |
479 def PreExecution(self): | 531 def PreExecution(self): |
480 pass | 532 pass |
481 | 533 |
482 def PostExecution(self): | 534 def PostExecution(self): |
483 pass | 535 pass |
484 | 536 |
485 def PreTests(self, node, path): | 537 def PreTests(self, node, path): |
486 if isinstance(node, Runnable): | 538 if isinstance(node, RunnableConfig): |
487 node.ChangeCWD(path) | 539 node.ChangeCWD(path) |
488 | 540 |
489 def Run(self, runnable, count): | 541 def Run(self, runnable, count): |
490 try: | 542 try: |
491 output = commands.Execute( | 543 output = commands.Execute( |
492 runnable.GetCommand(self.shell_dir, self.extra_flags), | 544 runnable.GetCommand(self.shell_dir, self.extra_flags), |
493 timeout=runnable.timeout, | 545 timeout=runnable.timeout, |
494 ) | 546 ) |
495 except OSError as e: | 547 except OSError as e: |
496 print ">>> OSError (#%d):" % (count + 1) | 548 print ">>> OSError (#%d):" % (count + 1) |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
593 "bin", | 645 "bin", |
594 skip_if_missing=True, | 646 skip_if_missing=True, |
595 ) | 647 ) |
596 self._PushFile( | 648 self._PushFile( |
597 self.shell_dir, | 649 self.shell_dir, |
598 "snapshot_blob.bin", | 650 "snapshot_blob.bin", |
599 "bin", | 651 "bin", |
600 skip_if_missing=True, | 652 skip_if_missing=True, |
601 ) | 653 ) |
602 | 654 |
603 if isinstance(node, Runnable): | 655 if isinstance(node, RunnableConfig): |
604 self._PushFile(bench_abs, node.main, bench_rel) | 656 self._PushFile(bench_abs, node.main, bench_rel) |
605 for resource in node.resources: | 657 for resource in node.resources: |
606 self._PushFile(bench_abs, resource, bench_rel) | 658 self._PushFile(bench_abs, resource, bench_rel) |
607 | 659 |
608 def Run(self, runnable, count): | 660 def Run(self, runnable, count): |
609 cache = cache_control.CacheControl(self.device) | 661 cache = cache_control.CacheControl(self.device) |
610 cache.DropRamCaches() | 662 cache.DropRamCaches() |
611 binary_on_device = os.path.join( | 663 binary_on_device = os.path.join( |
612 AndroidPlatform.DEVICE_DIR, "bin", runnable.binary) | 664 AndroidPlatform.DEVICE_DIR, "bin", runnable.binary) |
613 cmd = [binary_on_device] + runnable.GetCommandFlags(self.extra_flags) | 665 cmd = [binary_on_device] + runnable.GetCommandFlags(self.extra_flags) |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
696 with open(path) as f: | 748 with open(path) as f: |
697 suite = json.loads(f.read()) | 749 suite = json.loads(f.read()) |
698 | 750 |
699 # If no name is given, default to the file name without .json. | 751 # If no name is given, default to the file name without .json. |
700 suite.setdefault("name", os.path.splitext(os.path.basename(path))[0]) | 752 suite.setdefault("name", os.path.splitext(os.path.basename(path))[0]) |
701 | 753 |
702 # Setup things common to one test suite. | 754 # Setup things common to one test suite. |
703 platform.PreExecution() | 755 platform.PreExecution() |
704 | 756 |
705 # Build the graph/trace tree structure. | 757 # Build the graph/trace tree structure. |
706 root = BuildGraphs(suite, options.arch) | 758 root = BuildGraphConfigs(suite, options.arch) |
707 | 759 |
708 # Callback to be called on each node on traversal. | 760 # Callback to be called on each node on traversal. |
709 def NodeCB(node): | 761 def NodeCB(node): |
710 platform.PreTests(node, path) | 762 platform.PreTests(node, path) |
711 | 763 |
712 # Traverse graph/trace tree and interate over all runnables. | 764 # Traverse graph/trace tree and interate over all runnables. |
713 for runnable in FlattenRunnables(root, NodeCB): | 765 for runnable in FlattenRunnables(root, NodeCB): |
714 print ">>> Running suite: %s" % "/".join(runnable.graphs) | 766 print ">>> Running suite: %s" % "/".join(runnable.graphs) |
715 | 767 |
716 def Runner(): | 768 def Runner(): |
(...skipping 10 matching lines...) Expand all Loading... |
727 | 779 |
728 if options.json_test_results: | 780 if options.json_test_results: |
729 results.WriteToFile(options.json_test_results) | 781 results.WriteToFile(options.json_test_results) |
730 else: # pragma: no cover | 782 else: # pragma: no cover |
731 print results | 783 print results |
732 | 784 |
733 return min(1, len(results.errors)) | 785 return min(1, len(results.errors)) |
734 | 786 |
735 if __name__ == "__main__": # pragma: no cover | 787 if __name__ == "__main__": # pragma: no cover |
736 sys.exit(Main(sys.argv[1:])) | 788 sys.exit(Main(sys.argv[1:])) |
OLD | NEW |