Add possibility of upload check for pc perf tests

Presubmit bot failures are unrelated to the cl.

No-Presubmit: True
Bug: webrtc:12162
Change-Id: I598d3aea8df9429bdff18b80a400c358fa1461d2
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/186123
Commit-Queue: Andrey Logvin <landrey@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32592}
This commit is contained in:
Andrey Logvin
2020-11-11 17:16:26 +00:00
committed by Commit Bot
parent 7dff9f3a76
commit 728b5d01b0
2 changed files with 120 additions and 48 deletions

View File

@ -7,9 +7,11 @@
# in the file PATENTS. All contributing project authors may # in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree. # be found in the AUTHORS file in the root of the source tree.
import datetime
import httplib2 import httplib2
import json import json
import subprocess import subprocess
import time
import zlib import zlib
from tracing.value import histogram from tracing.value import histogram
@ -59,6 +61,52 @@ def _SendHistogramSet(url, histograms, oauth_token):
return response, content return response, content
def _WaitForUploadConfirmation(url, oauth_token, upload_token, wait_timeout,
wait_polling_period):
"""Make a HTTP GET requests to the Performance Dashboard untill upload
status is known or the time is out.
Args:
url: URL of Performance Dashboard instance, e.g.
"https://chromeperf.appspot.com".
oauth_token: An oauth token to use for authorization.
upload_token: String that identifies Performance Dashboard and can be used
for the status check.
wait_timeout: (datetime.timedelta) Maximum time to wait for the
confirmation.
wait_polling_period: (datetime.timedelta) Performance Dashboard will be
polled every wait_polling_period amount of time.
"""
assert wait_polling_period <= wait_timeout
headers = {'Authorization': 'Bearer %s' % oauth_token}
http = httplib2.Http()
response = None
resp_json = None
current_time = datetime.datetime.now()
end_time = current_time + wait_timeout
next_poll_time = current_time + wait_polling_period
while datetime.datetime.now() < end_time:
current_time = datetime.datetime.now()
if next_poll_time > current_time:
time.sleep((next_poll_time - current_time).total_seconds())
next_poll_time = datetime.datetime.now() + wait_polling_period
response, content = http.request(url + '/uploads' + upload_token,
method='GET', headers=headers)
resp_json = json.loads(content)
print 'Upload state polled. Response: %s.' % content
if (response.status != 200 or
resp_json['state'] == 'COMPLETED' or
resp_json['state'] == 'FAILED'):
break
return response, resp_json
# TODO(https://crbug.com/1029452): HACKHACK # TODO(https://crbug.com/1029452): HACKHACK
# Remove once we have doubles in the proto and handle -infinity correctly. # Remove once we have doubles in the proto and handle -infinity correctly.
def _ApplyHacks(dicts): def _ApplyHacks(dicts):
@ -113,13 +161,36 @@ def UploadToDashboard(options):
_DumpOutput(histograms, options.output_json_file) _DumpOutput(histograms, options.output_json_file)
oauth_token = _GenerateOauthToken() oauth_token = _GenerateOauthToken()
response, content = _SendHistogramSet(options.dashboard_url, histograms, response, content = _SendHistogramSet(
oauth_token) options.dashboard_url, histograms, oauth_token)
upload_token = json.loads(content).get('token')
if not options.wait_for_upload or not upload_token:
print 'Not waiting for upload status confirmation.'
if response.status == 200: if response.status == 200:
print 'Received 200 from dashboard.' print 'Received 200 from dashboard.'
return 0 return 0
else: else:
print('Upload failed with %d: %s\n\n%s' % print('Upload failed with %d: %s\n\n%s' % (response.status,
(response.status, response.reason, content)) response.reason, content))
return 1
response, resp_json = _WaitForUploadConfirmation(
options.dashboard_url,
oauth_token,
upload_token,
datetime.timedelta(seconds=options.wait_timeout_sec),
datetime.timedelta(seconds=options.wait_polling_period_sec))
if response.status != 200 or resp_json['state'] == 'FAILED':
print('Upload failed with %d: %s\n\n%s' % (response.status,
response.reason,
str(resp_json)))
return 1
if resp_json['state'] == 'COMPLETED':
print 'Upload completed.'
return 0
print('Upload wasn\'t completed in a given time: %d.', options.wait_timeout)
return 1 return 1

