#!/usr/bin/env python # Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. """Converts and uploads results to the Chrome perf dashboard. This conversion step is needed because test/testsupport/perf_test.cc can't output histograms natively. There is, unfortunately, no C++ API for histograms. This script is in python so it can depend on Catapult's python API instead. See histogram_util.py for how this is done. We should move to the C++ API and delete the scripts in this dir as soon as there is a C++ API (less conversions = easier to understand). This script can't be in recipes, because we can't access the catapult APIs from there. It needs to be here source-side. This script is adapted from the downstream variant like this: * Follows upstream naming conventions. * Downstream-only parameters and concepts go away. * oAuth tokens are generated by luci-auth. """ import argparse import httplib2 import json import sys import subprocess import zlib import histogram_util def _GenerateOauthToken(): args = ['luci-auth', 'token'] p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) if p.wait() == 0: output = p.stdout.read() return output.strip() else: raise RuntimeError( 'Error generating authentication token.\nStdout: %s\nStderr:%s' % (p.stdout.read(), p.stderr.read())) def _SendHistogramSetJson(url, histogram_json, oauth_token): """Make a HTTP POST with the given JSON to the Performance Dashboard. Args: url: URL of Performance Dashboard instance, e.g. "https://chromeperf.appspot.com". histogram_json: a JSON object that contains the data to be sent. oauth_token: An oauth token to use for authorization. """ headers = {'Authorization': 'Bearer %s' % oauth_token} serialized = json.dumps(histogram_json.AsDicts(), indent=4) data = zlib.compress(serialized) http = httplib2.Http() response, content = http.request(url + '/add_histograms', method='POST', body=data, headers=headers) return response, content def _LoadHistogramSetJson(options): with options.input_results_file as f: json_data = json.load(f) histograms = histogram_util.LoadHistograms(json_data) hs = histogram_util.MakeWebRtcHistogramSet( stats=histograms, commit_pos=options.commit_position, commit_hash=options.webrtc_git_hash, master=options.perf_dashboard_machine_group, bot=options.bot, test_suite=options.test_suite, build_url=options.build_page_url) return hs 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.') parser.add_argument('--bot', required=True, help='The bot running the test (e.g. ' 'webrtc-win-large-tests).') parser.add_argument('--test-suite', required=True, help='The key for the test in the dashboard (i.e. what ' 'you select in the top-level test suite selector in the ' 'dashboard') parser.add_argument('--webrtc-git-hash', required=True, help='webrtc.googlesource.com commit hash.') parser.add_argument('--commit-position', type=int, required=True, help='Commit pos corresponding to the git hash.') parser.add_argument('--build-page-url', required=True, help='URL to the build page for this build.') parser.add_argument('--dashboard-url', required=True, help='Which dashboard to use.') parser.add_argument('--input-results-file', type=argparse.FileType(), required=True, help='A JSON file with output from WebRTC tests.') parser.add_argument('--output-json-file', type=argparse.FileType('w'), help='Where to write the output (for debugging).') return parser def main(args): parser = _CreateParser() options = parser.parse_args(args) histogram_json = _LoadHistogramSetJson(options) if options.output_json_file: with options.output_json_file as output_file: json.dump(histogram_json.AsDicts(), output_file, indent=4) oauth_token = _GenerateOauthToken() response, content = _SendHistogramSetJson( options.dashboard_url, histogram_json, oauth_token) if response.status == 200: return 0 else: print("Upload failed with %d: %s\n\n%s" % (response.status, response.reason, content)) return 1 if __name__ == '__main__': sys.exit(main(sys.argv[1:]))