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

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