| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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 """Script to parse perf data from Chrome Endure test executions, to be graphed. | 6 """Script to parse perf data from Chrome Endure test executions, to be graphed. |
| 7 | 7 |
| 8 This script connects via HTTP to a buildbot master in order to scrape and parse | 8 This script connects via HTTP to a buildbot master in order to scrape and parse |
| 9 perf data from Chrome Endure tests that have been run. The perf data is then | 9 perf data from Chrome Endure tests that have been run. The perf data is then |
| 10 stored in local text files to be graphed by the Chrome Endure graphing code. | 10 stored in local text files to be graphed by the Chrome Endure graphing code. |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 elif int(line_dict['rev']) < int(revision): | 105 elif int(line_dict['rev']) < int(revision): |
| 106 break | 106 break |
| 107 if not overwritten: | 107 if not overwritten: |
| 108 existing_lines.insert(0, simplejson.dumps(new_line)) | 108 existing_lines.insert(0, simplejson.dumps(new_line)) |
| 109 | 109 |
| 110 with open(data_file, 'w') as f: | 110 with open(data_file, 'w') as f: |
| 111 f.write('\n'.join(existing_lines)) | 111 f.write('\n'.join(existing_lines)) |
| 112 os.chmod(data_file, 0755) | 112 os.chmod(data_file, 0755) |
| 113 | 113 |
| 114 | 114 |
| 115 def OutputPerfData(revision, graph_name, description, value, units, units_x, | 115 def OutputPerfData(revision, graph_name, values, units, units_x, dest_dir): |
| 116 dest_dir): | |
| 117 """Outputs perf data to a local text file to be graphed. | 116 """Outputs perf data to a local text file to be graphed. |
| 118 | 117 |
| 119 Args: | 118 Args: |
| 120 revision: The string revision number associated with the perf data. | 119 revision: The string revision number associated with the perf data. |
| 121 graph_name: The string name of the graph on which to plot the data. | 120 graph_name: The string name of the graph on which to plot the data. |
| 122 description: A string description of the perf value to be graphed. | 121 values: A dict which maps a description to a value. A value is either a |
| 123 value: Either a single data value to be graphed, or a list of 2-tuples | 122 single data value to be graphed, or a list of 2-tuples |
| 124 representing (x, y) points to be graphed for long-running tests. | 123 representing (x, y) points to be graphed for long-running tests. |
| 125 units: The string description for the y-axis units on the graph. | 124 units: The string description for the y-axis units on the graph. |
| 126 units_x: The string description for the x-axis units on the graph. Should | 125 units_x: The string description for the x-axis units on the graph. Should |
| 127 be set to None if the results are not for long-running graphs. | 126 be set to None if the results are not for long-running graphs. |
| 128 dest_dir: The name of the destination directory to which to write. | 127 dest_dir: The name of the destination directory to which to write. |
| 129 """ | 128 """ |
| 130 # Update graphs.dat, which contains metadata associated with each graph. | 129 # Update graphs.dat, which contains metadata associated with each graph. |
| 131 existing_graphs = [] | 130 existing_graphs = [] |
| 132 graphs_file = os.path.join(dest_dir, 'graphs.dat') | 131 graphs_file = os.path.join(dest_dir, 'graphs.dat') |
| 133 if os.path.exists(graphs_file): | 132 if os.path.exists(graphs_file): |
| (...skipping 19 matching lines...) Expand all Loading... |
| 153 os.chmod(graphs_file, 0755) | 152 os.chmod(graphs_file, 0755) |
| 154 | 153 |
| 155 # Update summary data file, containing the actual data to be graphed. | 154 # Update summary data file, containing the actual data to be graphed. |
| 156 data_file_name = graph_name + '-summary.dat' | 155 data_file_name = graph_name + '-summary.dat' |
| 157 existing_lines = [] | 156 existing_lines = [] |
| 158 data_file = os.path.join(dest_dir, data_file_name) | 157 data_file = os.path.join(dest_dir, data_file_name) |
| 159 if os.path.exists(data_file): | 158 if os.path.exists(data_file): |
| 160 with open(data_file, 'r') as f: | 159 with open(data_file, 'r') as f: |
| 161 existing_lines = f.readlines() | 160 existing_lines = f.readlines() |
| 162 existing_lines = map(lambda x: x.strip(), existing_lines) | 161 existing_lines = map(lambda x: x.strip(), existing_lines) |
| 163 if units_x: | 162 new_traces = {} |
| 164 points = [] | 163 for description in values: |
| 165 for point in value: | 164 value = values[description] |
| 166 points.append([str(point[0]), str(point[1])]) | 165 if units_x: |
| 167 new_traces = { | 166 points = [] |
| 168 description: points | 167 for point in value: |
| 169 } | 168 points.append([str(point[0]), str(point[1])]) |
| 170 else: | 169 new_traces[description] = points |
| 171 new_traces = { | 170 else: |
| 172 description: [str(value), str(0.0)] | 171 new_traces[description] = [str(value), str(0.0)] |
| 173 } | |
| 174 new_line = { | 172 new_line = { |
| 175 'traces': new_traces, | 173 'traces': new_traces, |
| 176 'rev': revision | 174 'rev': revision |
| 177 } | 175 } |
| 178 | 176 |
| 179 WriteToDataFile(new_line, existing_lines, revision, data_file) | 177 WriteToDataFile(new_line, existing_lines, revision, data_file) |
| 180 | 178 |
| 181 | 179 |
| 182 def OutputEventData(revision, description, event_list, dest_dir): | 180 def OutputEventData(revision, event_dict, dest_dir): |
| 183 """Outputs event data to a local text file to be graphed. | 181 """Outputs event data to a local text file to be graphed. |
| 184 | 182 |
| 185 Args: | 183 Args: |
| 186 revision: The string revision number associated with the event data. | 184 revision: The string revision number associated with the event data. |
| 187 description: A string description of the event values to be graphed. | 185 event_dict: A dict which maps a description to an array of tuples |
| 188 event_list: An array of tuples representing event data to be graphed. | 186 representing event data to be graphed. |
| 189 dest_dir: The name of the destination directory to which to write. | 187 dest_dir: The name of the destination directory to which to write. |
| 190 """ | 188 """ |
| 191 data_file_name = '_EVENT_-summary.dat' | 189 data_file_name = '_EVENT_-summary.dat' |
| 192 existing_lines = [] | 190 existing_lines = [] |
| 193 data_file = os.path.join(dest_dir, data_file_name) | 191 data_file = os.path.join(dest_dir, data_file_name) |
| 194 if os.path.exists(data_file): | 192 if os.path.exists(data_file): |
| 195 with open(data_file, 'r') as f: | 193 with open(data_file, 'r') as f: |
| 196 existing_lines = f.readlines() | 194 existing_lines = f.readlines() |
| 197 existing_lines = map(lambda x: x.strip(), existing_lines) | 195 existing_lines = map(lambda x: x.strip(), existing_lines) |
| 198 | 196 |
| 199 value_list = [] | 197 new_events = {} |
| 200 for event_time, event_data in event_list: | 198 for description in event_dict: |
| 201 value_list.append([str(event_time), event_data]) | 199 event_list = event_dict[description] |
| 202 new_events = { | 200 value_list = [] |
| 203 description: value_list | 201 for event_time, event_data in event_list: |
| 204 } | 202 value_list.append([str(event_time), event_data]) |
| 203 new_events[description] = value_list |
| 205 | 204 |
| 206 new_line = { | 205 new_line = { |
| 207 'rev': revision, | 206 'rev': revision, |
| 208 'events': new_events | 207 'events': new_events |
| 209 } | 208 } |
| 210 | 209 |
| 211 WriteToDataFile(new_line, existing_lines, revision, data_file) | 210 WriteToDataFile(new_line, existing_lines, revision, data_file) |
| 212 | 211 |
| 213 | 212 |
| 214 def UpdatePerfDataForSlaveAndBuild(slave_info, build_num): | 213 def UpdatePerfDataForSlaveAndBuild(slave_info, build_num): |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 332 AppendRawPerfData('_EVENT_', match[0], eval(match[1]), None, None, | 331 AppendRawPerfData('_EVENT_', match[0], eval(match[1]), None, None, |
| 333 stdio_url_data['webapp_name'], | 332 stdio_url_data['webapp_name'], |
| 334 stdio_url_data['test_name']) | 333 stdio_url_data['test_name']) |
| 335 | 334 |
| 336 # For each graph_name/description pair that refers to a long-running test | 335 # For each graph_name/description pair that refers to a long-running test |
| 337 # result or an event, concatenate all the results together (assume results | 336 # result or an event, concatenate all the results together (assume results |
| 338 # in the input file are in the correct order). For short-running test | 337 # in the input file are in the correct order). For short-running test |
| 339 # results, keep just one if more than one is specified. | 338 # results, keep just one if more than one is specified. |
| 340 perf_data = {} # Maps a graph-line key to a perf data dictionary. | 339 perf_data = {} # Maps a graph-line key to a perf data dictionary. |
| 341 for data in perf_data_raw: | 340 for data in perf_data_raw: |
| 342 key = data['graph_name'] + '|' + data['description'] | 341 key_graph = data['graph_name'] |
| 342 key_description = data['description'] |
| 343 if not key_graph in perf_data: |
| 344 perf_data[key_graph] = { |
| 345 'graph_name': data['graph_name'], |
| 346 'value': {}, |
| 347 'units': data['units'], |
| 348 'units_x': data['units_x'], |
| 349 'webapp_name': data['webapp_name'], |
| 350 'test_name': data['test_name'], |
| 351 } |
| 343 if data['graph_name'] != '_EVENT_' and not data['units_x']: | 352 if data['graph_name'] != '_EVENT_' and not data['units_x']: |
| 344 # Short-running test result. | 353 # Short-running test result. |
| 345 perf_data[key] = data | 354 perf_data[key_graph]['value'][key_description] = data['value'] |
| 346 else: | 355 else: |
| 347 # Long-running test result or event. | 356 # Long-running test result or event. |
| 348 if key in perf_data: | 357 if key_description in perf_data[key_graph]['value']: |
| 349 perf_data[key]['value'] += data['value'] | 358 perf_data[key_graph]['value'][key_description] += data['value'] |
| 350 else: | 359 else: |
| 351 perf_data[key] = data | 360 perf_data[key_graph]['value'][key_description] = data['value'] |
| 352 | 361 |
| 353 # Finally, for each graph-line in |perf_data|, update the associated local | 362 # Finally, for each graph-line in |perf_data|, update the associated local |
| 354 # graph data files if necessary. | 363 # graph data files if necessary. |
| 355 for perf_data_key in perf_data: | 364 for perf_data_key in perf_data: |
| 356 perf_data_dict = perf_data[perf_data_key] | 365 perf_data_dict = perf_data[perf_data_key] |
| 357 | 366 |
| 358 dest_dir = os.path.join(LOCAL_GRAPH_DIR, perf_data_dict['webapp_name']) | 367 dest_dir = os.path.join(LOCAL_GRAPH_DIR, perf_data_dict['webapp_name']) |
| 359 if not os.path.exists(dest_dir): | 368 if not os.path.exists(dest_dir): |
| 360 os.mkdir(dest_dir) # Webapp name directory. | 369 os.mkdir(dest_dir) # Webapp name directory. |
| 361 os.chmod(dest_dir, 0755) | 370 os.chmod(dest_dir, 0755) |
| 362 dest_dir = os.path.join(dest_dir, perf_data_dict['test_name']) | 371 dest_dir = os.path.join(dest_dir, perf_data_dict['test_name']) |
| 363 | 372 |
| 364 SetupBaseGraphDirIfNeeded(perf_data_dict['webapp_name'], | 373 SetupBaseGraphDirIfNeeded(perf_data_dict['webapp_name'], |
| 365 perf_data_dict['test_name'], dest_dir) | 374 perf_data_dict['test_name'], dest_dir) |
| 366 if perf_data_dict['graph_name'] == '_EVENT_': | 375 if perf_data_dict['graph_name'] == '_EVENT_': |
| 367 OutputEventData(revision, perf_data_dict['description'], | 376 OutputEventData(revision, perf_data_dict['value'], dest_dir) |
| 368 perf_data_dict['value'], dest_dir) | |
| 369 else: | 377 else: |
| 370 OutputPerfData(revision, perf_data_dict['graph_name'], | 378 OutputPerfData(revision, perf_data_dict['graph_name'], |
| 371 perf_data_dict['description'], perf_data_dict['value'], | 379 perf_data_dict['value'], |
| 372 perf_data_dict['units'], perf_data_dict['units_x'], | 380 perf_data_dict['units'], perf_data_dict['units_x'], |
| 373 dest_dir) | 381 dest_dir) |
| 374 | 382 |
| 375 return True | 383 return True |
| 376 | 384 |
| 377 | 385 |
| 378 def UpdatePerfDataFiles(): | 386 def UpdatePerfDataFiles(): |
| 379 """Updates the Chrome Endure graph data files with the latest test results. | 387 """Updates the Chrome Endure graph data files with the latest test results. |
| 380 | 388 |
| 381 For each known Chrome Endure slave, we scan its latest test results looking | 389 For each known Chrome Endure slave, we scan its latest test results looking |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 587 if not success: | 595 if not success: |
| 588 logging.error('Failed to update perf data files.') | 596 logging.error('Failed to update perf data files.') |
| 589 sys.exit(0) | 597 sys.exit(0) |
| 590 | 598 |
| 591 GenerateIndexPage() | 599 GenerateIndexPage() |
| 592 logging.debug('All done!') | 600 logging.debug('All done!') |
| 593 | 601 |
| 594 | 602 |
| 595 if __name__ == '__main__': | 603 if __name__ == '__main__': |
| 596 main() | 604 main() |
| OLD | NEW |