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

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 list_length = len(revision_list)
tonyg 2013/02/14 01:21:01 inline?
shatch 2013/02/14 01:37:47 Done.
802 step_name = 'Bisection Range: [%s - %s]' %\
803 (revision_list[list_length-1], revision_list[0])
tonyg 2013/02/14 01:21:01 indent continued line by 4 spaces
shatch 2013/02/14 01:37:47 Done.
804 OutputAnnotationStepStart(step_name)
805
782 print 806 print
783 print 'Revisions to bisect on [%s]:' % depot 807 print 'Revisions to bisect on [%s]:' % depot
784 for revision_id in revision_list: 808 for revision_id in revision_list:
785 print ' -> %s' % (revision_id, ) 809 print ' -> %s' % (revision_id, )
786 print 810 print
787 811
812 if self.opts.output_buildbot_annotations:
813 OutputAnnotationStepClosed()
814
788 def Run(self, command_to_run, bad_revision_in, good_revision_in, metric): 815 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 816 """Given known good and bad revisions, run a binary search on all
790 intermediate revisions to determine the CL where the performance regression 817 intermediate revisions to determine the CL where the performance regression
791 occurred. 818 occurred.
792 819
793 Args: 820 Args:
794 command_to_run: Specify the command to execute the performance test. 821 command_to_run: Specify the command to execute the performance test.
795 good_revision: Number/tag of the known good revision. 822 good_revision: Number/tag of the known good revision.
796 bad_revision: Number/tag of the known bad revision. 823 bad_revision: Number/tag of the known bad revision.
797 metric: The performance metric to monitor. 824 metric: The performance metric to monitor.
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
839 'src') 866 'src')
840 867
841 if bad_revision is None: 868 if bad_revision is None:
842 results['error'] = 'Could\'t resolve [%s] to SHA1.' % (bad_revision_in,) 869 results['error'] = 'Could\'t resolve [%s] to SHA1.' % (bad_revision_in,)
843 return results 870 return results
844 871
845 if good_revision is None: 872 if good_revision is None:
846 results['error'] = 'Could\'t resolve [%s] to SHA1.' % (good_revision_in,) 873 results['error'] = 'Could\'t resolve [%s] to SHA1.' % (good_revision_in,)
847 return results 874 return results
848 875
876 if self.opts.output_buildbot_annotations:
877 OutputAnnotationStepStart('Gathering Revisions')
878
849 print 'Gathering revision range for bisection.' 879 print 'Gathering revision range for bisection.'
850 880
851 # Retrieve a list of revisions to do bisection on. 881 # Retrieve a list of revisions to do bisection on.
852 src_revision_list = self.GetRevisionList(bad_revision, good_revision) 882 src_revision_list = self.GetRevisionList(bad_revision, good_revision)
853 883
884 if self.opts.output_buildbot_annotations:
885 OutputAnnotationStepClosed()
886
854 if src_revision_list: 887 if src_revision_list:
855 # revision_data will store information about a revision such as the 888 # revision_data will store information about a revision such as the
856 # depot it came from, the webkit/V8 revision at that time, 889 # depot it came from, the webkit/V8 revision at that time,
857 # performance timing, build state, etc... 890 # performance timing, build state, etc...
858 revision_data = results['revision_data'] 891 revision_data = results['revision_data']
859 892
860 # revision_list is the list we're binary searching through at the moment. 893 # revision_list is the list we're binary searching through at the moment.
861 revision_list = [] 894 revision_list = []
862 895
863 sort_key_ids = 0 896 sort_key_ids = 0
864 897
865 for current_revision_id in src_revision_list: 898 for current_revision_id in src_revision_list:
866 sort_key_ids += 1 899 sort_key_ids += 1
867 900
868 revision_data[current_revision_id] = {'value' : None, 901 revision_data[current_revision_id] = {'value' : None,
869 'passed' : '?', 902 'passed' : '?',
870 'depot' : 'chromium', 903 'depot' : 'chromium',
871 'external' : None, 904 'external' : None,
872 'sort' : sort_key_ids} 905 'sort' : sort_key_ids}
873 revision_list.append(current_revision_id) 906 revision_list.append(current_revision_id)
874 907
875 min_revision = 0 908 min_revision = 0
876 max_revision = len(revision_list) - 1 909 max_revision = len(revision_list) - 1
877 910
878 self.PrintRevisionsToBisectMessage(revision_list, 'src') 911 self.PrintRevisionsToBisectMessage(revision_list, 'src')
879 912
913 if self.opts.output_buildbot_annotations:
914 OutputAnnotationStepStart('Gathering Reference Values')
915
880 print 'Gathering reference values for bisection.' 916 print 'Gathering reference values for bisection.'
881 917
882 # Perform the performance tests on the good and bad revisions, to get 918 # Perform the performance tests on the good and bad revisions, to get
883 # reference values. 919 # reference values.
884 (bad_results, good_results) = self.GatherReferenceValues(good_revision, 920 (bad_results, good_results) = self.GatherReferenceValues(good_revision,
885 bad_revision, 921 bad_revision,
886 command_to_run, 922 command_to_run,
887 metric) 923 metric)
888 924
925 if self.opts.output_buildbot_annotations:
926 OutputAnnotationStepClosed()
927
889 if bad_results[1]: 928 if bad_results[1]:
890 results['error'] = bad_results[0] 929 results['error'] = bad_results[0]
891 return results 930 return results
892 931
893 if good_results[1]: 932 if good_results[1]:
894 results['error'] = good_results[0] 933 results['error'] = good_results[0]
895 return results 934 return results
896 935
897 936
898 # We need these reference values to determine if later runs should be 937 # 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: 1017 else:
979 next_revision_index = int((max_revision - min_revision) / 2) +\ 1018 next_revision_index = int((max_revision - min_revision) / 2) +\
980 min_revision 1019 min_revision
981 1020
982 next_revision_id = revision_list[next_revision_index] 1021 next_revision_id = revision_list[next_revision_index]
983 next_revision_data = revision_data[next_revision_id] 1022 next_revision_data = revision_data[next_revision_id]
984 next_revision_depot = next_revision_data['depot'] 1023 next_revision_depot = next_revision_data['depot']
985 1024
986 self.ChangeToDepotWorkingDirectory(next_revision_depot) 1025 self.ChangeToDepotWorkingDirectory(next_revision_depot)
987 1026
1027 if self.opts.output_buildbot_annotations:
1028 step_name = 'Working on [%s]' % next_revision_id
1029 OutputAnnotationStepStart(step_name)
1030
988 print 'Working on revision: [%s]' % next_revision_id 1031 print 'Working on revision: [%s]' % next_revision_id
989 1032
990 run_results = self.SyncBuildAndRunRevision(next_revision_id, 1033 run_results = self.SyncBuildAndRunRevision(next_revision_id,
991 next_revision_depot, 1034 next_revision_depot,
992 command_to_run, 1035 command_to_run,
993 metric) 1036 metric)
994 1037
1038 if self.opts.output_buildbot_annotations:
1039 OutputAnnotationStepClosed()
1040
995 # If the build is successful, check whether or not the metric 1041 # If the build is successful, check whether or not the metric
996 # had regressed. 1042 # had regressed.
997 if not run_results[1]: 1043 if not run_results[1]:
998 if next_revision_depot == 'chromium': 1044 if next_revision_depot == 'chromium':
999 next_revision_data['external'] = run_results[2] 1045 next_revision_data['external'] = run_results[2]
1000 1046
1001 passed_regression = self.CheckIfRunPassed(run_results[0], 1047 passed_regression = self.CheckIfRunPassed(run_results[0],
1002 known_good_value, 1048 known_good_value,
1003 known_bad_value) 1049 known_bad_value)
1004 1050
(...skipping 21 matching lines...) Expand all
1026 def FormatAndPrintResults(self, bisect_results): 1072 def FormatAndPrintResults(self, bisect_results):
1027 """Prints the results from a bisection run in a readable format. 1073 """Prints the results from a bisection run in a readable format.
1028 1074
1029 Args 1075 Args
1030 bisect_results: The results from a bisection test run. 1076 bisect_results: The results from a bisection test run.
1031 """ 1077 """
1032 revision_data = bisect_results['revision_data'] 1078 revision_data = bisect_results['revision_data']
1033 revision_data_sorted = sorted(revision_data.iteritems(), 1079 revision_data_sorted = sorted(revision_data.iteritems(),
1034 key = lambda x: x[1]['sort']) 1080 key = lambda x: x[1]['sort'])
1035 1081
1082 if self.opts.output_buildbot_annotations:
1083 OutputAnnotationStepStart('Results')
1084
1036 print 1085 print
1037 print 'Full results of bisection:' 1086 print 'Full results of bisection:'
1038 for current_id, current_data in revision_data_sorted: 1087 for current_id, current_data in revision_data_sorted:
1039 build_status = current_data['passed'] 1088 build_status = current_data['passed']
1040 1089
1041 if type(build_status) is bool: 1090 if type(build_status) is bool:
1042 build_status = int(build_status) 1091 build_status = int(build_status)
1043 1092
1044 print ' %8s %s %s' % (current_data['depot'], current_id, build_status) 1093 print ' %8s %s %s' % (current_data['depot'], current_id, build_status)
1045 print 1094 print
1046 1095
1047 # Find range where it possibly broke. 1096 # Find range where it possibly broke.
1048 first_working_revision = None 1097 first_working_revision = None
1049 last_broken_revision = None 1098 last_broken_revision = None
1050 1099
1051 for k, v in revision_data_sorted: 1100 for k, v in revision_data_sorted:
1052 if v['passed'] == 1: 1101 if v['passed'] == 1:
1053 if not first_working_revision: 1102 if not first_working_revision:
1054 first_working_revision = k 1103 first_working_revision = k
1055 1104
1056 if not v['passed']: 1105 if not v['passed']:
1057 last_broken_revision = k 1106 last_broken_revision = k
1058 1107
1059 if last_broken_revision != None and first_working_revision != None: 1108 if last_broken_revision != None and first_working_revision != None:
1060 print 'Results: Regression was detected as a result of changes on:' 1109 print 'Results: Regression may have occurred in range:'
1061 print ' -> First Bad Revision: [%s] [%s]' %\ 1110 print ' -> First Bad Revision: [%s] [%s]' %\
1062 (last_broken_revision, 1111 (last_broken_revision,
1063 revision_data[last_broken_revision]['depot']) 1112 revision_data[last_broken_revision]['depot'])
1064 print ' -> Last Good Revision: [%s] [%s]' %\ 1113 print ' -> Last Good Revision: [%s] [%s]' %\
1065 (first_working_revision, 1114 (first_working_revision,
1066 revision_data[first_working_revision]['depot']) 1115 revision_data[first_working_revision]['depot'])
1067 1116
1117 if self.opts.output_buildbot_annotations:
1118 OutputAnnotationStepClosed()
1119
1068 1120
1069 def DetermineAndCreateSourceControl(): 1121 def DetermineAndCreateSourceControl():
1070 """Attempts to determine the underlying source control workflow and returns 1122 """Attempts to determine the underlying source control workflow and returns
1071 a SourceControl object. 1123 a SourceControl object.
1072 1124
1073 Returns: 1125 Returns:
1074 An instance of a SourceControl object, or None if the current workflow 1126 An instance of a SourceControl object, or None if the current workflow
1075 is unsupported. 1127 is unsupported.
1076 """ 1128 """
1077 1129
(...skipping 27 matching lines...) Expand all
1105 help='A revision to start bisection where performance' + 1157 help='A revision to start bisection where performance' +
1106 ' test is known to pass. Must be earlier than the ' + 1158 ' test is known to pass. Must be earlier than the ' +
1107 'bad revision. May be either a git or svn revision.') 1159 'bad revision. May be either a git or svn revision.')
1108 parser.add_option('-m', '--metric', 1160 parser.add_option('-m', '--metric',
1109 type='str', 1161 type='str',
1110 help='The desired metric to bisect on. For example ' + 1162 help='The desired metric to bisect on. For example ' +
1111 '"vm_rss_final_b/vm_rss_f_b"') 1163 '"vm_rss_final_b/vm_rss_f_b"')
1112 parser.add_option('--use_goma', 1164 parser.add_option('--use_goma',
1113 action="store_true", 1165 action="store_true",
1114 help='Add a bunch of extra threads for goma.') 1166 help='Add a bunch of extra threads for goma.')
1167 parser.add_option('--output_buildbot_annotations',
1168 action="store_true",
1169 help='Add extra annotation output for buildbot.')
1115 parser.add_option('--debug_ignore_build', 1170 parser.add_option('--debug_ignore_build',
1116 action="store_true", 1171 action="store_true",
1117 help='DEBUG: Don\'t perform builds.') 1172 help='DEBUG: Don\'t perform builds.')
1118 parser.add_option('--debug_ignore_sync', 1173 parser.add_option('--debug_ignore_sync',
1119 action="store_true", 1174 action="store_true",
1120 help='DEBUG: Don\'t perform syncs.') 1175 help='DEBUG: Don\'t perform syncs.')
1121 parser.add_option('--debug_ignore_perf_test', 1176 parser.add_option('--debug_ignore_perf_test',
1122 action="store_true", 1177 action="store_true",
1123 help='DEBUG: Don\'t perform performance tests.') 1178 help='DEBUG: Don\'t perform performance tests.')
1124 (opts, args) = parser.parse_args() 1179 (opts, args) = parser.parse_args()
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
1185 if not(bisect_results['error']): 1240 if not(bisect_results['error']):
1186 bisect_test.FormatAndPrintResults(bisect_results) 1241 bisect_test.FormatAndPrintResults(bisect_results)
1187 return 0 1242 return 0
1188 else: 1243 else:
1189 print 'Error: ' + bisect_results['error'] 1244 print 'Error: ' + bisect_results['error']
1190 print 1245 print
1191 return 1 1246 return 1
1192 1247
1193 if __name__ == '__main__': 1248 if __name__ == '__main__':
1194 sys.exit(main()) 1249 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