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

Side by Side Diff: tools/run_perf.py

Issue 1915303002: [tools] Specify affinity and raise priority when benchmarking (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 7 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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)]
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 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
781 retries=0, 799 retries=0,
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
809 class CustomMachineConfiguration:
810 def __init__(self, disable_aslr = None, governor = None):
811 self.aslr_backup = None
812 self.governor_backup = None
813 self.disable_aslr = disable_aslr
814 self.governor = governor
815
Michael Achenbach 2016/04/29 07:40:32 I like this!
816 def __enter__(self):
817 if self.disable_aslr != None:
818 self.BackupASLR()
819 self.DisableASLR()
820 if self.governor != None:
821 self.BackupGovernor()
822 self.UpdateGovernor()
823 return self
824
825 def __exit__(self, type, value, traceback):
826 if self.aslr_backup != None:
827 self.RestoreASLR()
828 if self.governor_backup != None:
829 self.RestoreGovernor()
830
831 def BackupASLR(self):
Michael Achenbach 2016/04/29 07:40:32 The next 6 methods are each called only once and h
Mircea Trofin 2016/04/29 15:25:10 Done.
832 self.aslr_backup = CustomMachineConfiguration.GetASLR()
833
834 def DisableASLR(self):
835 CustomMachineConfiguration.SetASLR(0)
836
837 def RestoreASLR(self):
838 CustomMachineConfiguration.SetASLR(self.aslr_backup)
839
840 def BackupGovernor(self):
841 self.governor_backup = CustomMachineConfiguration.GetCPUGovernor()
842
843 def UpdateGovernor(self):
844 CustomMachineConfiguration.SetCPUGovernor(self.governor)
845
846 def RestoreGovernor(self):
847 CustomMachineConfiguration.SetCPUGovernor(self.governor_backup)
848
849 @staticmethod
850 def GetASLR():
851 try:
852 with open("/proc/sys/kernel/randomize_va_space", "r") as f:
853 return int(f.readline().strip())
854 except Exception as e:
855 print "Failed to get current ASLR settings."
856 raise e
857
858 @staticmethod
859 def SetASLR(value):
860 try:
861 with open("/proc/sys/kernel/randomize_va_space", "w") as f:
862 f.write(str(value))
863 except Exception as e:
864 print "Failed to update ASLR to %s." % value
865 print "Are we running under sudo?"
866 raise e
867
868 new_value = CustomMachineConfiguration.GetASLR()
869 if value != new_value:
870 raise Exception("Present value is %s" % new_value)
871
872 @staticmethod
873 def GetCPUCoresRange():
874 try:
875 with open("/sys/devices/system/cpu/present", "r") as f:
876 indexes = f.readline()
877 first, last = map(int, indexes.split("-"))
878 return range(first, last + 1)
879 except Exception as e:
880 print "Failed to retrieve number of CPUs."
881 raise e
882
883 @staticmethod
884 def GetCPUPathForId(cpu_index):
885 ret = "/sys/devices/system/cpu/cpu"
886 ret += str(cpu_index)
887 ret += "/cpufreq/scaling_governor"
888 return ret
889
890 @staticmethod
891 def GetCPUGovernor():
892 try:
893 cpu_indices = CustomMachineConfiguration.GetCPUCoresRange()
894 ret = None
895 for cpu_index in cpu_indices:
896 cpu_device = CustomMachineConfiguration.GetCPUPathForId(cpu_index)
897 with open(cpu_device, "r") as f:
898 # We assume the governors of all CPUs are set to the same value
899 val = f.readline().strip()
900 if ret == None:
901 ret = val
902 elif ret != val:
903 raise Exception("CPU cores have differing governor settings")
904 return ret
905 except Exception as e:
906 print "Failed to get the current CPU governor."
907 print "Is the CPU governor disabled? Check BIOS."
908 raise e
909
910 @staticmethod
911 def SetCPUGovernor(value):
912 try:
913 cpu_indices = CustomMachineConfiguration.GetCPUCoresRange()
914 for cpu_index in cpu_indices:
915 cpu_device = CustomMachineConfiguration.GetCPUPathForId(cpu_index)
916 with open(cpu_device, "w") as f:
917 f.write(value)
918
919 except Exception as e:
920 print "Failed to change CPU governor to %s." % value
921 print "Are we running under sudo?"
922 raise e
923
924 cur_value = CustomMachineConfiguration.GetCPUGovernor()
925 if cur_value != value:
926 raise Exception("Could not set CPU governor. Present value is %s"
927 % cur_value )
791 928
792 # TODO: Implement results_processor. 929 # TODO: Implement results_processor.
793 def Main(args): 930 def Main(args):
794 logging.getLogger().setLevel(logging.INFO) 931 logging.getLogger().setLevel(logging.INFO)
795 parser = optparse.OptionParser() 932 parser = optparse.OptionParser()
796 parser.add_option("--android-build-tools", 933 parser.add_option("--android-build-tools",
797 help="Path to chromium's build/android. Specifying this " 934 help="Path to chromium's build/android. Specifying this "
798 "option will run tests using android platform.") 935 "option will run tests using android platform.")
799 parser.add_option("--arch", 936 parser.add_option("--arch",
800 help=("The architecture to run tests for, " 937 help=("The architecture to run tests for, "
(...skipping 14 matching lines...) Expand all
815 help="Path to a file for storing json results from run " 952 help="Path to a file for storing json results from run "
816 "without patch.") 953 "without patch.")
817 parser.add_option("--outdir", help="Base directory with compile output", 954 parser.add_option("--outdir", help="Base directory with compile output",
818 default="out") 955 default="out")
819 parser.add_option("--outdir-no-patch", 956 parser.add_option("--outdir-no-patch",
820 help="Base directory with compile output without patch") 957 help="Base directory with compile output without patch")
821 parser.add_option("--binary-override-path", 958 parser.add_option("--binary-override-path",
822 help="JavaScript engine binary. By default, d8 under " 959 help="JavaScript engine binary. By default, d8 under "
823 "architecture-specific build dir. " 960 "architecture-specific build dir. "
824 "Not supported in conjunction with outdir-no-patch.") 961 "Not supported in conjunction with outdir-no-patch.")
962 parser.add_option("--prioritize",
963 help="Raise the priority to nice -20 for the benchmarking "
964 "process.Requires Linux, schedtool, and sudo privileges.",
965 default=False, action="store_true")
966 parser.add_option("--affinitize",
967 help="Run benchmarking process on the specified core. "
968 "For example: "
969 "--affinitize=0 will run the benchmark process on core 0. "
970 "--affinitize=3 will run the benchmark process on core 3. "
971 "Requires Linux, schedtool, and sudo privileges.",
972 default=None)
973 parser.add_option("--noaslr",
974 help="Disable ASLR for the duration of the benchmarked "
975 "process. Requires Linux and sudo privileges.",
976 default=False, action="store_true")
977 parser.add_option("--cpu-governor",
978 help="Set cpu governor to specified policy for the "
979 "duration of the benchmarked process. Typical options: "
980 "'powersave' for more stable results, or 'performance' "
981 "for shorter completion time of suite, with potentially "
982 "more noise in results.")
825 983
826 (options, args) = parser.parse_args(args) 984 (options, args) = parser.parse_args(args)
827 985
828 if len(args) == 0: # pragma: no cover 986 if len(args) == 0: # pragma: no cover
829 parser.print_help() 987 parser.print_help()
830 return 1 988 return 1
831 989
832 if options.arch in ["auto", "native"]: # pragma: no cover 990 if options.arch in ["auto", "native"]: # pragma: no cover
833 options.arch = ARCH_GUESS 991 options.arch = ARCH_GUESS
834 992
(...skipping 30 matching lines...) Expand all
865 return 1 1023 return 1
866 options.shell_dir = os.path.dirname(options.binary_override_path) 1024 options.shell_dir = os.path.dirname(options.binary_override_path)
867 default_binary_name = os.path.basename(options.binary_override_path) 1025 default_binary_name = os.path.basename(options.binary_override_path)
868 1026
869 if options.outdir_no_patch: 1027 if options.outdir_no_patch:
870 options.shell_dir_no_patch = os.path.join( 1028 options.shell_dir_no_patch = os.path.join(
871 workspace, options.outdir_no_patch, build_config) 1029 workspace, options.outdir_no_patch, build_config)
872 else: 1030 else:
873 options.shell_dir_no_patch = None 1031 options.shell_dir_no_patch = None
874 1032
1033 prev_aslr = None
1034 prev_cpu_gov = None
875 platform = Platform.GetPlatform(options) 1035 platform = Platform.GetPlatform(options)
876 1036
877 results = Results() 1037 results = Results()
878 results_no_patch = Results() 1038 results_no_patch = Results()
879 for path in args: 1039 with CustomMachineConfiguration(governor = options.cpu_governor,
880 path = os.path.abspath(path) 1040 disable_aslr = options.noaslr) as conf:
1041 for path in args:
1042 path = os.path.abspath(path)
881 1043
882 if not os.path.exists(path): # pragma: no cover 1044 if not os.path.exists(path): # pragma: no cover
883 results.errors.append("Configuration file %s does not exist." % path) 1045 results.errors.append("Configuration file %s does not exist." % path)
884 continue 1046 continue
885 1047
886 with open(path) as f: 1048 with open(path) as f:
887 suite = json.loads(f.read()) 1049 suite = json.loads(f.read())
888 1050
889 # If no name is given, default to the file name without .json. 1051 # If no name is given, default to the file name without .json.
890 suite.setdefault("name", os.path.splitext(os.path.basename(path))[0]) 1052 suite.setdefault("name", os.path.splitext(os.path.basename(path))[0])
891 1053
892 # Setup things common to one test suite. 1054 # Setup things common to one test suite.
893 platform.PreExecution() 1055 platform.PreExecution()
894 1056
895 # Build the graph/trace tree structure. 1057 # Build the graph/trace tree structure.
896 default_parent = DefaultSentinel(default_binary_name) 1058 default_parent = DefaultSentinel(default_binary_name)
897 root = BuildGraphConfigs(suite, options.arch, default_parent) 1059 root = BuildGraphConfigs(suite, options.arch, default_parent)
898 1060
899 # Callback to be called on each node on traversal. 1061 # Callback to be called on each node on traversal.
900 def NodeCB(node): 1062 def NodeCB(node):
901 platform.PreTests(node, path) 1063 platform.PreTests(node, path)
902 1064
903 # Traverse graph/trace tree and interate over all runnables. 1065 # Traverse graph/trace tree and interate over all runnables.
904 for runnable in FlattenRunnables(root, NodeCB): 1066 for runnable in FlattenRunnables(root, NodeCB):
905 print ">>> Running suite: %s" % "/".join(runnable.graphs) 1067 print ">>> Running suite: %s" % "/".join(runnable.graphs)
906 1068
907 def Runner(): 1069 def Runner():
908 """Output generator that reruns several times.""" 1070 """Output generator that reruns several times."""
909 for i in xrange(0, max(1, runnable.run_count)): 1071 for i in xrange(0, max(1, runnable.run_count)):
910 # TODO(machenbach): Allow timeout per arch like with run_count per 1072 # TODO(machenbach): Allow timeout per arch like with run_count per
911 # arch. 1073 # arch.
912 yield platform.Run(runnable, i) 1074 yield platform.Run(runnable, i)
913 1075
914 # Let runnable iterate over all runs and handle output. 1076 # Let runnable iterate over all runs and handle output.
915 result, result_no_patch = runnable.Run( 1077 result, result_no_patch = runnable.Run(
916 Runner, trybot=options.shell_dir_no_patch) 1078 Runner, trybot=options.shell_dir_no_patch)
917 results += result 1079 results += result
918 results_no_patch += result_no_patch 1080 results_no_patch += result_no_patch
919 platform.PostExecution() 1081 platform.PostExecution()
920 1082
921 if options.json_test_results: 1083 if options.json_test_results:
922 results.WriteToFile(options.json_test_results) 1084 results.WriteToFile(options.json_test_results)
923 else: # pragma: no cover 1085 else: # pragma: no cover
924 print results 1086 print results
925 1087
926 if options.json_test_results_no_patch: 1088 if options.json_test_results_no_patch:
927 results_no_patch.WriteToFile(options.json_test_results_no_patch) 1089 results_no_patch.WriteToFile(options.json_test_results_no_patch)
928 else: # pragma: no cover 1090 else: # pragma: no cover
929 print results_no_patch 1091 print results_no_patch
930 1092
931 return min(1, len(results.errors)) 1093 return min(1, len(results.errors))
932 1094
933 if __name__ == "__main__": # pragma: no cover 1095 if __name__ == "__main__": # pragma: no cover
934 sys.exit(Main(sys.argv[1:])) 1096 sys.exit(Main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698