Chromium Code Reviews| 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 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 111 elif int(line_dict['rev']) < int(revision): | 111 elif int(line_dict['rev']) < int(revision): |
| 112 break | 112 break |
| 113 if not overwritten: | 113 if not overwritten: |
| 114 existing_lines.insert(0, simplejson.dumps(new_line)) | 114 existing_lines.insert(0, simplejson.dumps(new_line)) |
| 115 | 115 |
| 116 with open(data_file, 'w') as f: | 116 with open(data_file, 'w') as f: |
| 117 f.write('\n'.join(existing_lines)) | 117 f.write('\n'.join(existing_lines)) |
| 118 os.chmod(data_file, 0755) | 118 os.chmod(data_file, 0755) |
| 119 | 119 |
| 120 | 120 |
| 121 def OutputPerfData(revision, graph_name, description, value, units, units_x, | 121 def OutputPerfData(revision, graph_name, values, units, units_x, dest_dir): |
| 122 dest_dir): | |
| 123 """Outputs perf data to a local text file to be graphed. | 122 """Outputs perf data to a local text file to be graphed. |
| 124 | 123 |
| 125 Args: | 124 Args: |
| 126 revision: The string revision number associated with the perf data. | 125 revision: The string revision number associated with the perf data. |
| 127 graph_name: The string name of the graph on which to plot the data. | 126 graph_name: The string name of the graph on which to plot the data. |
| 128 description: A string description of the perf value to be graphed. | 127 values: A dict which maps a description to a value. A value is either a |
| 129 value: Either a single data value to be graphed, or a list of 2-tuples | 128 single data value to be graphed, or a list of 2-tuples |
| 130 representing (x, y) points to be graphed for long-running tests. | 129 representing (x, y) points to be graphed for long-running tests. |
| 131 units: The string description for the y-axis units on the graph. | 130 units: The string description for the y-axis units on the graph. |
| 132 units_x: The string description for the x-axis units on the graph. Should | 131 units_x: The string description for the x-axis units on the graph. Should |
| 133 be set to None if the results are not for long-running graphs. | 132 be set to None if the results are not for long-running graphs. |
| 134 dest_dir: The name of the destination directory to which to write. | 133 dest_dir: The name of the destination directory to which to write. |
| 135 """ | 134 """ |
| 136 # Update graphs.dat, which contains metadata associated with each graph. | 135 # Update graphs.dat, which contains metadata associated with each graph. |
| 137 existing_graphs = [] | 136 existing_graphs = [] |
| 138 graphs_file = os.path.join(dest_dir, 'graphs.dat') | 137 graphs_file = os.path.join(dest_dir, 'graphs.dat') |
| 139 if os.path.exists(graphs_file): | 138 if os.path.exists(graphs_file): |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 159 os.chmod(graphs_file, 0755) | 158 os.chmod(graphs_file, 0755) |
| 160 | 159 |
| 161 # Update summary data file, containing the actual data to be graphed. | 160 # Update summary data file, containing the actual data to be graphed. |
| 162 data_file_name = graph_name + '-summary.dat' | 161 data_file_name = graph_name + '-summary.dat' |
| 163 existing_lines = [] | 162 existing_lines = [] |
| 164 data_file = os.path.join(dest_dir, data_file_name) | 163 data_file = os.path.join(dest_dir, data_file_name) |
| 165 if os.path.exists(data_file): | 164 if os.path.exists(data_file): |
| 166 with open(data_file, 'r') as f: | 165 with open(data_file, 'r') as f: |
| 167 existing_lines = f.readlines() | 166 existing_lines = f.readlines() |
| 168 existing_lines = map(lambda x: x.strip(), existing_lines) | 167 existing_lines = map(lambda x: x.strip(), existing_lines) |
| 169 if units_x: | 168 new_traces = {} |
| 170 points = [] | 169 for description in values: |
| 171 for point in value: | 170 value = values[description] |
| 172 points.append([str(point[0]), str(point[1])]) | 171 if units_x: |
| 173 new_traces = { | 172 points = [] |
| 174 description: points | 173 for point in value: |
| 175 } | 174 points.append([str(point[0]), str(point[1])]) |
| 176 else: | 175 new_traces[description] = points |
| 177 new_traces = { | 176 else: |
| 178 description: [str(value), str(0.0)] | 177 new_traces[description] = [str(value), str(0.0)] |
| 179 } | |
| 180 new_line = { | 178 new_line = { |
| 181 'traces': new_traces, | 179 'traces': new_traces, |
| 182 'rev': revision | 180 'rev': revision |
| 183 } | 181 } |
| 184 | 182 |
| 185 WriteToDataFile(new_line, existing_lines, revision, data_file) | 183 WriteToDataFile(new_line, existing_lines, revision, data_file) |
| 186 | 184 |
| 187 | 185 |
| 188 def OutputEventData(revision, description, event_list, dest_dir): | 186 def OutputEventData(revision, event_dict, dest_dir): |
| 189 """Outputs event data to a local text file to be graphed. | 187 """Outputs event data to a local text file to be graphed. |
| 190 | 188 |
| 191 Args: | 189 Args: |
| 192 revision: The string revision number associated with the event data. | 190 revision: The string revision number associated with the event data. |
| 193 description: A string description of the event values to be graphed. | 191 event_dict: A dict which maps a description to an array of tuples |
| 194 event_list: An array of tuples representing event data to be graphed. | 192 representing event data to be graphed. |
| 195 dest_dir: The name of the destination directory to which to write. | 193 dest_dir: The name of the destination directory to which to write. |
| 196 """ | 194 """ |
| 197 data_file_name = '_EVENT_-summary.dat' | 195 data_file_name = '_EVENT_-summary.dat' |
| 198 existing_lines = [] | 196 existing_lines = [] |
| 199 data_file = os.path.join(dest_dir, data_file_name) | 197 data_file = os.path.join(dest_dir, data_file_name) |
| 200 if os.path.exists(data_file): | 198 if os.path.exists(data_file): |
| 201 with open(data_file, 'r') as f: | 199 with open(data_file, 'r') as f: |
| 202 existing_lines = f.readlines() | 200 existing_lines = f.readlines() |
| 203 existing_lines = map(lambda x: x.strip(), existing_lines) | 201 existing_lines = map(lambda x: x.strip(), existing_lines) |
| 204 | 202 |
| 205 value_list = [] | 203 new_events = {} |
| 206 for event_time, event_data in event_list: | 204 for description in event_dict: |
| 207 value_list.append([str(event_time), event_data]) | 205 event_list = event_dict[description] |
| 208 new_events = { | 206 value_list = [] |
| 209 description: value_list | 207 for event_time, event_data in event_list: |
| 210 } | 208 value_list.append([str(event_time), event_data]) |
| 209 new_events[description] = value_list | |
| 211 | 210 |
| 212 new_line = { | 211 new_line = { |
| 213 'rev': revision, | 212 'rev': revision, |
| 214 'events': new_events | 213 'events': new_events |
| 215 } | 214 } |
| 216 | 215 |
| 217 WriteToDataFile(new_line, existing_lines, revision, data_file) | 216 WriteToDataFile(new_line, existing_lines, revision, data_file) |
| 218 | 217 |
| 219 | 218 |
| 220 def UpdatePerfDataForSlaveAndBuild(slave_info, build_num): | 219 def UpdatePerfDataForSlaveAndBuild(slave_info, build_num): |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 338 AppendRawPerfData('_EVENT_', match[0], eval(match[1]), None, None, | 337 AppendRawPerfData('_EVENT_', match[0], eval(match[1]), None, None, |
| 339 stdio_url_data['webapp_name'], | 338 stdio_url_data['webapp_name'], |
| 340 stdio_url_data['test_name']) | 339 stdio_url_data['test_name']) |
| 341 | 340 |
| 342 # For each graph_name/description pair that refers to a long-running test | 341 # For each graph_name/description pair that refers to a long-running test |
| 343 # result or an event, concatenate all the results together (assume results | 342 # result or an event, concatenate all the results together (assume results |
| 344 # in the input file are in the correct order). For short-running test | 343 # in the input file are in the correct order). For short-running test |
| 345 # results, keep just one if more than one is specified. | 344 # results, keep just one if more than one is specified. |
| 346 perf_data = {} # Maps a graph-line key to a perf data dictionary. | 345 perf_data = {} # Maps a graph-line key to a perf data dictionary. |
| 347 for data in perf_data_raw: | 346 for data in perf_data_raw: |
| 348 key = data['graph_name'] + '|' + data['description'] | 347 key1 = data['graph_name'] |
|
dennis_jeffrey
2012/09/26 00:34:29
use a more descriptive variable name, such as "key
Dai Mikurube (NOT FULLTIME)
2012/09/26 02:44:51
Done.
| |
| 348 key2 = data['description'] | |
|
dennis_jeffrey
2012/09/26 00:34:29
use a more descriptive variable name, such as "key
Dai Mikurube (NOT FULLTIME)
2012/09/26 02:44:51
Done.
| |
| 349 if not key1 in perf_data: | |
| 350 perf_data[key1] = { | |
| 351 'graph_name': data['graph_name'], | |
| 352 'value': {}, | |
| 353 'units': data['units'], | |
| 354 'units_x': data['units_x'], | |
| 355 'webapp_name': data['webapp_name'], | |
| 356 'test_name': data['test_name'], | |
| 357 } | |
| 349 if data['graph_name'] != '_EVENT_' and not data['units_x']: | 358 if data['graph_name'] != '_EVENT_' and not data['units_x']: |
| 350 # Short-running test result. | 359 # Short-running test result. |
| 351 perf_data[key] = data | 360 perf_data[key1]['value'][key2] = data['value'] |
| 352 else: | 361 else: |
| 353 # Long-running test result or event. | 362 # Long-running test result or event. |
| 354 if key in perf_data: | 363 if key2 in perf_data[key1]['value']: |
| 355 perf_data[key]['value'] += data['value'] | 364 perf_data[key1]['value'][key2] += data['value'] |
| 356 else: | 365 else: |
| 357 perf_data[key] = data | 366 perf_data[key1]['value'][key2] = data['value'] |
| 358 | 367 |
| 359 # Finally, for each graph-line in |perf_data|, update the associated local | 368 # Finally, for each graph-line in |perf_data|, update the associated local |
| 360 # graph data files if necessary. | 369 # graph data files if necessary. |
| 361 for perf_data_key in perf_data: | 370 for perf_data_key in perf_data: |
| 362 perf_data_dict = perf_data[perf_data_key] | 371 perf_data_dict = perf_data[perf_data_key] |
| 363 | 372 |
| 364 dest_dir = os.path.join(LOCAL_GRAPH_DIR, perf_data_dict['webapp_name']) | 373 dest_dir = os.path.join(LOCAL_GRAPH_DIR, perf_data_dict['webapp_name']) |
| 365 if not os.path.exists(dest_dir): | 374 if not os.path.exists(dest_dir): |
| 366 os.mkdir(dest_dir) # Webapp name directory. | 375 os.mkdir(dest_dir) # Webapp name directory. |
| 367 os.chmod(dest_dir, 0755) | 376 os.chmod(dest_dir, 0755) |
| 368 dest_dir = os.path.join(dest_dir, perf_data_dict['test_name']) | 377 dest_dir = os.path.join(dest_dir, perf_data_dict['test_name']) |
| 369 | 378 |
| 370 SetupBaseGraphDirIfNeeded(perf_data_dict['webapp_name'], | 379 SetupBaseGraphDirIfNeeded(perf_data_dict['webapp_name'], |
| 371 perf_data_dict['test_name'], dest_dir) | 380 perf_data_dict['test_name'], dest_dir) |
| 372 if perf_data_dict['graph_name'] == '_EVENT_': | 381 if perf_data_dict['graph_name'] == '_EVENT_': |
| 373 OutputEventData(revision, perf_data_dict['description'], | 382 OutputEventData(revision, perf_data_dict['value'], dest_dir) |
| 374 perf_data_dict['value'], dest_dir) | |
| 375 else: | 383 else: |
| 376 OutputPerfData(revision, perf_data_dict['graph_name'], | 384 OutputPerfData(revision, perf_data_dict['graph_name'], |
| 377 perf_data_dict['description'], perf_data_dict['value'], | 385 perf_data_dict['value'], |
| 378 perf_data_dict['units'], perf_data_dict['units_x'], | 386 perf_data_dict['units'], perf_data_dict['units_x'], |
| 379 dest_dir) | 387 dest_dir) |
| 380 | 388 |
| 381 return True | 389 return True |
| 382 | 390 |
| 383 | 391 |
| 384 def UpdatePerfDataFiles(): | 392 def UpdatePerfDataFiles(): |
| 385 """Updates the Chrome Endure graph data files with the latest test results. | 393 """Updates the Chrome Endure graph data files with the latest test results. |
| 386 | 394 |
| 387 For each known Chrome Endure slave, we scan its latest test results looking | 395 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... | |
| 593 if not success: | 601 if not success: |
| 594 logging.error('Failed to update perf data files.') | 602 logging.error('Failed to update perf data files.') |
| 595 sys.exit(0) | 603 sys.exit(0) |
| 596 | 604 |
| 597 GenerateIndexPage() | 605 GenerateIndexPage() |
| 598 logging.debug('All done!') | 606 logging.debug('All done!') |
| 599 | 607 |
| 600 | 608 |
| 601 if __name__ == '__main__': | 609 if __name__ == '__main__': |
| 602 main() | 610 main() |
| OLD | NEW |