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

Side by Side Diff: tools/bisect-perf-regression.py

Issue 12254022: Adding annotation output for trybot. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Changes from review. Created 7 years, 10 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 (c) 2013 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2013 The Chromium 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 """Performance Test Bisect Tool 6 """Performance Test Bisect Tool
7 7
8 This script bisects a series of changelists using binary search. It starts at 8 This script bisects a series of changelists using binary search. It starts at
9 a bad revision where a performance metric has regressed, and asks for a last 9 a bad revision where a performance metric has regressed, and asks for a last
10 known-good revision. It will then binary search across this revision range by 10 known-good revision. It will then binary search across this revision range by
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 True if the string can be converted to an int. 119 True if the string can be converted to an int.
120 """ 120 """
121 try: 121 try:
122 int(string_to_check) 122 int(string_to_check)
123 123
124 return True 124 return True
125 except ValueError: 125 except ValueError:
126 return False 126 return False
127 127
128 128
129 def OutputAnnotationStepStart(name):
130 """Outputs appropriate annotation to signal the start of a step to
131 a trybot.
132
133 Args:
134 name: The name of the step.
135 """
136 print '@@@SEED_STEP %s@@@' % name
137 print '@@@STEP_CURSOR %s@@@' % name
138 print '@@@STEP_STARTED@@@'
139
140
141 def OutputAnnotationStepClosed():
142 """Outputs appropriate annotation to signal the closing of a step to
143 a trybot."""
144 print '@@@STEP_CLOSED@@@'
145
146
129 def RunProcess(command): 147 def RunProcess(command):
130 """Run an arbitrary command, returning its output and return code. 148 """Run an arbitrary command, returning its output and return code.
131 149
132 Args: 150 Args:
133 command: A list containing the command and args to execute. 151 command: A list containing the command and args to execute.
134 152
135 Returns: 153 Returns:
136 A tuple of the output and return code. 154 A tuple of the output and return code.
137 """ 155 """
138 # On Windows, use shell=True to get PATH interpretation. 156 # On Windows, use shell=True to get PATH interpretation.
(...skipping 633 matching lines...) Expand 10 before | Expand all | Expand 10 after
772 for i in xrange(num_depot_revisions): 790 for i in xrange(num_depot_revisions):
773 r = revisions[i] 791 r = revisions[i]
774 792
775 revision_data[r] = {'revision' : r, 793 revision_data[r] = {'revision' : r,
776 'depot' : depot, 794 'depot' : depot,
777 'value' : None, 795 'value' : None,
778 'passed' : '?', 796 'passed' : '?',
779 'sort' : i + sort + 1} 797 'sort' : i + sort + 1}
780 798
781 def PrintRevisionsToBisectMessage(self, revision_list, depot): 799 def PrintRevisionsToBisectMessage(self, revision_list, depot):
800 if self.opts.output_buildbot_annotations:
801 step_name = 'Bisection Range: [%s - %s]' % (
802 revision_list[len(revision_list)-1], revision_list[0])
803 OutputAnnotationStepStart(step_name)
804
782 print 805 print
783 print 'Revisions to bisect on [%s]:' % depot 806 print 'Revisions to bisect on [%s]:' % depot
784 for revision_id in revision_list: 807 for revision_id in revision_list:
785 print ' -> %s' % (revision_id, ) 808 print ' -> %s' % (revision_id, )
786 print 809 print
787 810
811 if self.opts.output_buildbot_annotations:
812 OutputAnnotationStepClosed()
813
788 def Run(self, command_to_run, bad_revision_in, good_revision_in, metric): 814 def Run(self, command_to_run, bad_revision_in, good_revision_in, metric):
789 """Given known good and bad revisions, run a binary search on all 815 """Given known good and bad revisions, run a binary search on all
790 intermediate revisions to determine the CL where the performance regression 816 intermediate revisions to determine the CL where the performance regression
791 occurred. 817 occurred.
792 818
793 Args: 819 Args:
794 command_to_run: Specify the command to execute the performance test. 820 command_to_run: Specify the command to execute the performance test.
795 good_revision: Number/tag of the known good revision. 821 good_revision: Number/tag of the known good revision.
796 bad_revision: Number/tag of the known bad revision. 822 bad_revision: Number/tag of the known bad revision.
797 metric: The performance metric to monitor. 823 metric: The performance metric to monitor.
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
839 'src') 865 'src')
840 866
841 if bad_revision is None: 867 if bad_revision is None:
842 results['error'] = 'Could\'t resolve [%s] to SHA1.' % (bad_revision_in,) 868 results['error'] = 'Could\'t resolve [%s] to SHA1.' % (bad_revision_in,)
843 return results 869 return results
844 870
845 if good_revision is None: 871 if good_revision is None:
846 results['error'] = 'Could\'t resolve [%s] to SHA1.' % (good_revision_in,) 872 results['error'] = 'Could\'t resolve [%s] to SHA1.' % (good_revision_in,)
847 return results 873 return results
848 874
875 if self.opts.output_buildbot_annotations:
876 OutputAnnotationStepStart('Gathering Revisions')
877
849 print 'Gathering revision range for bisection.' 878 print 'Gathering revision range for bisection.'
850 879
851 # Retrieve a list of revisions to do bisection on. 880 # Retrieve a list of revisions to do bisection on.
852 src_revision_list = self.GetRevisionList(bad_revision, good_revision) 881 src_revision_list = self.GetRevisionList(bad_revision, good_revision)
853 882
883 if self.opts.output_buildbot_annotations:
884 OutputAnnotationStepClosed()
885
854 if src_revision_list: 886 if src_revision_list:
855 # revision_data will store information about a revision such as the 887 # revision_data will store information about a revision such as the
856 # depot it came from, the webkit/V8 revision at that time, 888 # depot it came from, the webkit/V8 revision at that time,
857 # performance timing, build state, etc... 889 # performance timing, build state, etc...
858 revision_data = results['revision_data'] 890 revision_data = results['revision_data']
859 891
860 # revision_list is the list we're binary searching through at the moment. 892 # revision_list is the list we're binary searching through at the moment.
861 revision_list = [] 893 revision_list = []
862 894
863 sort_key_ids = 0 895 sort_key_ids = 0
864 896
865 for current_revision_id in src_revision_list: 897 for current_revision_id in src_revision_list:
866 sort_key_ids += 1 898 sort_key_ids += 1
867 899
868 revision_data[current_revision_id] = {'value' : None, 900 revision_data[current_revision_id] = {'value' : None,
869 'passed' : '?', 901 'passed' : '?',
870 'depot' : 'chromium', 902 'depot' : 'chromium',
871 'external' : None, 903 'external' : None,
872 'sort' : sort_key_ids} 904 'sort' : sort_key_ids}
873 revision_list.append(current_revision_id) 905 revision_list.append(current_revision_id)
874 906
875 min_revision = 0 907 min_revision = 0
876 max_revision = len(revision_list) - 1 908 max_revision = len(revision_list) - 1
877 909
878 self.PrintRevisionsToBisectMessage(revision_list, 'src') 910 self.PrintRevisionsToBisectMessage(revision_list, 'src')
879 911
912 if self.opts.output_buildbot_annotations:
913 OutputAnnotationStepStart('Gathering Reference Values')
914
880 print 'Gathering reference values for bisection.' 915 print 'Gathering reference values for bisection.'
881 916
882 # Perform the performance tests on the good and bad revisions, to get 917 # Perform the performance tests on the good and bad revisions, to get
883 # reference values. 918 # reference values.
884 (bad_results, good_results) = self.GatherReferenceValues(good_revision, 919 (bad_results, good_results) = self.GatherReferenceValues(good_revision,
885 bad_revision, 920 bad_revision,
886 command_to_run, 921 command_to_run,
887 metric) 922 metric)
888 923
924 if self.opts.output_buildbot_annotations:
925 OutputAnnotationStepClosed()
926
889 if bad_results[1]: 927 if bad_results[1]:
890 results['error'] = bad_results[0] 928 results['error'] = bad_results[0]
891 return results 929 return results
892 930
893 if good_results[1]: 931 if good_results[1]:
894 results['error'] = good_results[0] 932 results['error'] = good_results[0]
895 return results 933 return results
896 934
897 935
898 # We need these reference values to determine if later runs should be 936 # We need these reference values to determine if later runs should be
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
978 else: 1016 else:
979 next_revision_index = int((max_revision - min_revision) / 2) +\ 1017 next_revision_index = int((max_revision - min_revision) / 2) +\
980 min_revision 1018 min_revision
981 1019
982 next_revision_id = revision_list[next_revision_index] 1020 next_revision_id = revision_list[next_revision_index]
983 next_revision_data = revision_data[next_revision_id] 1021 next_revision_data = revision_data[next_revision_id]
984 next_revision_depot = next_revision_data['depot'] 1022 next_revision_depot = next_revision_data['depot']
985 1023
986 self.ChangeToDepotWorkingDirectory(next_revision_depot) 1024 self.ChangeToDepotWorkingDirectory(next_revision_depot)
987 1025
1026 if self.opts.output_buildbot_annotations:
1027 step_name = 'Working on [%s]' % next_revision_id
1028 OutputAnnotationStepStart(step_name)
1029
988 print 'Working on revision: [%s]' % next_revision_id 1030 print 'Working on revision: [%s]' % next_revision_id
989 1031
990 run_results = self.SyncBuildAndRunRevision(next_revision_id, 1032 run_results = self.SyncBuildAndRunRevision(next_revision_id,
991 next_revision_depot, 1033 next_revision_depot,
992 command_to_run, 1034 command_to_run,
993 metric) 1035 metric)
994 1036
1037 if self.opts.output_buildbot_annotations:
1038 OutputAnnotationStepClosed()
1039
995 # If the build is successful, check whether or not the metric 1040 # If the build is successful, check whether or not the metric
996 # had regressed. 1041 # had regressed.
997 if not run_results[1]: 1042 if not run_results[1]:
998 if next_revision_depot == 'chromium': 1043 if next_revision_depot == 'chromium':
999 next_revision_data['external'] = run_results[2] 1044 next_revision_data['external'] = run_results[2]
1000 1045
1001 passed_regression = self.CheckIfRunPassed(run_results[0], 1046 passed_regression = self.CheckIfRunPassed(run_results[0],
1002 known_good_value, 1047 known_good_value,
1003 known_bad_value) 1048 known_bad_value)
1004 1049
(...skipping 21 matching lines...) Expand all
1026 def FormatAndPrintResults(self, bisect_results): 1071 def FormatAndPrintResults(self, bisect_results):
1027 """Prints the results from a bisection run in a readable format. 1072 """Prints the results from a bisection run in a readable format.
1028 1073
1029 Args 1074 Args
1030 bisect_results: The results from a bisection test run. 1075 bisect_results: The results from a bisection test run.
1031 """ 1076 """
1032 revision_data = bisect_results['revision_data'] 1077 revision_data = bisect_results['revision_data']
1033 revision_data_sorted = sorted(revision_data.iteritems(), 1078 revision_data_sorted = sorted(revision_data.iteritems(),
1034 key = lambda x: x[1]['sort']) 1079 key = lambda x: x[1]['sort'])
1035 1080
1081 if self.opts.output_buildbot_annotations:
1082 OutputAnnotationStepStart('Results')
1083
1036 print 1084 print
1037 print 'Full results of bisection:' 1085 print 'Full results of bisection:'
1038 for current_id, current_data in revision_data_sorted: 1086 for current_id, current_data in revision_data_sorted:
1039 build_status = current_data['passed'] 1087 build_status = current_data['passed']
1040 1088
1041 if type(build_status) is bool: 1089 if type(build_status) is bool:
1042 build_status = int(build_status) 1090 build_status = int(build_status)
1043 1091
1044 print ' %8s %s %s' % (current_data['depot'], current_id, build_status) 1092 print ' %8s %s %s' % (current_data['depot'], current_id, build_status)
1045 print 1093 print
1046 1094
1047 # Find range where it possibly broke. 1095 # Find range where it possibly broke.
1048 first_working_revision = None 1096 first_working_revision = None
1049 last_broken_revision = None 1097 last_broken_revision = None
1050 1098
1051 for k, v in revision_data_sorted: 1099 for k, v in revision_data_sorted:
1052 if v['passed'] == 1: 1100 if v['passed'] == 1:
1053 if not first_working_revision: 1101 if not first_working_revision:
1054 first_working_revision = k 1102 first_working_revision = k
1055 1103
1056 if not v['passed']: 1104 if not v['passed']:
1057 last_broken_revision = k 1105 last_broken_revision = k
1058 1106
1059 if last_broken_revision != None and first_working_revision != None: 1107 if last_broken_revision != None and first_working_revision != None:
1060 print 'Results: Regression was detected as a result of changes on:' 1108 print 'Results: Regression may have occurred in range:'
1061 print ' -> First Bad Revision: [%s] [%s]' %\ 1109 print ' -> First Bad Revision: [%s] [%s]' %\
1062 (last_broken_revision, 1110 (last_broken_revision,
1063 revision_data[last_broken_revision]['depot']) 1111 revision_data[last_broken_revision]['depot'])
1064 print ' -> Last Good Revision: [%s] [%s]' %\ 1112 print ' -> Last Good Revision: [%s] [%s]' %\
1065 (first_working_revision, 1113 (first_working_revision,
1066 revision_data[first_working_revision]['depot']) 1114 revision_data[first_working_revision]['depot'])
1067 1115
1116 if self.opts.output_buildbot_annotations:
1117 OutputAnnotationStepClosed()
1118
1068 1119
1069 def DetermineAndCreateSourceControl(): 1120 def DetermineAndCreateSourceControl():
1070 """Attempts to determine the underlying source control workflow and returns 1121 """Attempts to determine the underlying source control workflow and returns
1071 a SourceControl object. 1122 a SourceControl object.
1072 1123
1073 Returns: 1124 Returns:
1074 An instance of a SourceControl object, or None if the current workflow 1125 An instance of a SourceControl object, or None if the current workflow
1075 is unsupported. 1126 is unsupported.
1076 """ 1127 """
1077 1128
(...skipping 27 matching lines...) Expand all
1105 help='A revision to start bisection where performance' + 1156 help='A revision to start bisection where performance' +
1106 ' test is known to pass. Must be earlier than the ' + 1157 ' test is known to pass. Must be earlier than the ' +
1107 'bad revision. May be either a git or svn revision.') 1158 'bad revision. May be either a git or svn revision.')
1108 parser.add_option('-m', '--metric', 1159 parser.add_option('-m', '--metric',
1109 type='str', 1160 type='str',
1110 help='The desired metric to bisect on. For example ' + 1161 help='The desired metric to bisect on. For example ' +
1111 '"vm_rss_final_b/vm_rss_f_b"') 1162 '"vm_rss_final_b/vm_rss_f_b"')
1112 parser.add_option('--use_goma', 1163 parser.add_option('--use_goma',
1113 action="store_true", 1164 action="store_true",
1114 help='Add a bunch of extra threads for goma.') 1165 help='Add a bunch of extra threads for goma.')
1166 parser.add_option('--output_buildbot_annotations',
1167 action="store_true",
1168 help='Add extra annotation output for buildbot.')
1115 parser.add_option('--debug_ignore_build', 1169 parser.add_option('--debug_ignore_build',
1116 action="store_true", 1170 action="store_true",
1117 help='DEBUG: Don\'t perform builds.') 1171 help='DEBUG: Don\'t perform builds.')
1118 parser.add_option('--debug_ignore_sync', 1172 parser.add_option('--debug_ignore_sync',
1119 action="store_true", 1173 action="store_true",
1120 help='DEBUG: Don\'t perform syncs.') 1174 help='DEBUG: Don\'t perform syncs.')
1121 parser.add_option('--debug_ignore_perf_test', 1175 parser.add_option('--debug_ignore_perf_test',
1122 action="store_true", 1176 action="store_true",
1123 help='DEBUG: Don\'t perform performance tests.') 1177 help='DEBUG: Don\'t perform performance tests.')
1124 (opts, args) = parser.parse_args() 1178 (opts, args) = parser.parse_args()
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
1185 if not(bisect_results['error']): 1239 if not(bisect_results['error']):
1186 bisect_test.FormatAndPrintResults(bisect_results) 1240 bisect_test.FormatAndPrintResults(bisect_results)
1187 return 0 1241 return 0
1188 else: 1242 else:
1189 print 'Error: ' + bisect_results['error'] 1243 print 'Error: ' + bisect_results['error']
1190 print 1244 print
1191 return 1 1245 return 1
1192 1246
1193 if __name__ == '__main__': 1247 if __name__ == '__main__':
1194 sys.exit(main()) 1248 sys.exit(main())
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