| 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 |