| OLD | NEW |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """Pulls historical try job metadata from Findit and prints a report.""" | 5 """Pulls historical try job metadata from Findit and prints a report.""" |
| 6 | 6 |
| 7 from collections import defaultdict | 7 from collections import defaultdict |
| 8 import datetime | 8 import datetime |
| 9 import os | 9 import os |
| 10 import sys | 10 import sys |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 def _FormatSecondsAsHMS(seconds): | 36 def _FormatSecondsAsHMS(seconds): |
| 37 """Formats the number of seconds into hours, minutes, seconds.""" | 37 """Formats the number of seconds into hours, minutes, seconds.""" |
| 38 if seconds == NOT_AVAILABLE: | 38 if seconds == NOT_AVAILABLE: |
| 39 return NOT_AVAILABLE | 39 return NOT_AVAILABLE |
| 40 | 40 |
| 41 minutes, seconds = divmod(seconds, 60) | 41 minutes, seconds = divmod(seconds, 60) |
| 42 hours, minutes = divmod(minutes, 60) | 42 hours, minutes = divmod(minutes, 60) |
| 43 return '%d:%02d:%02d' % (hours, minutes, seconds) | 43 return '%d:%02d:%02d' % (hours, minutes, seconds) |
| 44 | 44 |
| 45 | 45 |
| 46 def _CategorizeTryJobDataByMasterAndBuilder(try_job_data_list): | 46 def _CategorizeTryJobData(try_job_data_list): |
| 47 """Categorizes try_job_data_list into a dict by master_name and builder_name. | 47 """Categorizes try_job_data_list into a dict. |
| 48 | 48 |
| 49 Args: | 49 Args: |
| 50 try_job_data_list: A list of WfTryJobData objects. | 50 try_job_data_list: A list of WfTryJobData objects. |
| 51 | 51 |
| 52 Returns: | 52 Returns: |
| 53 A dict in the format: | 53 A dict in the format: |
| 54 | |
| 55 { | 54 { |
| 56 'master_name1': { | 55 'compile': { |
| 57 'builder_name1': [WfTryJobData1, WfTryJobData2, ...], | 56 'master_name1': { |
| 58 'builder_name2': [WfTryJobData3, ...] | 57 'builder_name1': [WfTryJobData1, WfTryJobData2, ...], |
| 58 'builder_name2': [WfTryJobData3, ...] |
| 59 }, |
| 60 'master_name2: { |
| 61 ... |
| 62 } |
| 59 }, | 63 }, |
| 60 'master_name2: { | 64 'test': { |
| 61 ... | 65 ... |
| 62 } | 66 } |
| 63 } | 67 } |
| 64 """ | 68 """ |
| 65 categorized_data = defaultdict(lambda: defaultdict(list)) | 69 categorized_data = { |
| 70 'compile': defaultdict(lambda: defaultdict(list)), |
| 71 'test': defaultdict(lambda: defaultdict(list)) |
| 72 } |
| 73 |
| 66 for try_job_data in try_job_data_list: | 74 for try_job_data in try_job_data_list: |
| 67 master_name = try_job_data.master_name | 75 master_name = try_job_data.master_name |
| 68 builder_name = try_job_data.builder_name | 76 builder_name = try_job_data.builder_name |
| 69 | 77 |
| 70 if not master_name or not builder_name: | 78 if not master_name or not builder_name: |
| 71 continue | 79 continue |
| 72 | 80 |
| 73 categorized_data[master_name][builder_name].append(try_job_data) | 81 try_job_type = try_job_data.try_job_type |
| 82 |
| 83 categorized_data[try_job_type][master_name][builder_name].append( |
| 84 try_job_data) |
| 74 | 85 |
| 75 return categorized_data | 86 return categorized_data |
| 76 | 87 |
| 77 | 88 |
| 78 def _GetReportInformation(try_job_data_list, start_date, end_date): | 89 def _GetReportInformation(try_job_data_list, start_date, end_date): |
| 79 """Computes and returns try job metadata. | 90 """Computes and returns try job metadata. |
| 80 | 91 |
| 81 Args: | 92 Args: |
| 82 try_job_data_list: A list of WfTryJobData entities. | 93 try_job_data_list: A list of WfTryJobData entities. |
| 83 start_date: The earliest request date to compute data. | 94 start_date: The earliest request date to compute data. |
| 84 end_date: The latest request date to compute data. | 95 end_date: The latest request date to compute data. |
| 85 | 96 |
| 86 Returns: | 97 Returns: |
| 87 A dict in the following format: | 98 A dict in the following format: |
| 88 { | 99 { |
| 89 'try_jobs_per_day': The average number of jobs requested over the time | 100 'try_jobs_per_day': The average number of jobs requested over the time |
| 90 period specified, | 101 period specified, |
| 91 'average_regression_range_size': The average number of revisions in the | 102 'average_regression_range_size': The average number of revisions in the |
| 92 regression range when the original failure was detected, | 103 regression range when the original failure was detected, |
| 93 'average_execution_time': The average amount of time spent on each try | 104 'average_execution_time': The average amount of time spent on each try |
| 94 job not including in-queue time. | 105 job not including in-queue time. |
| 95 'average_time_in_queue': The average amount of time a try job spends | 106 'average_time_in_queue': The average amount of time a try job spends |
| 96 in-queue before it is picked up. | 107 in-queue before it is picked up. |
| 97 'average_commits_analyzed': The average number of revisions each try job | 108 'average_commits_analyzed': The average number of revisions each try job |
| 98 needed to run before coming to a conclusion, | 109 needed to run before coming to a conclusion, |
| 99 'longest_execution_time': The length of time of the slowest try job, | 110 'longest_execution_time': The length of time of the slowest try job, |
| 100 'shortest_execution_time': The length of time of the fastest try job, | 111 'shortest_execution_time': The length of time of the fastest try job, |
| 101 'number_of_compile_try_jobs': The number of try jobs for 'compile', | 112 'number_of_try_jobs': The number of try jobs in this list, |
| 102 'number_of_test_try_jobs': The number of try jobs for 'test', | |
| 103 'detection_rate': The number of try jobs that found any culprits at all | 113 'detection_rate': The number of try jobs that found any culprits at all |
| 104 regardless of correctness over the total number of try jobs. | 114 regardless of correctness over the total number of try jobs. |
| 105 } | 115 } |
| 106 """ | 116 """ |
| 107 try_jobs_per_day = NOT_AVAILABLE | 117 try_jobs_per_day = NOT_AVAILABLE |
| 108 average_regression_range_size = NOT_AVAILABLE | 118 average_regression_range_size = NOT_AVAILABLE |
| 109 average_execution_time = NOT_AVAILABLE | 119 average_execution_time = NOT_AVAILABLE |
| 110 average_time_in_queue = NOT_AVAILABLE | 120 average_time_in_queue = NOT_AVAILABLE |
| 111 average_commits_analyzed = NOT_AVAILABLE | 121 average_commits_analyzed = NOT_AVAILABLE |
| 112 longest_execution_time = NOT_AVAILABLE | 122 longest_execution_time = NOT_AVAILABLE |
| 113 shortest_execution_time = NOT_AVAILABLE | 123 shortest_execution_time = NOT_AVAILABLE |
| 114 compile_try_jobs = NOT_AVAILABLE | |
| 115 test_try_jobs = NOT_AVAILABLE | |
| 116 detection_rate = NOT_AVAILABLE | 124 detection_rate = NOT_AVAILABLE |
| 117 compile_try_jobs = NOT_AVAILABLE | 125 number_of_try_jobs = len(try_job_data_list) if try_job_data_list else 0 |
| 118 test_try_jobs = NOT_AVAILABLE | |
| 119 | 126 |
| 120 if try_job_data_list: | 127 if try_job_data_list: |
| 121 try_jobs_per_day = ( | 128 try_jobs_per_day = ( |
| 122 len(try_job_data_list) / float((end_date - start_date).days)) | 129 len(try_job_data_list) / float((end_date - start_date).days)) |
| 123 regression_range_sizes = [] | 130 regression_range_sizes = [] |
| 124 execution_times_seconds = [] | 131 execution_times_seconds = [] |
| 125 in_queue_times = [] | 132 in_queue_times = [] |
| 126 commits_analyzed = [] | 133 commits_analyzed = [] |
| 127 culprits_detected = 0 | 134 culprits_detected = 0 |
| 128 compile_try_jobs = 0 | |
| 129 test_try_jobs = 0 | |
| 130 | 135 |
| 131 for try_job_data in try_job_data_list: | 136 for try_job_data in try_job_data_list: |
| 132 # Regression range size. | 137 # Regression range size. |
| 133 if try_job_data.regression_range_size: | 138 if try_job_data.regression_range_size: |
| 134 regression_range_sizes.append(try_job_data.regression_range_size) | 139 regression_range_sizes.append(try_job_data.regression_range_size) |
| 135 | 140 |
| 136 # Execution time. | 141 # Execution time. |
| 137 if try_job_data.start_time and try_job_data.end_time: | 142 if try_job_data.start_time and try_job_data.end_time: |
| 138 execution_times_seconds.append( | 143 execution_times_seconds.append( |
| 139 (try_job_data.end_time - try_job_data.start_time).seconds) | 144 (try_job_data.end_time - try_job_data.start_time).seconds) |
| 140 | 145 |
| 141 # In-queue time. | 146 # In-queue time. |
| 142 if try_job_data.start_time and try_job_data.request_time: | 147 if try_job_data.start_time and try_job_data.request_time: |
| 143 in_queue_times.append( | 148 in_queue_times.append( |
| 144 (try_job_data.start_time - try_job_data.request_time).seconds) | 149 (try_job_data.start_time - try_job_data.request_time).seconds) |
| 145 | 150 |
| 146 # Number of commits analyzed. | 151 # Number of commits analyzed. |
| 147 if try_job_data.number_of_commits_analyzed: | 152 if try_job_data.number_of_commits_analyzed: |
| 148 commits_analyzed.append(try_job_data.number_of_commits_analyzed) | 153 commits_analyzed.append(try_job_data.number_of_commits_analyzed) |
| 149 | 154 |
| 150 # Culprit detection rate. | 155 # Culprit detection rate. |
| 151 if try_job_data.culprits: | 156 if try_job_data.culprits: |
| 152 culprits_detected += 1 | 157 culprits_detected += 1 |
| 153 | 158 |
| 154 # Try job types. | |
| 155 if try_job_data.try_job_type == 'compile': | |
| 156 compile_try_jobs += 1 | |
| 157 elif try_job_data.try_job_type == 'test': | |
| 158 test_try_jobs += 1 | |
| 159 | |
| 160 average_regression_range_size = _GetAverageOfNumbersInList( | 159 average_regression_range_size = _GetAverageOfNumbersInList( |
| 161 regression_range_sizes) | 160 regression_range_sizes) |
| 162 average_execution_time = (_GetAverageOfNumbersInList( | 161 average_execution_time = (_GetAverageOfNumbersInList( |
| 163 execution_times_seconds) if execution_times_seconds else NOT_AVAILABLE) | 162 execution_times_seconds) if execution_times_seconds else NOT_AVAILABLE) |
| 164 average_time_in_queue = ( | 163 average_time_in_queue = ( |
| 165 _GetAverageOfNumbersInList(in_queue_times) if in_queue_times else | 164 _GetAverageOfNumbersInList(in_queue_times) if in_queue_times else |
| 166 NOT_AVAILABLE) | 165 NOT_AVAILABLE) |
| 167 average_commits_analyzed = _GetAverageOfNumbersInList( | 166 average_commits_analyzed = _GetAverageOfNumbersInList( |
| 168 commits_analyzed) | 167 commits_analyzed) |
| 169 longest_execution_time = ( | 168 longest_execution_time = ( |
| 170 str(datetime.timedelta(seconds=max(execution_times_seconds))) | 169 str(datetime.timedelta(seconds=max(execution_times_seconds))) |
| 171 if execution_times_seconds else NOT_AVAILABLE) | 170 if execution_times_seconds else NOT_AVAILABLE) |
| 172 shortest_execution_time = ( | 171 shortest_execution_time = ( |
| 173 str(datetime.timedelta(seconds=min(execution_times_seconds))) | 172 str(datetime.timedelta(seconds=min(execution_times_seconds))) |
| 174 if execution_times_seconds else NOT_AVAILABLE) | 173 if execution_times_seconds else NOT_AVAILABLE) |
| 175 detection_rate = float(culprits_detected) / len(try_job_data_list) | 174 detection_rate = float(culprits_detected) / len(try_job_data_list) |
| 176 | 175 |
| 177 return { | 176 return { |
| 178 'try_jobs_per_day': try_jobs_per_day, | 177 'try_jobs_per_day': try_jobs_per_day, |
| 179 'average_regression_range_size': average_regression_range_size, | 178 'average_regression_range_size': average_regression_range_size, |
| 180 'average_execution_time': average_execution_time, | 179 'average_execution_time': average_execution_time, |
| 181 'average_time_in_queue': average_time_in_queue, | 180 'average_time_in_queue': average_time_in_queue, |
| 182 'average_commits_analyzed': average_commits_analyzed, | 181 'average_commits_analyzed': average_commits_analyzed, |
| 183 'longest_execution_time': longest_execution_time, | 182 'longest_execution_time': longest_execution_time, |
| 184 'shortest_execution_time': shortest_execution_time, | 183 'shortest_execution_time': shortest_execution_time, |
| 185 'number_of_compile_try_jobs': compile_try_jobs, | 184 'number_of_try_jobs': number_of_try_jobs, |
| 186 'number_of_test_try_jobs': test_try_jobs, | |
| 187 'detection_rate': detection_rate | 185 'detection_rate': detection_rate |
| 188 } | 186 } |
| 189 | 187 |
| 190 | 188 |
| 191 def _GetReportListForMastersAndBuilders(supported_masters_to_builders, | 189 def _GetReportListForMastersAndBuilders(supported_masters_to_builders, |
| 192 sorted_try_job_data_dict, start_date, | 190 categorized_data_dict, |
| 193 end_date): | 191 start_date, end_date): |
| 194 """Gets a full try job data report of each master and builder. | 192 """Gets a full try job data report of each master and builder. |
| 195 | 193 |
| 196 Args: | 194 Args: |
| 197 supported_masters_to_builders: Findit's config for mapping masters to | 195 supported_masters_to_builders: Findit's config for mapping masters to |
| 198 builders. | 196 builders. |
| 199 sorted_try_job_data_dict: A 2-layer dict mapping masters to builders | 197 categorized_data_dict: A dict mapping try job types to masters, masters to |
| 200 and builders to lists of WfTryJobData objects. This dict should be the | 198 builders, and builders to lists of WfTryJobData objects. This dict should |
| 201 output of _SortTryJobDataByMasterAndBuilder(). | 199 be the output of _CategorizeTryJobData(). |
| 202 start_date: The earliest request date for which data should be computed. | 200 start_date: The earliest request date for which data should be computed. |
| 203 end_date: The latest request date for which data should be computed. | 201 end_date: The latest request date for which data should be computed. |
| 204 | 202 |
| 205 Returns: | 203 Returns: |
| 206 A list of dicts of masters to builders, with the metadata associated with | 204 A list of dicts of masters to builders, with the metadata associated with |
| 207 each builder based on the data provided in all_try_job_data_list in the | 205 each builder based on the data provided in all_try_job_data_list in the |
| 208 format [supported_dict, unsupported_dict]. All supported masters and | 206 format [supported_dict, unsupported_dict]. All supported masters and |
| 209 builders are accounted for even if there is no data, and all available data | 207 builders are accounted for even if there is no data, and all available data |
| 210 is displayed even if support for it has been deprecated. | 208 is displayed even if support for it has been deprecated. |
| 211 | |
| 212 [ | 209 [ |
| 213 { | 210 { |
| 214 'master_name': { | 211 'compile': { |
| 215 'builder_name': { | 212 'master_name': { |
| 216 'try_jobs_per_day': 1 or 'N/A', | 213 'builder_name': { |
| 217 'average_regression_range_size': 1 or 'N/A', | 214 'try_jobs_per_day': 1 or 'N/A', |
| 218 'average_execution_time': 1 or 'N/A', | 215 'average_regression_range_size': 1 or 'N/A', |
| 219 'average_time_in_queue': 1 or 'N/A', | 216 'average_execution_time': 1 or 'N/A', |
| 220 'average_commits_analyzed': 1 or 'N/A', | 217 'average_time_in_queue': 1 or 'N/A', |
| 221 'longest_execution_time': 1 or 'N/A', | 218 'average_commits_analyzed': 1 or 'N/A', |
| 222 'shortest_execution_time': 1 or 'N/A', | 219 'longest_execution_time': 1 or 'N/A', |
| 223 'number_of_compile_try_jobs': 1 or 'N/A', | 220 'shortest_execution_time': 1 or 'N/A', |
| 224 'number_of_test_try_jobs': 1 or 'N/A', | 221 'number_of_try_jobs': 1 or 'N/A', |
| 225 'detection_rate': 0.0-1.0 or 'N/A', | 222 'detection_rate': 0.0-1.0 or 'N/A', |
| 226 }, | 223 }, |
| 227 ... | 224 ... |
| 228 }, | 225 }, |
| 226 }, |
| 227 'test': { |
| 228 .... |
| 229 } |
| 229 ... | 230 ... |
| 230 }, | 231 }, |
| 231 { | 232 { |
| 232 'master_name': { | 233 'compile': ..., |
| 233 'builder_name': { | 234 'test': ... |
| 234 ... | |
| 235 } | |
| 236 } | |
| 237 } | 235 } |
| 238 ] | 236 ] |
| 239 """ | 237 """ |
| 240 supported = {} | 238 supported = defaultdict(dict) |
| 241 unsupported = {} | 239 unsupported = defaultdict(dict) |
| 242 | |
| 243 report = [supported, unsupported] | 240 report = [supported, unsupported] |
| 244 | 241 |
| 245 # Build the supported report according to Findit's config. | 242 # Build the supported report according to Findit's config. |
| 246 for master, builders in supported_masters_to_builders.iteritems(): | 243 for master, builders in supported_masters_to_builders.iteritems(): |
| 247 supported[master] = {} | 244 supported['compile'][master] = {} |
| 245 supported['test'][master] = {} |
| 246 |
| 248 for builder in builders: | 247 for builder in builders: |
| 249 try_job_data_list = sorted_try_job_data_dict.get(master, {}).get(builder) | 248 compile_try_job_data_list = ( |
| 250 supported[master][builder] = _GetReportInformation( | 249 categorized_data_dict.get('compile').get(master, {}).get(builder)) |
| 251 try_job_data_list, start_date, end_date) | 250 test_try_job_data_list = ( |
| 251 categorized_data_dict.get('test').get(master, {}).get(builder)) |
| 252 supported['compile'][master][builder] = _GetReportInformation( |
| 253 compile_try_job_data_list, start_date, end_date) |
| 254 supported['test'][master][builder] = _GetReportInformation( |
| 255 test_try_job_data_list, start_date, end_date) |
| 252 | 256 |
| 253 # Build the unsupported report according to what's in the try job data list | 257 # Build the unsupported report according to what's in the try job data list |
| 254 # but not found in Findit's config. | 258 # but not found in Findit's config. |
| 255 for master, builders in sorted_try_job_data_dict.iteritems(): | 259 for try_job_type, try_job_data_dict in categorized_data_dict.iteritems(): |
| 256 unsupported[master] = {} | 260 for master, builders in try_job_data_dict.iteritems(): |
| 257 for builder in builders: | 261 unsupported[try_job_type][master] = {} |
| 258 if not supported_masters_to_builders.get(master, {}).get(builder): | 262 |
| 259 try_job_data_list = sorted_try_job_data_dict[master][builder] | 263 for builder in builders: |
| 260 unsupported[master][builder] = _GetReportInformation( | 264 if not supported_masters_to_builders.get(master, {}).get(builder): |
| 261 try_job_data_list, start_date, end_date) | 265 try_job_data_list = ( |
| 266 categorized_data_dict[try_job_type][master][builder]) |
| 267 unsupported[try_job_type][master][builder] = _GetReportInformation( |
| 268 try_job_data_list, start_date, end_date) |
| 262 | 269 |
| 263 return report | 270 return report |
| 264 | 271 |
| 265 | 272 |
| 266 def CreateHtmlPage(report_list, start_date, end_date): | 273 def CreateHtmlPage(report_list, start_date, end_date): |
| 267 """Generates an html string for displaying the report. | 274 """Generates an html string for displaying the report. |
| 268 | 275 |
| 269 Args: | 276 Args: |
| 270 report_list: A list of 2 report dicts. The first is expected to contain data | 277 report_list: A list of 2 report dicts. The first is expected to contain data |
| 271 for masters and builders that are supported as specified by Findit's | 278 for masters and builders that are supported as specified by Findit's |
| (...skipping 11 matching lines...) Expand all Loading... |
| 283 border-collapse: collapse; | 290 border-collapse: collapse; |
| 284 border: 1px solid gray; | 291 border: 1px solid gray; |
| 285 } | 292 } |
| 286 table td, th { | 293 table td, th { |
| 287 border: 1px solid gray; | 294 border: 1px solid gray; |
| 288 } | 295 } |
| 289 </style>""" | 296 </style>""" |
| 290 | 297 |
| 291 html += '<b>Try job metadata from %s to %s (%s days)</b>' % ( | 298 html += '<b>Try job metadata from %s to %s (%s days)</b>' % ( |
| 292 str(start_date), str(end_date), (end_date - start_date).days) | 299 str(start_date), str(end_date), (end_date - start_date).days) |
| 293 html += """ | 300 html += '<h1>Aggregate metadata for try jobs per master/builder</h1>' |
| 294 <h1>Aggregate metadata for try jobs per master/builder</h1> | |
| 295 <table> | |
| 296 <tr> | |
| 297 <th>Master</th> | |
| 298 <th>Builder</th> | |
| 299 <th># Try Jobs Per Day</th> | |
| 300 <th>Average Regression Range Size</th> | |
| 301 <th>Average Number Of Revisions Analyzed</th> | |
| 302 <th>Average Time In Queue (HH:MM:SS)</th> | |
| 303 <th>Average Execution Time (HH:MM:SS)</th> | |
| 304 <th>Longest Execution Time (HH:MM:SS)</th> | |
| 305 <th>Shortest Execution Time (HH:MM:SS)</th> | |
| 306 <th>Culprit Detection Rate</th> | |
| 307 <th>Number of Compile Try Jobs</th> | |
| 308 <th>Number of Test Try Jobs</th> | |
| 309 </tr>""" | |
| 310 | 301 |
| 311 for i in range(len(report_list)): | 302 for i in range(len(report_list)): |
| 312 cell_template = '<td>%s</td>' if i == 0 else '<td bgcolor="#CCCCCC">%s</td>' | 303 if i == 0: # Supported dict. |
| 304 html += '<h2>Supported Masters/Builders</h2>' |
| 305 cell_template = '<td>%s</td>' |
| 306 else: # Unsupported dict. |
| 307 html += '<h2>Unsupported Masters/Builders</h2>' |
| 308 cell_template = '<td bgcolor="#CCCCCC">%s</td>' |
| 309 |
| 313 report = report_list[i] | 310 report = report_list[i] |
| 314 for master_name, builder_reports in report.iteritems(): | 311 for try_job_type, try_job_report in report.iteritems(): |
| 315 for builder_name in builder_reports: | 312 html += '<h3>Try job type: %s</h3>' % try_job_type |
| 316 builder_report = report[master_name][builder_name] | 313 html += """ |
| 317 html += '<tr>' | 314 <table> |
| 318 html += cell_template % master_name | 315 <tr> |
| 319 html += cell_template % builder_name | 316 <th>Master</th> |
| 320 html += cell_template % _FormatDigits( | 317 <th>Builder</th> |
| 321 builder_report['try_jobs_per_day']) | 318 <th># Try Jobs Per Day</th> |
| 322 html += cell_template % _FormatDigits( | 319 <th>Average Regression Range Size</th> |
| 323 builder_report['average_regression_range_size']) | 320 <th>Average # Revisions Analyzed</th> |
| 324 html += cell_template % _FormatDigits( | 321 <th>Average Time In Queue</th> |
| 325 builder_report['average_commits_analyzed']) | 322 <th>Average Execution Time</th> |
| 326 html += cell_template % _FormatSecondsAsHMS(_FormatDigits( | 323 <th>Longest Execution Time</th> |
| 327 builder_report['average_time_in_queue'])) | 324 <th>Shortest Execution Time</th> |
| 328 html += cell_template % _FormatSecondsAsHMS(_FormatDigits( | 325 <th>Culprit Detection Rate</th> |
| 329 builder_report['average_execution_time'])) | 326 <th># Try Jobs</th> |
| 330 html += cell_template % builder_report['longest_execution_time'] | 327 </tr>""" |
| 331 html += cell_template % builder_report['shortest_execution_time'] | |
| 332 html += cell_template % _FormatDigits(builder_report['detection_rate']) | |
| 333 html += cell_template % builder_report['number_of_compile_try_jobs'] | |
| 334 html += cell_template % builder_report['number_of_test_try_jobs'] | |
| 335 | 328 |
| 336 html += '</tr></thead><tbody>' | 329 for master_name, builder_reports in try_job_report.iteritems(): |
| 337 html += """ | 330 for builder_name in builder_reports: |
| 338 </tbody> | 331 builder_report = report[try_job_type][master_name][builder_name] |
| 339 </table>""" | 332 html += '<tr>' |
| 333 html += cell_template % master_name |
| 334 html += cell_template % builder_name |
| 335 html += cell_template % _FormatDigits( |
| 336 builder_report['try_jobs_per_day']) |
| 337 html += cell_template % _FormatDigits( |
| 338 builder_report['average_regression_range_size']) |
| 339 html += cell_template % _FormatDigits( |
| 340 builder_report['average_commits_analyzed']) |
| 341 html += cell_template % _FormatSecondsAsHMS(_FormatDigits( |
| 342 builder_report['average_time_in_queue'])) |
| 343 html += cell_template % _FormatSecondsAsHMS(_FormatDigits( |
| 344 builder_report['average_execution_time'])) |
| 345 html += cell_template % builder_report['longest_execution_time'] |
| 346 html += cell_template % builder_report['shortest_execution_time'] |
| 347 html += cell_template % _FormatDigits( |
| 348 builder_report['detection_rate']) |
| 349 html += cell_template % builder_report['number_of_try_jobs'] |
| 350 html += '</tr>' |
| 351 |
| 352 html += '</table>' |
| 340 | 353 |
| 341 return html | 354 return html |
| 342 | 355 |
| 356 |
| 343 if __name__ == '__main__': | 357 if __name__ == '__main__': |
| 344 # Set up the Remote API to use services on the live App Engine. | 358 # Set up the Remote API to use services on the live App Engine. |
| 345 remote_api.EnableRemoteApi(app_id='findit-for-me') | 359 remote_api.EnableRemoteApi(app_id='findit-for-me') |
| 346 | 360 |
| 347 START_DATE = datetime.datetime(2016, 2, 1) | 361 START_DATE = datetime.datetime(2016, 2, 1) |
| 348 END_DATE = datetime.datetime(2016, 2, 17) | 362 END_DATE = datetime.datetime(2016, 3, 8) |
| 349 | 363 |
| 350 wf_analysis_query = WfTryJobData.query( | 364 wf_analysis_query = WfTryJobData.query( |
| 351 WfTryJobData.request_time >= START_DATE, | 365 WfTryJobData.request_time >= START_DATE, |
| 352 WfTryJobData.request_time < END_DATE) | 366 WfTryJobData.request_time < END_DATE) |
| 353 data_list = wf_analysis_query.fetch() | 367 data_list = wf_analysis_query.fetch() |
| 354 | 368 |
| 355 masters_to_builders = FinditConfig.Get().builders_to_trybots | 369 masters_to_builders = FinditConfig.Get().builders_to_trybots |
| 356 categorized_data_dict = _CategorizeTryJobDataByMasterAndBuilder(data_list) | 370 data = _CategorizeTryJobData(data_list) |
| 357 full_report_list = _GetReportListForMastersAndBuilders( | 371 full_report_list = _GetReportListForMastersAndBuilders( |
| 358 masters_to_builders, categorized_data_dict, START_DATE, END_DATE) | 372 masters_to_builders, data, START_DATE, END_DATE) |
| 359 | 373 |
| 360 findit_tmp_dir = os.environ.get('TMP_DIR') | 374 findit_tmp_dir = os.environ.get('TMP_DIR') |
| 361 if not findit_tmp_dir: | 375 if not findit_tmp_dir: |
| 362 findit_tmp_dir = os.getcwd() | 376 findit_tmp_dir = os.getcwd() |
| 363 | 377 |
| 364 report_path = os.path.join(findit_tmp_dir, 'try_job_data_report.html') | 378 report_path = os.path.join(findit_tmp_dir, 'try_job_data_report.html') |
| 365 | 379 |
| 366 with open(report_path, 'w') as f: | 380 with open(report_path, 'w') as f: |
| 367 f.write(CreateHtmlPage(full_report_list, START_DATE, END_DATE)) | 381 f.write(CreateHtmlPage(full_report_list, START_DATE, END_DATE)) |
| 368 | 382 |
| 369 print 'Try job metadata report available at file://%s' % report_path | 383 print 'Try job metadata report available at file://%s' % report_path |
| OLD | NEW |