blob: 2eb1d97f74de92f53ee52f1890a1acac73ac5c07 [file] [log] [blame]
Patrik Höglundcb0b8742019-11-18 13:46:38 +01001#!/usr/bin/env python
2# Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
3#
4# Use of this source code is governed by a BSD-style license
5# that can be found in the LICENSE file in the root of the source
6# tree. An additional intellectual property rights grant can be found
7# in the file PATENTS. All contributing project authors may
8# be found in the AUTHORS file in the root of the source tree.
9
Patrik Höglundabea2682020-01-17 13:36:29 +010010"""Adds build info to perf results and uploads them.
Patrik Höglundcb0b8742019-11-18 13:46:38 +010011
Patrik Höglundabea2682020-01-17 13:36:29 +010012The tests don't know which bot executed the tests or at what revision, so we
13need to take their output and enrich it with this information. We load the JSON
14from the tests, add the build information as shared diagnostics and then
15upload it to the dashboard.
Patrik Höglundcb0b8742019-11-18 13:46:38 +010016
17This script can't be in recipes, because we can't access the catapult APIs from
18there. It needs to be here source-side.
Patrik Höglundcb0b8742019-11-18 13:46:38 +010019"""
20
21import argparse
22import httplib2
23import json
Patrik Höglundabea2682020-01-17 13:36:29 +010024import os
Patrik Höglundcb0b8742019-11-18 13:46:38 +010025import sys
26import subprocess
27import zlib
28
Patrik Höglundabea2682020-01-17 13:36:29 +010029SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
30CHECKOUT_ROOT = os.path.abspath(os.path.join(SCRIPT_DIR, os.pardir, os.pardir))
31sys.path.insert(0, os.path.join(CHECKOUT_ROOT, 'third_party', 'catapult',
32 'tracing'))
33
34from tracing.value import histogram_set
35from tracing.value.diagnostics import generic_set
36from tracing.value.diagnostics import reserved_infos
Patrik Höglundcb0b8742019-11-18 13:46:38 +010037
38
39def _GenerateOauthToken():
40 args = ['luci-auth', 'token']
41 p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
42 if p.wait() == 0:
43 output = p.stdout.read()
44 return output.strip()
45 else:
46 raise RuntimeError(
47 'Error generating authentication token.\nStdout: %s\nStderr:%s' %
48 (p.stdout.read(), p.stderr.read()))
49
50
Patrik Höglundabea2682020-01-17 13:36:29 +010051def _SendHistogramSet(url, histograms, oauth_token):
Patrik Höglundcb0b8742019-11-18 13:46:38 +010052 """Make a HTTP POST with the given JSON to the Performance Dashboard.
53
54 Args:
55 url: URL of Performance Dashboard instance, e.g.
56 "https://chromeperf.appspot.com".
Patrik Höglundabea2682020-01-17 13:36:29 +010057 histograms: a histogram set object that contains the data to be sent.
Patrik Höglundcb0b8742019-11-18 13:46:38 +010058 oauth_token: An oauth token to use for authorization.
59 """
60 headers = {'Authorization': 'Bearer %s' % oauth_token}
Patrik Höglundabea2682020-01-17 13:36:29 +010061 serialized = json.dumps(histograms.AsDicts(), indent=4)
62
63 if url.startswith('http://localhost'):
64 # The catapult server turns off compression in developer mode.
65 data = serialized
66 else:
67 data = zlib.compress(serialized)
Patrik Höglundcb0b8742019-11-18 13:46:38 +010068
69 http = httplib2.Http()
70 response, content = http.request(url + '/add_histograms', method='POST',
71 body=data, headers=headers)
72 return response, content
73
74
Patrik Höglundabea2682020-01-17 13:36:29 +010075def _LoadHistogramSetFromJson(options):
Patrik Höglundcb0b8742019-11-18 13:46:38 +010076 with options.input_results_file as f:
77 json_data = json.load(f)
78
Patrik Höglundabea2682020-01-17 13:36:29 +010079 histograms = histogram_set.HistogramSet()
80 histograms.ImportDicts(json_data)
81 return histograms
Patrik Höglundcb0b8742019-11-18 13:46:38 +010082
Patrik Höglundabea2682020-01-17 13:36:29 +010083
84def _AddBuildInfo(histograms, options):
85 common_diagnostics = {
86 reserved_infos.MASTERS: options.perf_dashboard_machine_group,
87 reserved_infos.BOTS: options.bot,
88 reserved_infos.POINT_ID: options.commit_position,
89 reserved_infos.BENCHMARKS: options.test_suite,
90 reserved_infos.WEBRTC_REVISIONS: str(options.webrtc_git_hash),
91 reserved_infos.BUILD_URLS: options.build_page_url,
92 }
93
94 for k, v in common_diagnostics.items():
95 histograms.AddSharedDiagnosticToAllHistograms(
96 k.name, generic_set.GenericSet([v]))
97
98
99def _DumpOutput(histograms, output_file):
100 with output_file:
101 json.dump(histograms.AsDicts(), output_file, indent=4)
Patrik Höglundcb0b8742019-11-18 13:46:38 +0100102
103
104def _CreateParser():
105 parser = argparse.ArgumentParser()
106 parser.add_argument('--perf-dashboard-machine-group', required=True,
107 help='The "master" the bots are grouped under. This '
108 'string is the group in the the perf dashboard path '
109 'group/bot/perf_id/metric/subtest.')
110 parser.add_argument('--bot', required=True,
111 help='The bot running the test (e.g. '
112 'webrtc-win-large-tests).')
113 parser.add_argument('--test-suite', required=True,
114 help='The key for the test in the dashboard (i.e. what '
115 'you select in the top-level test suite selector in the '
116 'dashboard')
117 parser.add_argument('--webrtc-git-hash', required=True,
118 help='webrtc.googlesource.com commit hash.')
119 parser.add_argument('--commit-position', type=int, required=True,
120 help='Commit pos corresponding to the git hash.')
121 parser.add_argument('--build-page-url', required=True,
122 help='URL to the build page for this build.')
123 parser.add_argument('--dashboard-url', required=True,
124 help='Which dashboard to use.')
125 parser.add_argument('--input-results-file', type=argparse.FileType(),
126 required=True,
127 help='A JSON file with output from WebRTC tests.')
128 parser.add_argument('--output-json-file', type=argparse.FileType('w'),
129 help='Where to write the output (for debugging).')
130 return parser
131
132
133def main(args):
134 parser = _CreateParser()
135 options = parser.parse_args(args)
136
Patrik Höglundabea2682020-01-17 13:36:29 +0100137 histograms = _LoadHistogramSetFromJson(options)
138 _AddBuildInfo(histograms, options)
Patrik Höglundcb0b8742019-11-18 13:46:38 +0100139
140 if options.output_json_file:
Patrik Höglundabea2682020-01-17 13:36:29 +0100141 _DumpOutput(histograms, options.output_json_file)
Patrik Höglundcb0b8742019-11-18 13:46:38 +0100142
143 oauth_token = _GenerateOauthToken()
Patrik Höglundabea2682020-01-17 13:36:29 +0100144 response, content = _SendHistogramSet(
145 options.dashboard_url, histograms, oauth_token)
Patrik Höglundcb0b8742019-11-18 13:46:38 +0100146
147 if response.status == 200:
148 return 0
149 else:
150 print("Upload failed with %d: %s\n\n%s" % (response.status, response.reason,
151 content))
152 return 1
153
154
155if __name__ == '__main__':
156 sys.exit(main(sys.argv[1:]))