diff --git a/tools_webrtc/perf/catapult_uploader.py b/tools_webrtc/perf/catapult_uploader.py index da376868b9..aae35ec656 100644 --- a/tools_webrtc/perf/catapult_uploader.py +++ b/tools_webrtc/perf/catapult_uploader.py @@ -14,6 +14,7 @@ import subprocess import time import zlib +import dataclasses import httplib2 from tracing.value import histogram @@ -22,6 +23,41 @@ from tracing.value.diagnostics import generic_set from tracing.value.diagnostics import reserved_infos +@dataclasses.dataclass +class UploaderOptions(): + """Required information to upload perf metrics. + + Attributes: + perf_dashboard_machine_group: The "master" the bots are grouped under. + This string is the group in the the perf dashboard path + group/bot/perf_id/metric/subtest. + bot: The bot running the test (e.g. webrtc-win-large-tests). + test_suite: The key for the test in the dashboard (i.e. what you select + in the top-level test suite selector in the dashboard + webrtc_git_hash: webrtc.googlesource.com commit hash. + commit_position: Commit pos corresponding to the git hash. + build_page_url: URL to the build page for this build. + dashboard_url: Which dashboard to use. + input_results_file: A HistogramSet proto file coming from WebRTC tests. + output_json_file: Where to write the output (for debugging). + wait_timeout_sec: Maximum amount of time in seconds that the script will + wait for the confirmation. + wait_polling_period_sec: Status will be requested from the Dashboard + every wait_polling_period_sec seconds. + """ + perf_dashboard_machine_group: str + bot: str + test_suite: str + webrtc_git_hash: str + commit_position: int + build_page_url: str + dashboard_url: str + input_results_file: str + output_json_file: str + wait_timeout_sec: datetime.timedelta = datetime.timedelta(seconds=1200) + wait_polling_period_sec: datetime.timedelta = datetime.timedelta(seconds=120) + + def _GenerateOauthToken(): args = ['luci-auth', 'token'] p = subprocess.Popen(args, @@ -195,7 +231,7 @@ def _ApplyHacks(dicts): def _LoadHistogramSetFromProto(options): hs = histogram_set.HistogramSet() - with options.input_results_file as f: + with open(options.input_results_file, 'rb') as f: hs.ImportProto(f.read()) return hs @@ -217,11 +253,11 @@ def _AddBuildInfo(histograms, options): def _DumpOutput(histograms, output_file): - with output_file: - json.dump(_ApplyHacks(histograms.AsDicts()), output_file, indent=4) + with open(output_file, 'wb') as f: + json.dump(_ApplyHacks(histograms.AsDicts()), f, indent=4) -def UploadToDashboard(options): +def UploadToDashboardImpl(options): histograms = _LoadHistogramSetFromProto(options) _AddBuildInfo(histograms, options) @@ -236,15 +272,14 @@ def UploadToDashboard(options): return 1 upload_token = json.loads(content).get('token') - if not options.wait_for_upload or not upload_token: + if not upload_token: print(('Received 200 from dashboard. ', 'Not waiting for the upload status confirmation.')) return 0 response, resp_json = _WaitForUploadConfirmation( - options.dashboard_url, upload_token, - datetime.timedelta(seconds=options.wait_timeout_sec), - datetime.timedelta(seconds=options.wait_polling_period_sec)) + options.dashboard_url, upload_token, options.wait_timeout_sec, + options.wait_polling_period_sec) if ((resp_json and resp_json['state'] == 'COMPLETED') or _CheckFullUploadInfo(options.dashboard_url, upload_token)): @@ -260,6 +295,15 @@ def UploadToDashboard(options): print('Upload failed.') return 1 - print(('Upload wasn\'t completed in a given time: %d seconds.' % + print(('Upload wasn\'t completed in a given time: %s seconds.' % options.wait_timeout_sec)) return 1 + + +def UploadToDashboard(options): + try: + exit_code = UploadToDashboardImpl(options) + except RuntimeError as e: + print(e) + return 2 + return exit_code diff --git a/tools_webrtc/perf/webrtc_dashboard_upload.py b/tools_webrtc/perf/webrtc_dashboard_upload.py index 995d201ca8..0b58e58f78 100644 --- a/tools_webrtc/perf/webrtc_dashboard_upload.py +++ b/tools_webrtc/perf/webrtc_dashboard_upload.py @@ -32,9 +32,9 @@ def _CreateParser(): parser = argparse.ArgumentParser() parser.add_argument('--perf-dashboard-machine-group', required=True, - help='The "master" the bots are grouped under. This ' - 'string is the group in the the perf dashboard path ' - 'group/bot/perf_id/metric/subtest.') + help='The "machine_group" the bots are grouped under.' + 'This string is the group in the the perf dashboard ' + 'path group/bot/perf_id/metric/subtest.') parser.add_argument('--bot', required=True, help='The bot running the test (e.g. ' @@ -68,27 +68,14 @@ def _CreateParser(): parser.add_argument('--outdir', required=True, help='Path to the local out/ dir (usually out/Default)') + # TODO(crbug.com/webrtc/13806): Remove this argument. parser.add_argument('--wait-for-upload', action='store_true', - help='If specified, script will wait untill Chrome ' - 'perf dashboard confirms that the data was succesfully ' - 'proccessed and uploaded') - parser.add_argument('--wait-timeout-sec', - type=int, - default=1200, - help='Used only if wait-for-upload is True. Maximum ' - 'amount of time in seconds that the script will wait ' - 'for the confirmation.') - parser.add_argument('--wait-polling-period-sec', - type=int, - default=120, - help='Used only if wait-for-upload is True. Status ' - 'will be requested from the Dashboard every ' - 'wait-polling-period-sec seconds.') + help='DEPRECATED: this option will soon be removed') return parser -def _ConfigurePythonPath(options): +def _ConfigurePythonPath(outdir): # We just yank the python scripts we require into the PYTHONPATH. You could # also imagine a solution where we use for instance # protobuf:py_proto_runtime to copy catapult and protobuf code to out/. @@ -110,8 +97,8 @@ def _ConfigurePythonPath(options): # The webrtc_dashboard_upload gn rule will build the protobuf stub for # python, so put it in the path for this script before we attempt to import # it. - histogram_proto_path = os.path.join(options.outdir, 'pyproto', 'tracing', - 'tracing', 'proto') + histogram_proto_path = os.path.join(outdir, 'pyproto', 'tracing', 'tracing', + 'proto') sys.path.insert(0, histogram_proto_path) # Fail early in case the proto hasn't been built. @@ -127,11 +114,23 @@ def main(args): parser = _CreateParser() options = parser.parse_args(args) - _ConfigurePythonPath(options) + _ConfigurePythonPath(options.outdir) import catapult_uploader - return catapult_uploader.UploadToDashboard(options) + uploader_options = catapult_uploader.UploaderOptions( + perf_dashboard_machine_group=options.perf_dashboard_machine_group, + bot=options.bot, + test_suite=options.test_suite, + webrtc_git_hash=options.webrtc_git_hash, + commit_position=options.commit_position, + build_page_url=options.build_page_url, + dashboard_url=options.dashboard_url, + input_results_file=options.input_results_file, + output_json_file=options.output_json_file, + ) + + return catapult_uploader.UploadToDashboard(uploader_options) if __name__ == '__main__':