Add a new script to upload perf tests.

Also add a script to do the bridge between a python 2 and a python 3 interpreter.
This should be removed when the merge scripts will be using python 3 (https://crbug.com/webrtc/13835).

Note that webrtc_dashboard_upload.py will be removed when the new script is stabilized.

Bug: webrtc:13806
Change-Id: I806fa11f417ef37674bdaeb5126c71570e3697d7
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/255560
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Christoffer Jansson <jansson@google.com>
Reviewed-by: Artem Titov <titovartem@webrtc.org>
Reviewed-by: Christoffer Jansson <jansson@webrtc.org>
Commit-Queue: Jeremy Leconte <jleconte@google.com>
Cr-Commit-Position: refs/heads/main@{#36252}
This commit is contained in:
Jeremy Leconte
2022-03-18 10:21:07 +01:00
committed by WebRTC LUCI CQ
parent e9a6ada2e3
commit 4fc9bd9f69
5 changed files with 224 additions and 4 deletions

View File

@ -820,9 +820,10 @@ def RunPythonTests(input_api, output_api):
return input_api.os_path.join(input_api.PresubmitLocalPath(), *args)
excluded_files = [
# This test should be run manually after webrtc_dashboard_upload target
# These tests should be run manually after webrtc_dashboard_upload target
# has been built.
'catapult_uploader_test.py'
'catapult_uploader_test.py',
'process_perf_results_test.py',
]
test_directories = [

View File

@ -14,6 +14,7 @@ import subprocess
import time
import zlib
from typing import Optional
import dataclasses
import httplib2
@ -53,7 +54,7 @@ class UploaderOptions():
build_page_url: str
dashboard_url: str
input_results_file: str
output_json_file: str
output_json_file: Optional[str] = None
wait_timeout_sec: datetime.timedelta = datetime.timedelta(seconds=1200)
wait_polling_period_sec: datetime.timedelta = datetime.timedelta(seconds=120)
@ -305,5 +306,5 @@ def UploadToDashboard(options):
exit_code = UploadToDashboardImpl(options)
except RuntimeError as e:
print(e)
return 2
return 1
return exit_code

View File

@ -0,0 +1,123 @@
#!/usr/bin/env vpython3
# Copyright (c) 2022 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 json
import os
import sys
from pathlib import Path
# Even if protobuf is not used directly, this allows transitive imports
# of the protobuf library to use the vpython wheel specified in the root
# level .vpython (see bugs.webrtc.org/12211 for context).
import google.protobuf # pylint: disable=unused-import
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/.
# This is the convention in Chromium and WebRTC python scripts. We do need
# 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
# 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'))
# 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(outdir, 'pyproto', 'tracing', 'tracing',
'proto')
sys.path.insert(0, histogram_proto_path)
# Fail early in case the proto hasn't been built.
from tracing.proto import histogram_proto
if not histogram_proto.HAS_PROTO:
print('Could not find histogram_pb2. You need to build the '
'webrtc_dashboard_upload target before invoking this '
'script. Expected to find '
'histogram_pb2.py in %s.' % histogram_proto_path)
return 1
return 0
def _UploadToDasboard(args):
build_properties = json.loads(args.build_properties)
exit_code = _ConfigurePythonPath(build_properties['outdir'])
if exit_code != 0:
return exit_code
import catapult_uploader
perftest_outputs = [
f.absolute() for f in Path(args.task_output_dir).rglob('perftest-output*')
if f.is_file()
]
for perftest_output in perftest_outputs:
uploader_options = catapult_uploader.UploaderOptions(
perf_dashboard_machine_group=(
build_properties['perf_dashboard_machine_group']),
bot=build_properties['bot'],
webrtc_git_hash=build_properties['webrtc_git_hash'],
commit_position=build_properties['commit_position'],
build_page_url=build_properties['build_page_url'],
dashboard_url=build_properties['dashboard_url'],
test_suite=args.test_suite,
input_results_file=perftest_output,
)
exit_code = catapult_uploader.UploadToDashboard(uploader_options)
if exit_code != 0:
return exit_code
return 0
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--build-properties', help=argparse.SUPPRESS)
parser.add_argument('--summary-json', help=argparse.SUPPRESS)
parser.add_argument('--task-output-dir', help=argparse.SUPPRESS)
parser.add_argument('--test-suite', help=argparse.SUPPRESS)
parser.add_argument('-o', '--output-json', help=argparse.SUPPRESS)
parser.add_argument('json_files', nargs='*', help=argparse.SUPPRESS)
args = parser.parse_args()
exit_code = _UploadToDasboard(args)
if exit_code != 0:
with open(args.output_json, 'w') as f:
json.dump({
"global_tags": ["UNRELIABLE_RESULTS"],
"missing_shards": [0]
}, f)
return exit_code
return 0
if __name__ == '__main__':
sys.exit(main())

View File

@ -0,0 +1,25 @@
#!/usr/bin/env vpython3
# Copyright (c) 2022 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.
"""Calls process_perf_results.py with a python 3 interpreter."""
import sys
import subprocess
# TODO(crbug.com/webrtc/13835): Delete this file and use
# process_perf_results.py instead.
def main():
cmd = sys.argv[0].replace('_py2', '')
print('Calling "%s" with py3 in case this script was called with py2.' % cmd)
return subprocess.call(['vpython3', cmd] + sys.argv[1:])
if __name__ == '__main__':
sys.exit(main())

View File

@ -0,0 +1,70 @@
#!/usr/bin/env vpython3
# Copyright (c) 2022 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.
import os
import sys
import unittest
from unittest import mock
_SCRIPT_DIR = os.path.dirname(__file__)
_SRC_DIR = os.path.normpath(os.path.join(_SCRIPT_DIR, '..', '..'))
sys.path.insert(0, os.path.join(_SRC_DIR, 'third_party', 'protobuf', 'python'))
import process_perf_results
class ProcessPerfResultsTest(unittest.TestCase):
def testConfigurePythonPath(self):
# pylint: disable=protected-access
self.assertEqual(
0,
process_perf_results._ConfigurePythonPath(
os.path.join(_SRC_DIR, 'out/Default')))
def testUploadToDasboard(self):
outdir = os.path.join(_SRC_DIR, 'out/Default')
args = mock.Mock(
build_properties='{' + '"outdir":"' + outdir + '", ' +
'"perf_dashboard_machine_group":"mock_machine_group", ' +
'"bot":"mock_bot", ' + '"webrtc_git_hash":"mock_webrtc_git_hash", ' +
'"commit_position":"123456", ' +
'"build_page_url":"mock_build_page_url", ' +
'"dashboard_url":"mock_dashboard_url"' + '}',
summary_json='mock_sumary_json',
task_output_dir='mock_task_output_dir',
test_suite='mock_test_suite',
)
perftest_output = mock.Mock(
absolute=lambda: 'dummy_path/perftest-output.pb',
is_file=lambda: True,
)
with mock.patch('pathlib.Path.rglob') as mocked_rglob:
with mock.patch('catapult_uploader.UploadToDashboard') as mocked_upload:
mocked_rglob.return_value = [perftest_output]
mocked_upload.return_value = 0
# pylint: disable=protected-access
self.assertEqual(0, process_perf_results._UploadToDasboard(args))
import catapult_uploader
mocked_upload.assert_called_once_with(
catapult_uploader.UploaderOptions(
perf_dashboard_machine_group='mock_machine_group',
bot='mock_bot',
test_suite='mock_test_suite',
webrtc_git_hash='mock_webrtc_git_hash',
commit_position='123456',
build_page_url='mock_build_page_url',
dashboard_url='mock_dashboard_url',
input_results_file=perftest_output.absolute()))
if (__name__) == '__main__':
unittest.main()