mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
201 lines
6.6 KiB
Python
Executable File
201 lines
6.6 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# Copyright 2014 The Chromium Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
"""A tool that uploads data to the performance dashboard."""
|
|
|
|
import argparse
|
|
import httplib
|
|
import json
|
|
import pprint
|
|
import re
|
|
import sys
|
|
import urllib
|
|
import urllib2
|
|
|
|
# TODO(yzshen): The following are missing currently:
|
|
# (1) CL range on the dashboard;
|
|
# (2) improvement direction on the dashboard;
|
|
# (3) a link from the build step pointing to the dashboard page.
|
|
|
|
|
|
_PERF_LINE_FORMAT = r"""^\s*([^\s/]+) # chart name
|
|
(/([^\s/]+))? # trace name (optional, separated with
|
|
# the chart name by a '/')
|
|
\s+(\S+) # value
|
|
\s+(\S+) # units
|
|
\s*$"""
|
|
|
|
_PRODUCTION_SERVER = "https://chromeperf.appspot.com"
|
|
_TESTING_SERVER = "https://chrome-perf.googleplex.com"
|
|
|
|
|
|
def UploadPerfData(master_name, perf_id, test_name, builder_name, build_number,
|
|
revision, perf_data, point_id, dry_run=False,
|
|
testing_dashboard=True):
|
|
"""Uploads perf data.
|
|
|
|
Args:
|
|
Please see the help for command-line args.
|
|
|
|
Returns:
|
|
A boolean value indicating whether the operation succeeded or not.
|
|
"""
|
|
|
|
def _ConvertToUploadFormat():
|
|
"""Converts perf data to the format that the server understands.
|
|
|
|
Returns:
|
|
A dictionary that (after being converted to JSON) conforms to the server
|
|
format.
|
|
"""
|
|
charts = {}
|
|
line_format = re.compile(_PERF_LINE_FORMAT, re.VERBOSE)
|
|
for line in perf_data:
|
|
match = re.match(line_format, line)
|
|
assert match, "Unable to parse the following input: %s" % line
|
|
|
|
chart_name = match.group(1)
|
|
trace_name = match.group(3) if match.group(3) else "summary"
|
|
|
|
if chart_name not in charts:
|
|
charts[chart_name] = {}
|
|
charts[chart_name][trace_name] = {
|
|
"type": "scalar",
|
|
"value": float(match.group(4)),
|
|
"units": match.group(5)
|
|
}
|
|
|
|
return {
|
|
"master": master_name,
|
|
"bot": perf_id,
|
|
"masterid": master_name,
|
|
"buildername": builder_name,
|
|
"buildnumber": build_number,
|
|
"versions": {
|
|
"mojo": revision
|
|
},
|
|
"point_id": point_id,
|
|
"supplemental": {},
|
|
"chart_data": {
|
|
"format_version": "1.0",
|
|
"benchmark_name": test_name,
|
|
"charts": charts
|
|
}
|
|
}
|
|
|
|
class _UploadException(Exception):
|
|
pass
|
|
|
|
def _Upload(server_url, json_data):
|
|
"""Make an HTTP POST with the given data to the performance dashboard.
|
|
|
|
Args:
|
|
server_url: URL of the performance dashboard instance.
|
|
json_data: JSON string that contains the data to be sent.
|
|
|
|
Raises:
|
|
_UploadException: An error occurred during uploading.
|
|
"""
|
|
# When data is provided to urllib2.Request, a POST is sent instead of GET.
|
|
# The data must be in the application/x-www-form-urlencoded format.
|
|
data = urllib.urlencode({"data": json_data})
|
|
req = urllib2.Request("%s/add_point" % server_url, data)
|
|
try:
|
|
urllib2.urlopen(req)
|
|
except urllib2.HTTPError as e:
|
|
raise _UploadException("HTTPError: %d. Response: %s\n"
|
|
"JSON: %s\n" % (e.code, e.read(), json_data))
|
|
except urllib2.URLError as e:
|
|
raise _UploadException("URLError: %s for JSON %s\n" %
|
|
(str(e.reason), json_data))
|
|
except httplib.HTTPException as e:
|
|
raise _UploadException("HTTPException for JSON %s\n" % json_data)
|
|
|
|
formatted_data = _ConvertToUploadFormat()
|
|
|
|
server_url = _TESTING_SERVER if testing_dashboard else _PRODUCTION_SERVER
|
|
|
|
if dry_run:
|
|
print "Won't upload because --dry-run is specified."
|
|
print "Server: %s" % server_url
|
|
print "Data:"
|
|
pprint.pprint(formatted_data)
|
|
else:
|
|
print "Uploading data to %s ..." % server_url
|
|
try:
|
|
_Upload(server_url, json.dumps(formatted_data))
|
|
except _UploadException as e:
|
|
print e
|
|
return False
|
|
|
|
print "Done."
|
|
|
|
dashboard_params = urllib.urlencode({
|
|
"masters": master_name,
|
|
"bots": perf_id,
|
|
"tests": test_name,
|
|
"rev": point_id
|
|
})
|
|
print "Results Dashboard: %s/report?%s" % (server_url, dashboard_params)
|
|
|
|
return True
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="A tool that uploads data to the performance dashboard.")
|
|
|
|
parser.add_argument(
|
|
"--master-name", required=True,
|
|
help="Buildbot master name, used to construct link to buildbot log by "
|
|
"the dashboard, and also as the top-level category for the data.")
|
|
parser.add_argument(
|
|
"--perf-id", required=True,
|
|
help="Used as the second-level category for the data, usually the "
|
|
"platform type.")
|
|
parser.add_argument(
|
|
"--test-name", required=True,
|
|
help="Name of the test that the perf data was generated from.")
|
|
parser.add_argument(
|
|
"--builder-name", required=True,
|
|
help="Buildbot builder name, used to construct link to buildbot log by "
|
|
"the dashboard.")
|
|
parser.add_argument(
|
|
"--build-number", required=True, type=int,
|
|
help="Build number, used to construct link to buildbot log by the "
|
|
"dashboard.")
|
|
parser.add_argument(
|
|
"--revision", required=True, help="The mojo git commit hash.")
|
|
parser.add_argument(
|
|
"--perf-data", required=True, metavar="foo_perf.log",
|
|
type=argparse.FileType("r"),
|
|
help="A text file containing the perf data. Each line is a data point in "
|
|
"the following format: chart_name[/trace_name] value units")
|
|
parser.add_argument(
|
|
"--point-id", required=True, type=int,
|
|
help="The x coordinate for the data points.")
|
|
parser.add_argument(
|
|
"--dry-run", action="store_true",
|
|
help="Display the server URL and the data to upload, but not actually "
|
|
"upload the data.")
|
|
server_group = parser.add_mutually_exclusive_group()
|
|
server_group.add_argument(
|
|
"--testing-dashboard", action="store_true", default=True,
|
|
help="Upload the data to the testing dashboard (default).")
|
|
server_group.add_argument(
|
|
"--production-dashboard", dest="testing_dashboard", action="store_false",
|
|
default=False, help="Upload the data to the production dashboard.")
|
|
args = parser.parse_args()
|
|
|
|
result = UploadPerfData(args.master_name, args.perf_id, args.test_name,
|
|
args.builder_name, args.build_number, args.revision,
|
|
args.perf_data, args.point_id, args.dry_run,
|
|
args.testing_dashboard)
|
|
return 0 if result else 1
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|