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

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