|
Lines 33-38
import json
Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py_sec1
|
| 33 |
import logging |
33 |
import logging |
| 34 |
import optparse |
34 |
import optparse |
| 35 |
import time |
35 |
import time |
|
|
36 |
import datetime |
| 36 |
|
37 |
|
| 37 |
from webkitpy.common import find_files |
38 |
from webkitpy.common import find_files |
| 38 |
from webkitpy.common.checkout.scm.detection import SCMDetector |
39 |
from webkitpy.common.checkout.scm.detection import SCMDetector |
|
Lines 67-72
class PerfTestsRunner(object):
Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py_sec2
|
| 67 |
self._base_path = self._port.perf_tests_dir() |
68 |
self._base_path = self._port.perf_tests_dir() |
| 68 |
self._results = {} |
69 |
self._results = {} |
| 69 |
self._timestamp = time.time() |
70 |
self._timestamp = time.time() |
|
|
71 |
self._utc_timestamp = datetime.datetime.utcnow() |
| 70 |
self._needs_http = None |
72 |
self._needs_http = None |
| 71 |
self._has_http_lock = False |
73 |
self._has_http_lock = False |
| 72 |
|
74 |
|
|
Lines 126-133
class PerfTestsRunner(object):
Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py_sec3
|
| 126 |
return optparse.OptionParser(option_list=(perf_option_list)).parse_args(args) |
128 |
return optparse.OptionParser(option_list=(perf_option_list)).parse_args(args) |
| 127 |
|
129 |
|
| 128 |
def _collect_tests(self): |
130 |
def _collect_tests(self): |
| 129 |
"""Return the list of tests found.""" |
|
|
| 130 |
|
| 131 |
test_extensions = ['.html', '.svg'] |
131 |
test_extensions = ['.html', '.svg'] |
| 132 |
if self._options.replay: |
132 |
if self._options.replay: |
| 133 |
test_extensions.append('.replay') |
133 |
test_extensions.append('.replay') |
|
Lines 208-231
class PerfTestsRunner(object):
Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py_sec4
|
| 208 |
def _generate_and_show_results(self): |
208 |
def _generate_and_show_results(self): |
| 209 |
options = self._options |
209 |
options = self._options |
| 210 |
output_json_path = self._output_json_path() |
210 |
output_json_path = self._output_json_path() |
| 211 |
output = self._generate_results_dict(self._timestamp, options.description, options.platform, options.builder_name, options.build_number) |
211 |
output, perf_webkit_output = self._generate_results_dict(self._timestamp, options.description, options.platform, options.builder_name, options.build_number) |
| 212 |
|
212 |
|
| 213 |
if options.slave_config_json_path: |
213 |
if options.slave_config_json_path: |
| 214 |
output = self._merge_slave_config_json(options.slave_config_json_path, output) |
214 |
output, perf_webkit_output = self._merge_slave_config_json(options.slave_config_json_path, output, perf_webkit_output) |
| 215 |
if not output: |
215 |
if not output: |
| 216 |
return self.EXIT_CODE_BAD_SOURCE_JSON |
216 |
return self.EXIT_CODE_BAD_SOURCE_JSON |
| 217 |
|
217 |
|
| 218 |
output = self._merge_outputs_if_needed(output_json_path, output) |
218 |
output = self._merge_outputs_if_needed(output_json_path, output) |
| 219 |
if not output: |
219 |
if not output: |
| 220 |
return self.EXIT_CODE_BAD_MERGE |
220 |
return self.EXIT_CODE_BAD_MERGE |
|
|
221 |
perf_webkit_output = [perf_webkit_output] |
| 221 |
|
222 |
|
| 222 |
results_page_path = self._host.filesystem.splitext(output_json_path)[0] + '.html' |
223 |
results_page_path = self._host.filesystem.splitext(output_json_path)[0] + '.html' |
| 223 |
self._generate_output_files(output_json_path, results_page_path, output) |
224 |
perf_webkit_json_path = self._host.filesystem.splitext(output_json_path)[0] + '-perf-webkit.json' if options.test_results_server else None |
|
|
225 |
self._generate_output_files(output_json_path, perf_webkit_json_path, results_page_path, output, perf_webkit_output) |
| 224 |
|
226 |
|
| 225 |
if options.test_results_server: |
227 |
if options.test_results_server: |
| 226 |
if not self._upload_json(options.test_results_server, output_json_path): |
228 |
if not self._upload_json(options.test_results_server, output_json_path): |
| 227 |
return self.EXIT_CODE_FAILED_UPLOADING |
229 |
return self.EXIT_CODE_FAILED_UPLOADING |
| 228 |
|
230 |
|
|
|
231 |
# FIXME: Remove this code once we've made transition to use perf.webkit.org |
| 232 |
if not self._upload_json('perf.webkit.org', perf_webkit_json_path, "/api/report"): |
| 233 |
return self.EXIT_CODE_FAILED_UPLOADING |
| 234 |
|
| 229 |
if options.show_results: |
235 |
if options.show_results: |
| 230 |
self._port.show_results_html_file(results_page_path) |
236 |
self._port.show_results_html_file(results_page_path) |
| 231 |
|
237 |
|
|
Lines 233-241
class PerfTestsRunner(object):
Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py_sec5
|
| 233 |
contents = {'results': self._results} |
239 |
contents = {'results': self._results} |
| 234 |
if description: |
240 |
if description: |
| 235 |
contents['description'] = description |
241 |
contents['description'] = description |
|
|
242 |
|
| 243 |
revisions_for_perf_webkit = {} |
| 236 |
for (name, path) in self._port.repository_paths(): |
244 |
for (name, path) in self._port.repository_paths(): |
| 237 |
scm = SCMDetector(self._host.filesystem, self._host.executive).detect_scm_system(path) or self._host.scm() |
245 |
scm = SCMDetector(self._host.filesystem, self._host.executive).detect_scm_system(path) or self._host.scm() |
| 238 |
contents[name + '-revision'] = scm.svn_revision(path) |
246 |
revision = scm.svn_revision(path) |
|
|
247 |
contents[name.lower() + '-revision'] = revision |
| 248 |
revisions_for_perf_webkit[name] = {'revision': str(revision), 'timestamp': scm.svn_timestamp(path)} |
| 239 |
|
249 |
|
| 240 |
# FIXME: Add --branch or auto-detect the branch we're in |
250 |
# FIXME: Add --branch or auto-detect the branch we're in |
| 241 |
for key, value in {'timestamp': int(timestamp), 'branch': self._default_branch, 'platform': platform, |
251 |
for key, value in {'timestamp': int(timestamp), 'branch': self._default_branch, 'platform': platform, |
|
Lines 243-262
class PerfTestsRunner(object):
Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py_sec6
|
| 243 |
if value: |
253 |
if value: |
| 244 |
contents[key] = value |
254 |
contents[key] = value |
| 245 |
|
255 |
|
| 246 |
return contents |
256 |
contents_for_perf_webkit = { |
|
|
257 |
'builderName': builder_name, |
| 258 |
'buildNumber': str(build_number), |
| 259 |
'buildTime': self._datetime_in_ES5_compatible_iso_format(self._utc_timestamp), |
| 260 |
'platform': platform, |
| 261 |
'revisions': revisions_for_perf_webkit, |
| 262 |
'tests': {}} |
| 247 |
|
263 |
|
| 248 |
def _merge_slave_config_json(self, slave_config_json_path, output): |
264 |
for metric_full_name in self._results: |
|
|
265 |
result = self._results[metric_full_name] |
| 266 |
|
| 267 |
# We can't reprot results without indivisual measurements. |
| 268 |
if not isinstance(result, dict): |
| 269 |
continue |
| 270 |
|
| 271 |
assert metric_full_name.count(':') <= 1 |
| 272 |
test_full_name, _, metric = metric_full_name.partition(':') |
| 273 |
if not metric: |
| 274 |
metric = {'fps': 'FrameRate', 'runs/s': 'Runs', 'ms': 'Time'}[result['unit']] |
| 275 |
|
| 276 |
tests = contents_for_perf_webkit['tests'] |
| 277 |
path = test_full_name.split('/') |
| 278 |
for i in range(0, len(path)): |
| 279 |
# FIXME: We shouldn't assume HTML extension. |
| 280 |
is_last_token = i + 1 == len(path) |
| 281 |
url = 'http://trac.webkit.org/browser/trunk/PerformanceTests/' + '/'.join(path[0:i + 1]) |
| 282 |
if is_last_token: |
| 283 |
url += '.html' |
| 284 |
|
| 285 |
tests.setdefault(path[i], {'url': url}) |
| 286 |
current_test = tests[path[i]] |
| 287 |
if is_last_token: |
| 288 |
current_test.setdefault('metrics', {}) |
| 289 |
assert metric not in current_test['metrics'] |
| 290 |
current_test['metrics'][metric] = {'current': result['values']} |
| 291 |
else: |
| 292 |
current_test.setdefault('tests', {}) |
| 293 |
tests = current_test['tests'] |
| 294 |
|
| 295 |
return contents, contents_for_perf_webkit |
| 296 |
|
| 297 |
@staticmethod |
| 298 |
def _datetime_in_ES5_compatible_iso_format(datetime): |
| 299 |
return datetime.strftime('%Y-%m-%dT%H:%M:%S.%f') |
| 300 |
|
| 301 |
def _merge_slave_config_json(self, slave_config_json_path, contents, contents_for_perf_webkit): |
| 249 |
if not self._host.filesystem.isfile(slave_config_json_path): |
302 |
if not self._host.filesystem.isfile(slave_config_json_path): |
| 250 |
_log.error("Missing slave configuration JSON file: %s" % slave_config_json_path) |
303 |
_log.error("Missing slave configuration JSON file: %s" % slave_config_json_path) |
| 251 |
return None |
304 |
return None, None |
| 252 |
|
305 |
|
| 253 |
try: |
306 |
try: |
| 254 |
slave_config_json = self._host.filesystem.open_text_file_for_reading(slave_config_json_path) |
307 |
slave_config_json = self._host.filesystem.open_text_file_for_reading(slave_config_json_path) |
| 255 |
slave_config = json.load(slave_config_json) |
308 |
slave_config = json.load(slave_config_json) |
| 256 |
return dict(slave_config.items() + output.items()) |
309 |
contents = dict(slave_config.items() + contents.items()) |
|
|
310 |
for key in slave_config: |
| 311 |
contents_for_perf_webkit['builder' + key.capitalize()] = slave_config[key] |
| 312 |
return contents, contents_for_perf_webkit |
| 257 |
except Exception, error: |
313 |
except Exception, error: |
| 258 |
_log.error("Failed to merge slave configuration JSON file %s: %s" % (slave_config_json_path, error)) |
314 |
_log.error("Failed to merge slave configuration JSON file %s: %s" % (slave_config_json_path, error)) |
| 259 |
return None |
315 |
return None, None |
| 260 |
|
316 |
|
| 261 |
def _merge_outputs_if_needed(self, output_json_path, output): |
317 |
def _merge_outputs_if_needed(self, output_json_path, output): |
| 262 |
if self._options.reset_results or not self._host.filesystem.isfile(output_json_path): |
318 |
if self._options.reset_results or not self._host.filesystem.isfile(output_json_path): |
|
Lines 268-279
class PerfTestsRunner(object):
Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py_sec7
|
| 268 |
_log.error("Failed to merge output JSON file %s: %s" % (output_json_path, error)) |
324 |
_log.error("Failed to merge output JSON file %s: %s" % (output_json_path, error)) |
| 269 |
return None |
325 |
return None |
| 270 |
|
326 |
|
| 271 |
def _generate_output_files(self, output_json_path, results_page_path, output): |
327 |
def _generate_output_files(self, output_json_path, perf_webkit_json_path, results_page_path, output, perf_webkit_output): |
| 272 |
filesystem = self._host.filesystem |
328 |
filesystem = self._host.filesystem |
| 273 |
|
329 |
|
| 274 |
json_output = json.dumps(output) |
330 |
json_output = json.dumps(output) |
| 275 |
filesystem.write_text_file(output_json_path, json_output) |
331 |
filesystem.write_text_file(output_json_path, json_output) |
| 276 |
|
332 |
|
|
|
333 |
if perf_webkit_json_path: |
| 334 |
filesystem.write_text_file(perf_webkit_json_path, json.dumps(perf_webkit_output)) |
| 335 |
|
| 277 |
if results_page_path: |
336 |
if results_page_path: |
| 278 |
template_path = filesystem.join(self._port.perf_tests_dir(), 'resources/results-template.html') |
337 |
template_path = filesystem.join(self._port.perf_tests_dir(), 'resources/results-template.html') |
| 279 |
template = filesystem.read_text_file(template_path) |
338 |
template = filesystem.read_text_file(template_path) |
|
Lines 284-305
class PerfTestsRunner(object):
Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py_sec8
|
| 284 |
|
343 |
|
| 285 |
filesystem.write_text_file(results_page_path, results_page) |
344 |
filesystem.write_text_file(results_page_path, results_page) |
| 286 |
|
345 |
|
| 287 |
def _upload_json(self, test_results_server, json_path, file_uploader=FileUploader): |
346 |
def _upload_json(self, test_results_server, json_path, host_path="/api/test/report", file_uploader=FileUploader): |
| 288 |
uploader = file_uploader("https://%s/api/test/report" % test_results_server, 120) |
347 |
url = "https://%s%s" % (test_results_server, host_path) |
|
|
348 |
uploader = file_uploader(url, 120) |
| 289 |
try: |
349 |
try: |
| 290 |
response = uploader.upload_single_text_file(self._host.filesystem, 'application/json', json_path) |
350 |
response = uploader.upload_single_text_file(self._host.filesystem, 'application/json', json_path) |
| 291 |
except Exception, error: |
351 |
except Exception, error: |
| 292 |
_log.error("Failed to upload JSON file in 120s: %s" % error) |
352 |
_log.error("Failed to upload JSON file to %s in 120s: %s" % (url, error)) |
| 293 |
return False |
353 |
return False |
| 294 |
|
354 |
|
| 295 |
response_body = [line.strip('\n') for line in response] |
355 |
response_body = [line.strip('\n') for line in response] |
| 296 |
if response_body != ['OK']: |
356 |
if response_body != ['OK']: |
| 297 |
_log.error("Uploaded JSON but got a bad response:") |
357 |
try: |
| 298 |
for line in response_body: |
358 |
parsed_response = json.loads('\n'.join(response_body)) |
| 299 |
_log.error(line) |
359 |
except: |
| 300 |
return False |
360 |
_log.error("Uploaded JSON to %s but got a bad response:" % url) |
|
|
361 |
for line in response_body: |
| 362 |
_log.error(line) |
| 363 |
return False |
| 364 |
if parsed_response.get('status') != 'OK': |
| 365 |
_log.error("Uploaded JSON to %s but got an error:" % url) |
| 366 |
_log.error(json.dumps(parsed_response, indent=4)) |
| 367 |
return False |
| 301 |
|
368 |
|
| 302 |
_log.info("JSON file uploaded.") |
369 |
_log.info("JSON file uploaded to %s." % url) |
| 303 |
return True |
370 |
return True |
| 304 |
|
371 |
|
| 305 |
def _print_status(self, tests, expected, unexpected): |
372 |
def _print_status(self, tests, expected, unexpected): |