View File

@ -24,54 +24,54 @@ import sys
def _CreateParser(): def _CreateParser():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--perf-dashboard-machine-group', parser.add_argument('--perf-dashboard-machine-group', required=True,
required=True,
help='The "master" the bots are grouped under. This ' help='The "master" the bots are grouped under. This '
'string is the group in the the perf dashboard path ' 'string is the group in the the perf dashboard path '
'group/bot/perf_id/metric/subtest.') 'group/bot/perf_id/metric/subtest.')
parser.add_argument('--bot', parser.add_argument('--bot', required=True,
required=True,
help='The bot running the test (e.g. ' help='The bot running the test (e.g. '
'webrtc-win-large-tests).') 'webrtc-win-large-tests).')
parser.add_argument( parser.add_argument('--test-suite', required=True,
'--test-suite',
required=True,
help='The key for the test in the dashboard (i.e. what ' help='The key for the test in the dashboard (i.e. what '
'you select in the top-level test suite selector in the ' 'you select in the top-level test suite selector in '
'dashboard') 'the dashboard')
parser.add_argument('--webrtc-git-hash', parser.add_argument('--webrtc-git-hash', required=True,
required=True,
help='webrtc.googlesource.com commit hash.') help='webrtc.googlesource.com commit hash.')
parser.add_argument('--commit-position', parser.add_argument('--commit-position', type=int, required=True,
type=int,
required=True,
help='Commit pos corresponding to the git hash.') help='Commit pos corresponding to the git hash.')
parser.add_argument('--build-page-url', parser.add_argument('--build-page-url', required=True,
required=True,
help='URL to the build page for this build.') help='URL to the build page for this build.')
parser.add_argument('--dashboard-url', parser.add_argument('--dashboard-url', required=True,
required=True,
help='Which dashboard to use.') help='Which dashboard to use.')
parser.add_argument('--input-results-file', parser.add_argument('--input-results-file', type=argparse.FileType(),
type=argparse.FileType(),
required=True, required=True,
help='A JSON file with output from WebRTC tests.') help='A JSON file with output from WebRTC tests.')
parser.add_argument('--output-json-file', parser.add_argument('--output-json-file', type=argparse.FileType('w'),
type=argparse.FileType('w'),
help='Where to write the output (for debugging).') help='Where to write the output (for debugging).')
parser.add_argument( parser.add_argument('--outdir', required=True,
'--outdir',
required=True,
help='Path to the local out/ dir (usually out/Default)') help='Path to the local out/ dir (usually out/Default)')
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.')
return parser return parser
def _ConfigurePythonPath(options): def _ConfigurePythonPath(options):
# We just yank the python scripts we require into the PYTHONPATH. You could # 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 # also imagine a solution where we use for instance
# to copy catapult and protobuf code to out/. This is the convention in # protobuf:py_proto_runtime to copy catapult and protobuf code to out/.
# Chromium and WebRTC python scripts. We do need to build histogram_pb2 # This is the convention in Chromium and WebRTC python scripts. We do need
# however, so that's why we add out/ to sys.path below. # to build histogram_pb2 however, so that's why we add out/ to sys.path
# below.
# #
# It would be better if there was an equivalent to py_binary in GN, but # It would be better if there was an equivalent to py_binary in GN, but
# there's not. # there's not.
@ -84,8 +84,9 @@ def _ConfigurePythonPath(options):
sys.path.insert( sys.path.insert(
0, os.path.join(checkout_root, 'third_party', 'protobuf', 'python')) 0, os.path.join(checkout_root, 'third_party', 'protobuf', 'python'))
# The webrtc_dashboard_upload gn rule will build the protobuf stub for python, # The webrtc_dashboard_upload gn rule will build the protobuf stub for
# so put it in the path for this script before we attempt to import it. # 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', histogram_proto_path = os.path.join(options.outdir, 'pyproto', 'tracing',
'tracing', 'proto') 'tracing', 'proto')
sys.path.insert(0, histogram_proto_path) sys.path.insert(0, histogram_proto_path)