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 594 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
605 stdout = self._Run(runnable, count, no_patch=False) | 605 stdout = self._Run(runnable, count, no_patch=False) |
606 if self.shell_dir_no_patch: | 606 if self.shell_dir_no_patch: |
607 return stdout, self._Run(runnable, count, no_patch=True) | 607 return stdout, self._Run(runnable, count, no_patch=True) |
608 else: | 608 else: |
609 return stdout, None | 609 return stdout, None |
610 | 610 |
611 | 611 |
612 class DesktopPlatform(Platform): | 612 class DesktopPlatform(Platform): |
613 def __init__(self, options): | 613 def __init__(self, options): |
614 super(DesktopPlatform, self).__init__(options) | 614 super(DesktopPlatform, self).__init__(options) |
615 self.command_prefix = [] | |
616 | |
617 if options.prioritize or options.affinitize != None: | |
618 self.command_prefix = ["schedtool"] | |
619 if options.prioritize: | |
620 self.command_prefix += ["-n", "-20"] | |
621 if options.affinitize != None: | |
622 # schedtool expects a bit pattern when setting affinity, where each | |
623 # bit set to '1' corresponds to a core where the process may run on. | |
624 # First bit corresponds to CPU 0. Since the 'affinitize' parameter is | |
625 # a core number, we need to map to said bit pattern. | |
626 cpu = int(options.affinitize) | |
627 core = 1 << cpu | |
628 self.command_prefix += ["-a", ("0x%x" % core)] | |
Michael Achenbach
2016/04/28 13:03:07
Another question to this: Now we set exactly one c
Mircea Trofin
2016/04/28 14:21:57
Multi-core may introduce other sources of variance
| |
629 self.command_prefix += ["-e"] | |
615 | 630 |
616 def PreExecution(self): | 631 def PreExecution(self): |
617 pass | 632 pass |
618 | 633 |
619 def PostExecution(self): | 634 def PostExecution(self): |
620 pass | 635 pass |
621 | 636 |
622 def PreTests(self, node, path): | 637 def PreTests(self, node, path): |
623 if isinstance(node, RunnableConfig): | 638 if isinstance(node, RunnableConfig): |
624 node.ChangeCWD(path) | 639 node.ChangeCWD(path) |
625 | 640 |
626 def _Run(self, runnable, count, no_patch=False): | 641 def _Run(self, runnable, count, no_patch=False): |
627 suffix = ' - without patch' if no_patch else '' | 642 suffix = ' - without patch' if no_patch else '' |
628 shell_dir = self.shell_dir_no_patch if no_patch else self.shell_dir | 643 shell_dir = self.shell_dir_no_patch if no_patch else self.shell_dir |
629 title = ">>> %%s (#%d)%s:" % ((count + 1), suffix) | 644 title = ">>> %%s (#%d)%s:" % ((count + 1), suffix) |
645 command = self.command_prefix + runnable.GetCommand(shell_dir, | |
646 self.extra_flags) | |
630 try: | 647 try: |
631 output = commands.Execute( | 648 output = commands.Execute( |
632 runnable.GetCommand(shell_dir, self.extra_flags), | 649 command, |
633 timeout=runnable.timeout, | 650 timeout=runnable.timeout, |
634 ) | 651 ) |
635 except OSError as e: # pragma: no cover | 652 except OSError as e: # pragma: no cover |
636 print title % "OSError" | 653 print title % "OSError" |
637 print e | 654 print e |
638 return "" | 655 return "" |
656 | |
639 print title % "Stdout" | 657 print title % "Stdout" |
640 print output.stdout | 658 print output.stdout |
641 if output.stderr: # pragma: no cover | 659 if output.stderr: # pragma: no cover |
642 # Print stderr for debugging. | 660 # Print stderr for debugging. |
643 print title % "Stderr" | 661 print title % "Stderr" |
644 print output.stderr | 662 print output.stderr |
645 if output.timed_out: | 663 if output.timed_out: |
646 print ">>> Test timed out after %ss." % runnable.timeout | 664 print ">>> Test timed out after %ss." % runnable.timeout |
647 if '--prof' in self.extra_flags: | 665 if '--prof' in self.extra_flags: |
648 os_prefix = {"linux": "linux", "macos": "mac"}.get(utils.GuessOS()) | 666 os_prefix = {"linux": "linux", "macos": "mac"}.get(utils.GuessOS()) |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
782 ) | 800 ) |
783 stdout = "\n".join(output) | 801 stdout = "\n".join(output) |
784 print title % "Stdout" | 802 print title % "Stdout" |
785 print stdout | 803 print stdout |
786 except device_errors.CommandTimeoutError: | 804 except device_errors.CommandTimeoutError: |
787 print ">>> Test timed out after %ss." % runnable.timeout | 805 print ">>> Test timed out after %ss." % runnable.timeout |
788 stdout = "" | 806 stdout = "" |
789 return stdout | 807 return stdout |
790 | 808 |
791 | 809 |
810 def GetASLR(): | |
811 try: | |
812 f = os.open("/proc/sys/kernel/randomize_va_space", os.O_RDONLY) | |
Michael Achenbach
2016/04/28 14:47:44
Could you use with clauses? Also below.
with open(
Mircea Trofin
2016/04/28 16:02:46
Done.
| |
813 val = os.read(f, 1) | |
814 os.close(f) | |
815 return int(val) | |
816 except Exception as e: | |
817 print "Failed to get current ASLR settings." | |
818 raise e | |
819 | |
820 def SetASLR(value): | |
821 try: | |
822 f = os.open("/proc/sys/kernel/randomize_va_space", os.O_WRONLY) | |
823 val = os.write(f, str(value)) | |
824 os.close(f) | |
825 | |
826 new_value = GetASLR() | |
827 if value != new_value: raise Exception("Present value is %s" % new_value) | |
Michael Achenbach
2016/04/28 14:47:44
Maybe move this condition outside the try block to
Mircea Trofin
2016/04/28 16:02:46
Done.
| |
828 except Exception as e: | |
829 print "Failed to update ASLR to %s." % value | |
830 raise e | |
831 | |
832 def GetCPUCoresRange(): | |
833 try: | |
834 f = open("/sys/devices/system/cpu/present", "r") | |
835 indexes = f.readline() | |
836 [first, last] = map(int, indexes.split("-")) | |
Michael Achenbach
2016/04/28 14:47:44
first, last = map(int, indexes.split("-"))
should
Mircea Trofin
2016/04/28 16:02:47
Done.
| |
837 return range(first, last + 1) | |
838 except Exception as e: | |
839 print "Failed to retrieve CPU governor value" | |
840 raise e | |
841 | |
842 def GetCPUPathForId(cpu_index): | |
843 ret = "/sys/devices/system/cpu/cpu" | |
844 ret += str(cpu_index) | |
845 ret += "/cpufreq/scaling_governor" | |
846 return ret | |
847 | |
848 def GetCPUGovernor(): | |
849 try: | |
850 cpu_indices = GetCPUCoresRange() | |
851 ret = None | |
852 for cpu_index in cpu_indices: | |
Michael Achenbach
2016/04/28 14:47:44
nit: Maybe inline GetCPUCoresRange()
also in metho
Mircea Trofin
2016/04/28 16:02:46
I didn't understand what you meant here.
Michael Achenbach
2016/04/29 07:40:32
I meant to skip the local variable. But now that t
| |
853 f = open(GetCPUPathForId(cpu_index), "r") | |
854 # We assume the governors of all CPUs are set to the same value | |
855 val = f.readline().strip() | |
856 f.close() | |
857 if ret == None: | |
858 ret = val | |
859 else: | |
Michael Achenbach
2016/04/28 14:47:44
elif ret != val:
Mircea Trofin
2016/04/28 16:02:46
Done.
| |
860 if ret != val: | |
861 raise Exception("CPU cores have differing governor settings") | |
862 return ret | |
863 except Exception as e: | |
864 print "Failed to get the current CPU governor." | |
865 raise e | |
866 | |
867 | |
868 def SetCPUGovernor(value): | |
869 try: | |
870 cpu_indices = GetCPUCoresRange() | |
871 for cpu_index in cpu_indices: | |
872 f = open(GetCPUPathForId(cpu_index), "w") | |
873 f.write(value) | |
874 f.close() | |
875 | |
876 cur_value = GetCPUGovernor() | |
877 if cur_value != value: | |
Michael Achenbach
2016/04/28 14:47:44
same as above - move condition outside try
Mircea Trofin
2016/04/28 16:02:46
Done.
| |
878 raise Exception("Could not set CPU governor. Present value is %s" | |
879 % cur_value ) | |
880 except Exception as e: | |
881 print "Failed to change CPU governor to %s." % value | |
882 raise e | |
883 | |
792 # TODO: Implement results_processor. | 884 # TODO: Implement results_processor. |
793 def Main(args): | 885 def Main(args): |
794 logging.getLogger().setLevel(logging.INFO) | 886 logging.getLogger().setLevel(logging.INFO) |
795 parser = optparse.OptionParser() | 887 parser = optparse.OptionParser() |
796 parser.add_option("--android-build-tools", | 888 parser.add_option("--android-build-tools", |
797 help="Path to chromium's build/android. Specifying this " | 889 help="Path to chromium's build/android. Specifying this " |
798 "option will run tests using android platform.") | 890 "option will run tests using android platform.") |
799 parser.add_option("--arch", | 891 parser.add_option("--arch", |
800 help=("The architecture to run tests for, " | 892 help=("The architecture to run tests for, " |
801 "'auto' or 'native' for auto-detect"), | 893 "'auto' or 'native' for auto-detect"), |
(...skipping 13 matching lines...) Expand all Loading... | |
815 help="Path to a file for storing json results from run " | 907 help="Path to a file for storing json results from run " |
816 "without patch.") | 908 "without patch.") |
817 parser.add_option("--outdir", help="Base directory with compile output", | 909 parser.add_option("--outdir", help="Base directory with compile output", |
818 default="out") | 910 default="out") |
819 parser.add_option("--outdir-no-patch", | 911 parser.add_option("--outdir-no-patch", |
820 help="Base directory with compile output without patch") | 912 help="Base directory with compile output without patch") |
821 parser.add_option("--binary-override-path", | 913 parser.add_option("--binary-override-path", |
822 help="JavaScript engine binary. By default, d8 under " | 914 help="JavaScript engine binary. By default, d8 under " |
823 "architecture-specific build dir. " | 915 "architecture-specific build dir. " |
824 "Not supported in conjunction with outdir-no-patch.") | 916 "Not supported in conjunction with outdir-no-patch.") |
917 parser.add_option("--prioritize", | |
918 help="Raise the priority to nice -20 for the benchmarking" | |
919 "process.Requires Linux, schedtool, and sudo privileges.", | |
920 default=False, action="store_true") | |
921 parser.add_option("--affinitize", | |
922 help="Run benchmarking process on the specified core." | |
923 "For example:" | |
924 "--affinitize=0 will run the benchmark process on core 0." | |
925 "--affinitize=3 will run the benchmark process on core 3." | |
926 "Requires Linux, schedtool, and sudo privileges.", | |
927 default=None) | |
928 parser.add_option("--noaslr", | |
929 help="Disable ASLR for the duration of the benchmarked" | |
930 "process. Requires Linux and sudo privileges.", | |
931 default=False, action="store_true") | |
932 parser.add_option("--cpu-governor", | |
933 help="Set cpu governor to specified policy for the" | |
Michael Achenbach
2016/04/28 14:47:43
nit: Space before " to not concatenate strings.
Mircea Trofin
2016/04/28 16:02:46
Done.
| |
934 "duration of the benchmarked process. Typical options:" | |
935 "'powersave' for more stable results, or 'performance'" | |
936 "for shorter completion time of suite, with potentially" | |
937 "more noise in results.") | |
825 | 938 |
826 (options, args) = parser.parse_args(args) | 939 (options, args) = parser.parse_args(args) |
827 | 940 |
828 if len(args) == 0: # pragma: no cover | 941 if len(args) == 0: # pragma: no cover |
829 parser.print_help() | 942 parser.print_help() |
830 return 1 | 943 return 1 |
831 | 944 |
832 if options.arch in ["auto", "native"]: # pragma: no cover | 945 if options.arch in ["auto", "native"]: # pragma: no cover |
833 options.arch = ARCH_GUESS | 946 options.arch = ARCH_GUESS |
834 | 947 |
(...skipping 30 matching lines...) Expand all Loading... | |
865 return 1 | 978 return 1 |
866 options.shell_dir = os.path.dirname(options.binary_override_path) | 979 options.shell_dir = os.path.dirname(options.binary_override_path) |
867 default_binary_name = os.path.basename(options.binary_override_path) | 980 default_binary_name = os.path.basename(options.binary_override_path) |
868 | 981 |
869 if options.outdir_no_patch: | 982 if options.outdir_no_patch: |
870 options.shell_dir_no_patch = os.path.join( | 983 options.shell_dir_no_patch = os.path.join( |
871 workspace, options.outdir_no_patch, build_config) | 984 workspace, options.outdir_no_patch, build_config) |
872 else: | 985 else: |
873 options.shell_dir_no_patch = None | 986 options.shell_dir_no_patch = None |
874 | 987 |
988 prev_aslr = None | |
989 prev_cpu_gov = None | |
990 if options.noaslr: | |
991 prev_aslr = GetASLR() | |
992 SetASLR(0) | |
993 if options.cpu_governor: | |
994 prev_cpu_gov = GetCPUGovernor() | |
995 SetCPUGovernor(options.cpu_governor) | |
996 | |
875 platform = Platform.GetPlatform(options) | 997 platform = Platform.GetPlatform(options) |
876 | 998 |
877 results = Results() | 999 results = Results() |
878 results_no_patch = Results() | 1000 results_no_patch = Results() |
879 for path in args: | 1001 for path in args: |
880 path = os.path.abspath(path) | 1002 path = os.path.abspath(path) |
881 | 1003 |
882 if not os.path.exists(path): # pragma: no cover | 1004 if not os.path.exists(path): # pragma: no cover |
883 results.errors.append("Configuration file %s does not exist." % path) | 1005 results.errors.append("Configuration file %s does not exist." % path) |
884 continue | 1006 continue |
(...skipping 25 matching lines...) Expand all Loading... | |
910 # TODO(machenbach): Allow timeout per arch like with run_count per | 1032 # TODO(machenbach): Allow timeout per arch like with run_count per |
911 # arch. | 1033 # arch. |
912 yield platform.Run(runnable, i) | 1034 yield platform.Run(runnable, i) |
913 | 1035 |
914 # Let runnable iterate over all runs and handle output. | 1036 # Let runnable iterate over all runs and handle output. |
915 result, result_no_patch = runnable.Run( | 1037 result, result_no_patch = runnable.Run( |
916 Runner, trybot=options.shell_dir_no_patch) | 1038 Runner, trybot=options.shell_dir_no_patch) |
917 results += result | 1039 results += result |
918 results_no_patch += result_no_patch | 1040 results_no_patch += result_no_patch |
919 platform.PostExecution() | 1041 platform.PostExecution() |
920 | 1042 |
Michael Achenbach
2016/04/28 14:47:44
Please refactor and put everything between setting
Mircea Trofin
2016/04/28 16:02:47
Thanks for the suggestion - this makes sense. I mo
Michael Achenbach
2016/04/29 07:40:32
Very nice!
| |
1043 if prev_aslr != None: | |
1044 SetASLR(prev_aslr) | |
1045 if prev_cpu_gov != None: | |
1046 SetCPUGovernor(prev_cpu_gov) | |
1047 | |
921 if options.json_test_results: | 1048 if options.json_test_results: |
922 results.WriteToFile(options.json_test_results) | 1049 results.WriteToFile(options.json_test_results) |
923 else: # pragma: no cover | 1050 else: # pragma: no cover |
924 print results | 1051 print results |
925 | 1052 |
926 if options.json_test_results_no_patch: | 1053 if options.json_test_results_no_patch: |
927 results_no_patch.WriteToFile(options.json_test_results_no_patch) | 1054 results_no_patch.WriteToFile(options.json_test_results_no_patch) |
928 else: # pragma: no cover | 1055 else: # pragma: no cover |
929 print results_no_patch | 1056 print results_no_patch |
930 | 1057 |
931 return min(1, len(results.errors)) | 1058 return min(1, len(results.errors)) |
932 | 1059 |
933 if __name__ == "__main__": # pragma: no cover | 1060 if __name__ == "__main__": # pragma: no cover |
934 sys.exit(Main(sys.argv[1:])) | 1061 sys.exit(Main(sys.argv[1:])) |
OLD | NEW |