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 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
426 if arch not in suite.get("archs", SUPPORTED_ARCHS): | 426 if arch not in suite.get("archs", SUPPORTED_ARCHS): |
427 return None | 427 return None |
428 | 428 |
429 graph = MakeGraph(suite, arch, parent) | 429 graph = MakeGraph(suite, arch, parent) |
430 for subsuite in suite.get("tests", []): | 430 for subsuite in suite.get("tests", []): |
431 BuildGraphs(subsuite, arch, graph) | 431 BuildGraphs(subsuite, arch, graph) |
432 parent.AppendChild(graph) | 432 parent.AppendChild(graph) |
433 return graph | 433 return graph |
434 | 434 |
435 | 435 |
436 def FlattenRunnables(node): | 436 def FlattenRunnables(node, node_cb): |
437 """Generator that traverses the tree structure and iterates over all | 437 """Generator that traverses the tree structure and iterates over all |
438 runnables. | 438 runnables. |
439 """ | 439 """ |
| 440 node_cb(node) |
440 if isinstance(node, Runnable): | 441 if isinstance(node, Runnable): |
441 yield node | 442 yield node |
442 elif isinstance(node, Node): | 443 elif isinstance(node, Node): |
443 for child in node._children: | 444 for child in node._children: |
444 for result in FlattenRunnables(child): | 445 for result in FlattenRunnables(child, node_cb): |
445 yield result | 446 yield result |
446 else: # pragma: no cover | 447 else: # pragma: no cover |
447 raise Exception("Invalid suite configuration.") | 448 raise Exception("Invalid suite configuration.") |
448 | 449 |
449 | 450 |
450 class Platform(object): | 451 class Platform(object): |
451 @staticmethod | 452 @staticmethod |
452 def GetPlatform(options): | 453 def GetPlatform(options): |
453 if options.arch.startswith("android"): | 454 if options.arch.startswith("android"): |
454 return AndroidPlatform(options) | 455 return AndroidPlatform(options) |
455 else: | 456 else: |
456 return DesktopPlatform(options) | 457 return DesktopPlatform(options) |
457 | 458 |
458 | 459 |
459 class DesktopPlatform(Platform): | 460 class DesktopPlatform(Platform): |
460 def __init__(self, options): | 461 def __init__(self, options): |
461 self.shell_dir = options.shell_dir | 462 self.shell_dir = options.shell_dir |
462 | 463 |
463 def PreExecution(self): | 464 def PreExecution(self): |
464 pass | 465 pass |
465 | 466 |
466 def PostExecution(self): | 467 def PostExecution(self): |
467 pass | 468 pass |
468 | 469 |
469 def PreTests(self, runnable, path): | 470 def PreTests(self, node, path): |
470 runnable.ChangeCWD(path) | 471 if isinstance(node, Runnable): |
| 472 node.ChangeCWD(path) |
471 | 473 |
472 def Run(self, runnable, count): | 474 def Run(self, runnable, count): |
473 output = commands.Execute(runnable.GetCommand(self.shell_dir), | 475 output = commands.Execute(runnable.GetCommand(self.shell_dir), |
474 timeout=runnable.timeout) | 476 timeout=runnable.timeout) |
475 print ">>> Stdout (#%d):" % (count + 1) | 477 print ">>> Stdout (#%d):" % (count + 1) |
476 print output.stdout | 478 print output.stdout |
477 if output.stderr: # pragma: no cover | 479 if output.stderr: # pragma: no cover |
478 # Print stderr for debugging. | 480 # Print stderr for debugging. |
479 print ">>> Stderr (#%d):" % (count + 1) | 481 print ">>> Stderr (#%d):" % (count + 1) |
480 print output.stderr | 482 print output.stderr |
(...skipping 18 matching lines...) Expand all Loading... |
499 "the command-line with --device") | 501 "the command-line with --device") |
500 options.device = devices[0] | 502 options.device = devices[0] |
501 adb_wrapper = pylib.android_commands.AndroidCommands(options.device) | 503 adb_wrapper = pylib.android_commands.AndroidCommands(options.device) |
502 self.device = device_utils.DeviceUtils(adb_wrapper) | 504 self.device = device_utils.DeviceUtils(adb_wrapper) |
503 self.adb = adb_wrapper.Adb() | 505 self.adb = adb_wrapper.Adb() |
504 | 506 |
505 def PreExecution(self): | 507 def PreExecution(self): |
506 perf = perf_control.PerfControl(self.device) | 508 perf = perf_control.PerfControl(self.device) |
507 perf.SetHighPerfMode() | 509 perf.SetHighPerfMode() |
508 | 510 |
| 511 # Remember what we have already pushed to the device. |
| 512 self.pushed = set() |
| 513 |
509 def PostExecution(self): | 514 def PostExecution(self): |
510 perf = perf_control.PerfControl(self.device) | 515 perf = perf_control.PerfControl(self.device) |
511 perf.SetDefaultPerfMode() | 516 perf.SetDefaultPerfMode() |
512 self.device.RunShellCommand( | 517 self.device.RunShellCommand( |
513 ["rm", "-rf", "*"], | 518 ["rm", "-rf", "*"], |
514 cwd=AndroidPlatform.DEVICE_DIR, | 519 cwd=AndroidPlatform.DEVICE_DIR, |
515 ) | 520 ) |
516 | 521 |
517 def _PushFile(self, host_dir, file_name): | 522 def _PushFile(self, host_dir, file_name): |
518 file_on_host = os.path.join(host_dir, file_name) | 523 file_on_host = os.path.join(host_dir, file_name) |
519 file_on_device = AndroidPlatform.DEVICE_DIR + file_name | 524 file_on_device = AndroidPlatform.DEVICE_DIR + file_name |
| 525 |
| 526 # Only push files not yet pushed in one execution. |
| 527 if file_on_host in self.pushed: |
| 528 return |
| 529 else: |
| 530 self.pushed.add(file_on_host) |
| 531 |
520 logging.info("adb push %s %s" % (file_on_host, file_on_device)) | 532 logging.info("adb push %s %s" % (file_on_host, file_on_device)) |
521 self.adb.Push(file_on_host, file_on_device) | 533 self.adb.Push(file_on_host, file_on_device) |
522 | 534 |
523 def PreTests(self, runnable, path): | 535 def PreTests(self, node, path): |
524 suite_dir = os.path.abspath(os.path.dirname(path)) | 536 suite_dir = os.path.abspath(os.path.dirname(path)) |
525 bench_dir = os.path.join(suite_dir, | 537 bench_dir = os.path.join(suite_dir, |
526 os.path.normpath(os.path.join(*runnable.path))) | 538 os.path.normpath(os.path.join(*node.path))) |
527 | 539 |
528 self._PushFile(self.shell_dir, runnable.binary) | 540 self._PushFile(self.shell_dir, node.binary) |
529 self._PushFile(bench_dir, runnable.main) | 541 if isinstance(node, Runnable): |
530 for resource in runnable.resources: | 542 self._PushFile(bench_dir, node.main) |
| 543 for resource in node.resources: |
531 self._PushFile(bench_dir, resource) | 544 self._PushFile(bench_dir, resource) |
532 | 545 |
533 def Run(self, runnable, count): | 546 def Run(self, runnable, count): |
534 cache = cache_control.CacheControl(self.device) | 547 cache = cache_control.CacheControl(self.device) |
535 cache.DropRamCaches() | 548 cache.DropRamCaches() |
536 binary_on_device = AndroidPlatform.DEVICE_DIR + runnable.binary | 549 binary_on_device = AndroidPlatform.DEVICE_DIR + runnable.binary |
537 cmd = [binary_on_device] + runnable.GetCommandFlags() | 550 cmd = [binary_on_device] + runnable.GetCommandFlags() |
538 try: | 551 try: |
539 output = self.device.RunShellCommand( | 552 output = self.device.RunShellCommand( |
540 cmd, | 553 cmd, |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
597 | 610 |
598 workspace = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) | 611 workspace = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) |
599 | 612 |
600 if options.buildbot: | 613 if options.buildbot: |
601 options.shell_dir = os.path.join(workspace, options.outdir, "Release") | 614 options.shell_dir = os.path.join(workspace, options.outdir, "Release") |
602 else: | 615 else: |
603 options.shell_dir = os.path.join(workspace, options.outdir, | 616 options.shell_dir = os.path.join(workspace, options.outdir, |
604 "%s.release" % options.arch) | 617 "%s.release" % options.arch) |
605 | 618 |
606 platform = Platform.GetPlatform(options) | 619 platform = Platform.GetPlatform(options) |
607 platform.PreExecution() | |
608 | 620 |
609 results = Results() | 621 results = Results() |
610 for path in args: | 622 for path in args: |
611 path = os.path.abspath(path) | 623 path = os.path.abspath(path) |
612 | 624 |
613 if not os.path.exists(path): # pragma: no cover | 625 if not os.path.exists(path): # pragma: no cover |
614 results.errors.append("Configuration file %s does not exist." % path) | 626 results.errors.append("Configuration file %s does not exist." % path) |
615 continue | 627 continue |
616 | 628 |
617 with open(path) as f: | 629 with open(path) as f: |
618 suite = json.loads(f.read()) | 630 suite = json.loads(f.read()) |
619 | 631 |
620 # If no name is given, default to the file name without .json. | 632 # If no name is given, default to the file name without .json. |
621 suite.setdefault("name", os.path.splitext(os.path.basename(path))[0]) | 633 suite.setdefault("name", os.path.splitext(os.path.basename(path))[0]) |
622 | 634 |
623 for runnable in FlattenRunnables(BuildGraphs(suite, options.arch)): | 635 # Setup things common to one test suite. |
| 636 platform.PreExecution() |
| 637 |
| 638 # Build the graph/trace tree structure. |
| 639 root = BuildGraphs(suite, options.arch) |
| 640 |
| 641 # Callback to be called on each node on traversal. |
| 642 def NodeCB(node): |
| 643 platform.PreTests(node, path) |
| 644 |
| 645 # Traverse graph/trace tree and interate over all runnables. |
| 646 for runnable in FlattenRunnables(root, NodeCB): |
624 print ">>> Running suite: %s" % "/".join(runnable.graphs) | 647 print ">>> Running suite: %s" % "/".join(runnable.graphs) |
625 platform.PreTests(runnable, path) | |
626 | 648 |
627 def Runner(): | 649 def Runner(): |
628 """Output generator that reruns several times.""" | 650 """Output generator that reruns several times.""" |
629 for i in xrange(0, max(1, runnable.run_count)): | 651 for i in xrange(0, max(1, runnable.run_count)): |
630 # TODO(machenbach): Allow timeout per arch like with run_count per | 652 # TODO(machenbach): Allow timeout per arch like with run_count per |
631 # arch. | 653 # arch. |
632 yield platform.Run(runnable, i) | 654 yield platform.Run(runnable, i) |
633 | 655 |
634 # Let runnable iterate over all runs and handle output. | 656 # Let runnable iterate over all runs and handle output. |
635 results += runnable.Run(Runner) | 657 results += runnable.Run(Runner) |
636 | 658 |
637 platform.PostExecution() | 659 platform.PostExecution() |
638 | 660 |
639 if options.json_test_results: | 661 if options.json_test_results: |
640 results.WriteToFile(options.json_test_results) | 662 results.WriteToFile(options.json_test_results) |
641 else: # pragma: no cover | 663 else: # pragma: no cover |
642 print results | 664 print results |
643 | 665 |
644 return min(1, len(results.errors)) | 666 return min(1, len(results.errors)) |
645 | 667 |
646 if __name__ == "__main__": # pragma: no cover | 668 if __name__ == "__main__": # pragma: no cover |
647 sys.exit(Main(sys.argv[1:])) | 669 sys.exit(Main(sys.argv[1:])) |
OLD | NEW |