mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-14 06:10:40 +01:00

I had to pivot and make tests output protos instead of JSON. I basically move the proto -> JSON conversion into this script instead of doing it in the test binary. This is a temporary state. Later it will be enough to just read up the file and pass it straight to the Catapult implementation, once it learns to de-serialize the proto directly. Bug: chromium:1029452 Change-Id: I7ce992eeeb1a5ae0f20eed54174b08b496e74dfd Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/166920 Commit-Queue: Patrik Höglund <phoglund@webrtc.org> Reviewed-by: Artem Titov <titovartem@webrtc.org> Cr-Commit-Position: refs/heads/master@{#30419}
191 lines
7.4 KiB
Python
191 lines
7.4 KiB
Python
#!/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.
|
|
|
|
"""Adds build info to perf results and uploads them.
|
|
|
|
The tests don't know which bot executed the tests or at what revision, so we
|
|
need to take their output and enrich it with this information. We load the proto
|
|
from the tests, add the build information as shared diagnostics and then
|
|
upload it to the dashboard.
|
|
|
|
This script can't be in recipes, because we can't access the catapult APIs from
|
|
there. It needs to be here source-side.
|
|
"""
|
|
|
|
import argparse
|
|
import httplib2
|
|
import json
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
import zlib
|
|
|
|
# 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/, but this approach is allowed by
|
|
# convention. Fortunately neither catapult nor protobuf require any build rules
|
|
# to be executed. We can't do this for the histogram proto stub though because
|
|
# it's generated; see _LoadHistogramSetFromProto.
|
|
#
|
|
# It would be better if there was an equivalent to py_binary in GN, but there's
|
|
# not.
|
|
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
|
|
CHECKOUT_ROOT = os.path.abspath(os.path.join(SCRIPT_DIR, os.pardir, os.pardir))
|
|
sys.path.insert(0, os.path.join(CHECKOUT_ROOT, 'third_party', 'catapult',
|
|
'tracing'))
|
|
sys.path.insert(0, os.path.join(CHECKOUT_ROOT, 'third_party', 'protobuf',
|
|
'python'))
|
|
|
|
from tracing.value import histogram_set
|
|
from tracing.value.diagnostics import generic_set
|
|
from tracing.value.diagnostics import reserved_infos
|
|
|
|
from google.protobuf import json_format
|
|
|
|
|
|
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 _SendHistogramSet(url, histograms, 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".
|
|
histograms: a histogram set 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(histograms.AsDicts(), indent=4)
|
|
|
|
if url.startswith('http://localhost'):
|
|
# The catapult server turns off compression in developer mode.
|
|
data = serialized
|
|
else:
|
|
data = zlib.compress(serialized)
|
|
|
|
http = httplib2.Http()
|
|
response, content = http.request(url + '/add_histograms', method='POST',
|
|
body=data, headers=headers)
|
|
return response, content
|
|
|
|
|
|
def _LoadHistogramSetFromProto(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')
|
|
sys.path.insert(0, histogram_proto_path)
|
|
|
|
# TODO(https://crbug.com/1029452): Get rid of this import hack once we can
|
|
# just hand the contents of input_results_file straight to the histogram set.
|
|
try:
|
|
import histogram_pb2
|
|
except ImportError:
|
|
raise ImportError('Could not find histogram_pb2. You need to build the '
|
|
'webrtc_dashboard_upload target before invoking this '
|
|
'script. Expected to find '
|
|
'histogram_pb2 in %s.' % histogram_proto_path)
|
|
|
|
with options.input_results_file as f:
|
|
histograms = histogram_pb2.HistogramSet()
|
|
histograms.ParseFromString(f.read())
|
|
|
|
# TODO(https://crbug.com/1029452): Don't convert to JSON as a middle step once
|
|
# there is a proto de-serializer ready in catapult.
|
|
json_data = json.loads(json_format.MessageToJson(histograms))
|
|
hs = histogram_set.HistogramSet()
|
|
hs.ImportDicts(json_data)
|
|
return hs
|
|
|
|
|
|
def _AddBuildInfo(histograms, options):
|
|
common_diagnostics = {
|
|
reserved_infos.MASTERS: options.perf_dashboard_machine_group,
|
|
reserved_infos.BOTS: options.bot,
|
|
reserved_infos.POINT_ID: options.commit_position,
|
|
reserved_infos.BENCHMARKS: options.test_suite,
|
|
reserved_infos.WEBRTC_REVISIONS: str(options.webrtc_git_hash),
|
|
reserved_infos.BUILD_URLS: options.build_page_url,
|
|
}
|
|
|
|
for k, v in common_diagnostics.items():
|
|
histograms.AddSharedDiagnosticToAllHistograms(
|
|
k.name, generic_set.GenericSet([v]))
|
|
|
|
|
|
def _DumpOutput(histograms, output_file):
|
|
with output_file:
|
|
json.dump(histograms.AsDicts(), output_file, indent=4)
|
|
|
|
|
|
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).')
|
|
parser.add_argument('--outdir', required=True,
|
|
help='Path to the local out/ dir (usually out/Default)')
|
|
return parser
|
|
|
|
|
|
def main(args):
|
|
parser = _CreateParser()
|
|
options = parser.parse_args(args)
|
|
|
|
histograms = _LoadHistogramSetFromProto(options)
|
|
_AddBuildInfo(histograms, options)
|
|
|
|
if options.output_json_file:
|
|
_DumpOutput(histograms, options.output_json_file)
|
|
|
|
oauth_token = _GenerateOauthToken()
|
|
response, content = _SendHistogramSet(
|
|
options.dashboard_url, histograms, 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:]))
|