blob: ef327896c9e71aa46554e96197281485cd3238b1 [file] [log] [blame]
Simran Basi833814b2013-01-29 13:13:43 -08001# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +08005import json
Simran Basi833814b2013-01-29 13:13:43 -08006import logging
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +08007import numbers
8import numpy
Simran Basi833814b2013-01-29 13:13:43 -08009import os
Chinglin Yu0adaf112020-01-20 14:48:20 +080010import tempfile
Simran Basi833814b2013-01-29 13:13:43 -080011import StringIO
12
Simran Basi833814b2013-01-29 13:13:43 -080013from autotest_lib.client.common_lib import error, utils
14from autotest_lib.client.common_lib.cros import dev_server
15
16
Dave Tu6a404e62013-11-05 15:54:48 -080017TELEMETRY_RUN_BENCHMARKS_SCRIPT = 'tools/perf/run_benchmark'
Ilja H. Friedel086bc3f2014-02-27 22:17:55 -080018TELEMETRY_RUN_TESTS_SCRIPT = 'tools/telemetry/run_tests'
Gurchetan Singhfaf75e92017-04-17 18:09:44 -070019TELEMETRY_RUN_GPU_TESTS_SCRIPT = 'content/test/gpu/run_gpu_integration_test.py'
Mao Huangc9642d72017-09-28 16:50:02 +080020TELEMETRY_TIMEOUT_MINS = 150
Simran Basi833814b2013-01-29 13:13:43 -080021
Ting-Yuan Huange5b19132016-03-22 13:02:41 +080022DUT_CHROME_ROOT = '/usr/local/telemetry/src'
23
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +080024CHART_JSON_RESULT = 'results-chart.json'
25HISTOGRAM_SET_RESULT = 'histograms.json'
26
Simran Basi833814b2013-01-29 13:13:43 -080027# Result Statuses
28SUCCESS_STATUS = 'SUCCESS'
29WARNING_STATUS = 'WARNING'
30FAILED_STATUS = 'FAILED'
31
Kuo-Hsin Yang07da7b62018-08-08 16:56:06 +080032# A list of telemetry tests that cannot run on dut.
Kuo-Hsin Yange0915472018-09-10 10:36:16 +080033ON_DUT_BLACKLIST = [
Kuo-Hsin Yang120c2042019-06-21 17:09:32 +080034 'cros_ui_smoothness', # crbug/976839
Kuo-Hsin Yange0915472018-09-10 10:36:16 +080035 'loading.desktop', # crbug/882299
36 'rendering.desktop', # crbug/882291
37 'system_health.memory_desktop', # crbug/874386
38]
Simran Basi833814b2013-01-29 13:13:43 -080039
40class TelemetryResult(object):
41 """Class to represent the results of a telemetry run.
42
43 This class represents the results of a telemetry run, whether it ran
44 successful, failed or had warnings.
45 """
46
47
48 def __init__(self, exit_code=0, stdout='', stderr=''):
49 """Initializes this TelemetryResultObject instance.
50
51 @param status: Status of the telemtry run.
52 @param stdout: Stdout of the telemetry run.
53 @param stderr: Stderr of the telemetry run.
54 """
55 if exit_code == 0:
56 self.status = SUCCESS_STATUS
57 else:
58 self.status = FAILED_STATUS
59
Simran Basi833814b2013-01-29 13:13:43 -080060 self._stdout = stdout
61 self._stderr = stderr
62 self.output = '\n'.join([stdout, stderr])
63
64
Simran Basi833814b2013-01-29 13:13:43 -080065class TelemetryRunner(object):
66 """Class responsible for telemetry for a given build.
67
68 This class will extract and install telemetry on the devserver and is
69 responsible for executing the telemetry benchmarks and returning their
70 output to the caller.
71 """
72
Kuo-Hsin Yang66324262019-12-10 10:36:34 +080073 def __init__(self, host, local=False, telemetry_on_dut=True):
Simran Basi833814b2013-01-29 13:13:43 -080074 """Initializes this telemetry runner instance.
75
76 If telemetry is not installed for this build, it will be.
Luis Lozano23ae3192013-11-08 16:22:46 -080077
Ting-Yuan Huange5b19132016-03-22 13:02:41 +080078 Basically, the following commands on the local pc on which test_that
79 will be executed, depending on the 4 possible combinations of
80 local x telemetry_on_dut:
81
82 local=True, telemetry_on_dut=False:
Kuo-Hsin Yang66324262019-12-10 10:36:34 +080083 python2 run_benchmark --browser=cros-chrome --remote=[dut] [test]
Ting-Yuan Huange5b19132016-03-22 13:02:41 +080084
85 local=True, telemetry_on_dut=True:
Kuo-Hsin Yang66324262019-12-10 10:36:34 +080086 ssh [dut] python2 run_benchmark --browser=system [test]
Ting-Yuan Huange5b19132016-03-22 13:02:41 +080087
88 local=False, telemetry_on_dut=False:
Kuo-Hsin Yang66324262019-12-10 10:36:34 +080089 ssh [devserver] python2 run_benchmark --browser=cros-chrome
90 --remote=[dut] [test]
Ting-Yuan Huange5b19132016-03-22 13:02:41 +080091
92 local=False, telemetry_on_dut=True:
Kuo-Hsin Yang66324262019-12-10 10:36:34 +080093 ssh [devserver] ssh [dut] python2 run_benchmark --browser=system [test]
Ting-Yuan Huange5b19132016-03-22 13:02:41 +080094
Luis Lozano23ae3192013-11-08 16:22:46 -080095 @param host: Host where the test will be run.
96 @param local: If set, no devserver will be used, test will be run
97 locally.
Ting-Yuan Huange5b19132016-03-22 13:02:41 +080098 If not set, "ssh [devserver] " will be appended to test
99 commands.
100 @param telemetry_on_dut: If set, telemetry itself (the test harness)
101 will run on dut.
102 It decides browser=[system|cros-chrome]
Simran Basi833814b2013-01-29 13:13:43 -0800103 """
104 self._host = host
Ilja H. Friedelc7bf3102014-05-13 17:31:25 -0700105 self._devserver = None
106 self._telemetry_path = None
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800107 self._telemetry_on_dut = telemetry_on_dut
Luis Lozano23ae3192013-11-08 16:22:46 -0800108 # TODO (llozano crbug.com/324964). Remove conditional code.
109 # Use a class hierarchy instead.
110 if local:
111 self._setup_local_telemetry()
112 else:
113 self._setup_devserver_telemetry()
Chinglin Yu0adaf112020-01-20 14:48:20 +0800114 self._benchmark_deps = None
Luis Lozano23ae3192013-11-08 16:22:46 -0800115
116 logging.debug('Telemetry Path: %s', self._telemetry_path)
117
118
119 def _setup_devserver_telemetry(self):
120 """Setup Telemetry to use the devserver."""
121 logging.debug('Setting up telemetry for devserver testing')
Simran Basi833814b2013-01-29 13:13:43 -0800122 logging.debug('Grabbing build from AFE.')
Prathmesh Prabhucfff58a2017-02-06 10:07:43 -0800123 info = self._host.host_info_store.get()
124 if not info.build:
Simran Basi833814b2013-01-29 13:13:43 -0800125 logging.error('Unable to locate build label for host: %s.',
Dean Liaoe3e75f62017-11-14 10:36:43 +0800126 self._host.host_port)
Simran Basi833814b2013-01-29 13:13:43 -0800127 raise error.AutotestError('Failed to grab build for host %s.' %
Dean Liaoe3e75f62017-11-14 10:36:43 +0800128 self._host.host_port)
Simran Basi833814b2013-01-29 13:13:43 -0800129
Prathmesh Prabhucfff58a2017-02-06 10:07:43 -0800130 logging.debug('Setting up telemetry for build: %s', info.build)
Simran Basi833814b2013-01-29 13:13:43 -0800131
Prathmesh Prabhucfff58a2017-02-06 10:07:43 -0800132 self._devserver = dev_server.ImageServer.resolve(
133 info.build, hostname=self._host.hostname)
134 self._devserver.stage_artifacts(info.build, ['autotest_packages'])
135 self._telemetry_path = self._devserver.setup_telemetry(build=info.build)
Luis Lozano23ae3192013-11-08 16:22:46 -0800136
137
138 def _setup_local_telemetry(self):
139 """Setup Telemetry to use local path to its sources.
140
141 First look for chrome source root, either externally mounted, or inside
142 the chroot. Prefer chrome-src-internal source tree to chrome-src.
143 """
144 TELEMETRY_DIR = 'src'
145 CHROME_LOCAL_SRC = '/var/cache/chromeos-cache/distfiles/target/'
Josh Triplett05208c92014-07-17 13:21:29 -0700146 CHROME_EXTERNAL_SRC = os.path.expanduser('~/chrome_root/')
Luis Lozano23ae3192013-11-08 16:22:46 -0800147
148 logging.debug('Setting up telemetry for local testing')
149
150 sources_list = ('chrome-src-internal', 'chrome-src')
Josh Triplett05208c92014-07-17 13:21:29 -0700151 dir_list = [CHROME_EXTERNAL_SRC]
Luis Lozano23ae3192013-11-08 16:22:46 -0800152 dir_list.extend(
153 [os.path.join(CHROME_LOCAL_SRC, x) for x in sources_list])
154 if 'CHROME_ROOT' in os.environ:
155 dir_list.insert(0, os.environ['CHROME_ROOT'])
156
157 telemetry_src = ''
158 for dir in dir_list:
159 if os.path.exists(dir):
160 telemetry_src = os.path.join(dir, TELEMETRY_DIR)
161 break
162 else:
163 raise error.TestError('Telemetry source directory not found.')
164
165 self._devserver = None
166 self._telemetry_path = telemetry_src
167
168
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800169 def _get_telemetry_cmd(self, script, test_or_benchmark, output_format,
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700170 *args, **kwargs):
Luis Lozano23ae3192013-11-08 16:22:46 -0800171 """Build command to execute telemetry based on script and benchmark.
172
173 @param script: Telemetry script we want to run. For example:
174 [path_to_telemetry_src]/src/tools/telemetry/run_tests.
175 @param test_or_benchmark: Name of the test or benchmark we want to run,
176 with the page_set (if required) as part of
177 the string.
Luis Lozano814c7182015-09-08 11:20:47 -0700178 @param args: additional list of arguments to pass to the script.
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700179 @param kwargs: additional list of keyword arguments to pass to the
180 script.
Luis Lozano814c7182015-09-08 11:20:47 -0700181
Luis Lozano23ae3192013-11-08 16:22:46 -0800182 @returns Full telemetry command to execute the script.
183 """
184 telemetry_cmd = []
185 if self._devserver:
Allen Lia5cfb972016-12-27 17:17:22 -0800186 devserver_hostname = self._devserver.hostname
Luis Lozano23ae3192013-11-08 16:22:46 -0800187 telemetry_cmd.extend(['ssh', devserver_hostname])
188
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700189 results_dir = kwargs.get('results_dir', '')
190 no_verbose = kwargs.get('no_verbose', False)
191
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800192 if self._telemetry_on_dut:
Denis Nikitinfdc2c712019-11-15 15:33:52 -0800193 telemetry_cmd.extend([
194 self._host.ssh_command(alive_interval=900,
195 connection_attempts=4),
Kuo-Hsin Yang66324262019-12-10 10:36:34 +0800196 'python2',
Denis Nikitinfdc2c712019-11-15 15:33:52 -0800197 script,
198 '--output-format=%s' % output_format,
199 '--output-dir=%s' % DUT_CHROME_ROOT,
200 '--browser=system',
201 ])
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800202 else:
Denis Nikitinfdc2c712019-11-15 15:33:52 -0800203 telemetry_cmd.extend([
Kuo-Hsin Yang66324262019-12-10 10:36:34 +0800204 'python2',
Denis Nikitinfdc2c712019-11-15 15:33:52 -0800205 script,
206 '--browser=cros-chrome',
207 '--output-format=%s' % output_format,
208 '--output-dir=%s' %
209 (results_dir if results_dir else self._telemetry_path),
210 '--remote=%s' % self._host.host_port,
211 ])
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700212 if not no_verbose:
213 telemetry_cmd.append('--verbose')
Luis Lozano814c7182015-09-08 11:20:47 -0700214 telemetry_cmd.extend(args)
215 telemetry_cmd.append(test_or_benchmark)
216
Keith Haddow1e5c7012016-03-09 16:05:37 -0800217 return ' '.join(telemetry_cmd)
218
219
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800220 def _scp_telemetry_results_cmd(self, perf_results_dir, output_format):
Keith Haddow1e5c7012016-03-09 16:05:37 -0800221 """Build command to copy the telemetry results from the devserver.
222
223 @param perf_results_dir: directory path where test output is to be
224 collected.
225 @returns SCP command to copy the results json to the specified directory.
226 """
Dean Liaoe3e75f62017-11-14 10:36:43 +0800227 if not perf_results_dir:
228 return ''
229
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800230 output_filename = CHART_JSON_RESULT
231 if output_format == 'histograms':
232 output_filename = HISTOGRAM_SET_RESULT
Dean Liaoe3e75f62017-11-14 10:36:43 +0800233 scp_cmd = ['scp']
234 if self._telemetry_on_dut:
235 scp_cmd.append(self._host.make_ssh_options(alive_interval=900,
236 connection_attempts=4))
237 if not self._host.is_default_port:
238 scp_cmd.append('-P %d' % self._host.port)
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800239 src = 'root@%s:%s/%s' % (self._host.hostname, DUT_CHROME_ROOT,
240 output_filename)
Dean Liaoe3e75f62017-11-14 10:36:43 +0800241 else:
242 devserver_hostname = ''
Ricky Liangd186f3e2016-03-15 16:50:55 +0800243 if self._devserver:
Allen Lia5cfb972016-12-27 17:17:22 -0800244 devserver_hostname = self._devserver.hostname + ':'
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800245 src = '%s%s/%s' % (devserver_hostname, self._telemetry_path,
246 output_filename)
Keith Haddow1e5c7012016-03-09 16:05:37 -0800247
Dean Liaoe3e75f62017-11-14 10:36:43 +0800248 scp_cmd.extend([src, perf_results_dir])
Keith Haddow1e5c7012016-03-09 16:05:37 -0800249 return ' '.join(scp_cmd)
250
251
252 def _run_cmd(self, cmd):
253 """Execute an command in a external shell and capture the output.
254
255 @param cmd: String of is a valid shell command.
256
257 @returns The standard out, standard error and the integer exit code of
258 the executed command.
259 """
260 logging.debug('Running: %s', cmd)
261
262 output = StringIO.StringIO()
263 error_output = StringIO.StringIO()
264 exit_code = 0
265 try:
266 result = utils.run(cmd, stdout_tee=output,
267 stderr_tee=error_output,
268 timeout=TELEMETRY_TIMEOUT_MINS*60)
269 exit_code = result.exit_status
270 except error.CmdError as e:
271 logging.debug('Error occurred executing.')
272 exit_code = e.result_obj.exit_status
273
274 stdout = output.getvalue()
275 stderr = error_output.getvalue()
276 logging.debug('Completed with exit code: %d.\nstdout:%s\n'
277 'stderr:%s', exit_code, stdout, stderr)
278 return stdout, stderr, exit_code
Simran Basi833814b2013-01-29 13:13:43 -0800279
280
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700281 def _run_telemetry(self, script, test_or_benchmark, output_format,
282 *args, **kwargs):
Simran Basi833814b2013-01-29 13:13:43 -0800283 """Runs telemetry on a dut.
284
285 @param script: Telemetry script we want to run. For example:
Luis Lozano23ae3192013-11-08 16:22:46 -0800286 [path_to_telemetry_src]/src/tools/telemetry/run_tests.
Simran Basi833814b2013-01-29 13:13:43 -0800287 @param test_or_benchmark: Name of the test or benchmark we want to run,
288 with the page_set (if required) as part of the
289 string.
Luis Lozano814c7182015-09-08 11:20:47 -0700290 @param args: additional list of arguments to pass to the script.
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700291 @param kwargs: additional list of keyword arguments to pass to the
292 script.
Simran Basi833814b2013-01-29 13:13:43 -0800293
294 @returns A TelemetryResult Instance with the results of this telemetry
295 execution.
296 """
Simran Basi1dbfc132013-05-02 10:11:02 -0700297 # TODO (sbasi crbug.com/239933) add support for incognito mode.
Simran Basi833814b2013-01-29 13:13:43 -0800298
Luis Lozano814c7182015-09-08 11:20:47 -0700299 telemetry_cmd = self._get_telemetry_cmd(script,
300 test_or_benchmark,
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800301 output_format,
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700302 *args,
303 **kwargs)
304 logging.info('Running Telemetry: %s', telemetry_cmd)
Luis Lozano23ae3192013-11-08 16:22:46 -0800305
Keith Haddow1e5c7012016-03-09 16:05:37 -0800306 stdout, stderr, exit_code = self._run_cmd(telemetry_cmd)
Simran Basi833814b2013-01-29 13:13:43 -0800307
308 return TelemetryResult(exit_code=exit_code, stdout=stdout,
309 stderr=stderr)
310
311
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800312 def _run_scp(self, perf_results_dir, output_format):
Keith Haddow1e5c7012016-03-09 16:05:37 -0800313 """Runs telemetry on a dut.
314
315 @param perf_results_dir: The local directory that results are being
316 collected.
317 """
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800318 scp_cmd = self._scp_telemetry_results_cmd(perf_results_dir,
319 output_format)
Keith Haddow1e5c7012016-03-09 16:05:37 -0800320 logging.debug('Retrieving Results: %s', scp_cmd)
Dean Liaoe4773c72017-11-09 16:15:38 +0800321 _, _, exit_code = self._run_cmd(scp_cmd)
322 if exit_code != 0:
323 raise error.TestFail('Unable to retrieve results.')
Keith Haddow1e5c7012016-03-09 16:05:37 -0800324
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800325 if output_format == 'histograms':
326 # Converts to chart json format.
327 input_filename = os.path.join(perf_results_dir,
328 HISTOGRAM_SET_RESULT)
329 output_filename = os.path.join(perf_results_dir,
330 CHART_JSON_RESULT)
331 histograms = json.loads(open(input_filename).read())
332 chartjson = TelemetryRunner.convert_chart_json(histograms)
333 with open(output_filename, 'w') as fout:
334 fout.write(json.dumps(chartjson, indent=2))
Keith Haddow1e5c7012016-03-09 16:05:37 -0800335
Luis Lozano814c7182015-09-08 11:20:47 -0700336 def _run_test(self, script, test, *args):
Simran Basi1dbfc132013-05-02 10:11:02 -0700337 """Runs a telemetry test on a dut.
338
339 @param script: Which telemetry test script we want to run. Can be
340 telemetry's base test script or the Chrome OS specific
341 test script.
342 @param test: Telemetry test we want to run.
Luis Lozano814c7182015-09-08 11:20:47 -0700343 @param args: additional list of arguments to pass to the script.
Simran Basi1dbfc132013-05-02 10:11:02 -0700344
345 @returns A TelemetryResult Instance with the results of this telemetry
346 execution.
347 """
348 logging.debug('Running telemetry test: %s', test)
349 telemetry_script = os.path.join(self._telemetry_path, script)
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800350 result = self._run_telemetry(telemetry_script, test, 'chartjson', *args)
Simran Basi1dbfc132013-05-02 10:11:02 -0700351 if result.status is FAILED_STATUS:
Ilja H. Friedelc7bf3102014-05-13 17:31:25 -0700352 raise error.TestFail('Telemetry test %s failed.' % test)
Simran Basi1dbfc132013-05-02 10:11:02 -0700353 return result
354
355
Luis Lozano814c7182015-09-08 11:20:47 -0700356 def run_telemetry_test(self, test, *args):
Simran Basi833814b2013-01-29 13:13:43 -0800357 """Runs a telemetry test on a dut.
358
359 @param test: Telemetry test we want to run.
Luis Lozano814c7182015-09-08 11:20:47 -0700360 @param args: additional list of arguments to pass to the telemetry
361 execution script.
Simran Basi833814b2013-01-29 13:13:43 -0800362
363 @returns A TelemetryResult Instance with the results of this telemetry
364 execution.
365 """
Luis Lozano814c7182015-09-08 11:20:47 -0700366 return self._run_test(TELEMETRY_RUN_TESTS_SCRIPT, test, *args)
Simran Basi1dbfc132013-05-02 10:11:02 -0700367
368
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700369 def run_telemetry_benchmark(self,
370 benchmark,
371 perf_value_writer=None,
372 *args,
373 **kwargs):
Simran Basi833814b2013-01-29 13:13:43 -0800374 """Runs a telemetry benchmark on a dut.
375
376 @param benchmark: Benchmark we want to run.
Fang Denge689e712013-11-13 18:27:06 -0800377 @param perf_value_writer: Should be an instance with the function
378 output_perf_value(), if None, no perf value
379 will be written. Typically this will be the
380 job object from an autotest test.
Luis Lozano814c7182015-09-08 11:20:47 -0700381 @param args: additional list of arguments to pass to the telemetry
382 execution script.
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700383 @param kwargs: additional list of keyword arguments to pass to the
384 telemetry execution script.
Simran Basi833814b2013-01-29 13:13:43 -0800385
386 @returns A TelemetryResult Instance with the results of this telemetry
387 execution.
388 """
Dave Tu6a404e62013-11-05 15:54:48 -0800389 logging.debug('Running telemetry benchmark: %s', benchmark)
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800390
Kuo-Hsin Yang07da7b62018-08-08 16:56:06 +0800391 if benchmark in ON_DUT_BLACKLIST:
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800392 self._telemetry_on_dut = False
393
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700394 output_format = kwargs.get('ex_output_format', '')
395
396 if not output_format:
Kuo-Hsin Yang72901f32019-10-28 14:24:58 +0800397 output_format = 'histograms'
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800398
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800399 if self._telemetry_on_dut:
400 telemetry_script = os.path.join(DUT_CHROME_ROOT,
401 TELEMETRY_RUN_BENCHMARKS_SCRIPT)
402 self._ensure_deps(self._host, benchmark)
403 else:
404 telemetry_script = os.path.join(self._telemetry_path,
405 TELEMETRY_RUN_BENCHMARKS_SCRIPT)
406
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800407 result = self._run_telemetry(telemetry_script, benchmark,
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700408 output_format, *args, **kwargs)
Simran Basi833814b2013-01-29 13:13:43 -0800409
410 if result.status is WARNING_STATUS:
Dave Tu6a404e62013-11-05 15:54:48 -0800411 raise error.TestWarn('Telemetry Benchmark: %s'
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700412 ' exited with Warnings.\nOutput:\n%s\n' %
413 (benchmark, result.output))
414 elif result.status is FAILED_STATUS:
Dave Tu6a404e62013-11-05 15:54:48 -0800415 raise error.TestFail('Telemetry Benchmark: %s'
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700416 ' failed to run.\nOutput:\n%s\n' %
417 (benchmark, result.output))
418 elif '[ PASSED ] 0 tests.' in result.output:
419 raise error.TestWarn('Telemetry Benchmark: %s exited successfully,'
420 ' but no test actually passed.\nOutput\n%s\n'
421 % (benchmark, result.output))
Keith Haddow1e5c7012016-03-09 16:05:37 -0800422 if perf_value_writer:
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800423 self._run_scp(perf_value_writer.resultsdir, output_format)
Simran Basi833814b2013-01-29 13:13:43 -0800424 return result
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800425
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700426
427 def run_gpu_integration_test(self, test, *args):
428 """Runs a gpu test on a dut.
429
430 @param test: Gpu test we want to run.
431 @param args: additional list of arguments to pass to the telemetry
432 execution script.
433
Drew Davenport84395922018-09-10 10:42:37 -0600434 @returns A TelemetryResult instance with the results of this telemetry
435 execution.
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700436 """
437 script = os.path.join(DUT_CHROME_ROOT,
438 TELEMETRY_RUN_GPU_TESTS_SCRIPT)
439 cmd = []
440 if self._devserver:
441 devserver_hostname = self._devserver.hostname
442 cmd.extend(['ssh', devserver_hostname])
443
444 cmd.extend(
Dean Liaoe3e75f62017-11-14 10:36:43 +0800445 [self._host.ssh_command(alive_interval=900, connection_attempts=4),
Kuo-Hsin Yang66324262019-12-10 10:36:34 +0800446 'python2', script])
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700447 cmd.extend(args)
448 cmd.append(test)
449 cmd = ' '.join(cmd)
450 stdout, stderr, exit_code = self._run_cmd(cmd)
451
Drew Davenport84395922018-09-10 10:42:37 -0600452 if exit_code:
453 raise error.TestFail('Gpu Integration Test: %s'
454 ' failed to run.' % test)
455
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700456 return TelemetryResult(exit_code=exit_code, stdout=stdout,
457 stderr=stderr)
458
459
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800460 def _ensure_deps(self, dut, test_name):
461 """
462 Ensure the dependencies are locally available on DUT.
463
464 @param dut: The autotest host object representing DUT.
465 @param test_name: Name of the telemetry test.
466 """
467 # Get DEPs using host's telemetry.
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800468 # Example output, fetch_benchmark_deps.py --output-deps=deps octane:
469 # {'octane': ['tools/perf/page_sets/data/octane_002.wprgo']}
Chinglin Yu0adaf112020-01-20 14:48:20 +0800470 fetch_path = os.path.join(self._telemetry_path,
471 'tools', 'perf', 'fetch_benchmark_deps.py')
472 # Use a temporary file for |deps_path| to avoid race conditions. The
473 # created temporary file is assigned to |self._benchmark_deps| to make
474 # it valid until |self| is destroyed.
475 self._benchmark_deps = tempfile.NamedTemporaryFile(
476 prefix='fetch_benchmark_deps_result.', suffix='.json')
477 deps_path = self._benchmark_deps.name
Kuo-Hsin Yang66324262019-12-10 10:36:34 +0800478 format_fetch = ('python2 %s --output-deps=%s %s')
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800479 command_fetch = format_fetch % (fetch_path, deps_path, test_name)
480 command_get = 'cat %s' % deps_path
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800481
482 if self._devserver:
483 devserver_hostname = self._devserver.url().split(
484 'http://')[1].split(':')[0]
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800485 command_fetch = 'ssh %s %s' % (devserver_hostname, command_fetch)
486 command_get = 'ssh %s %s' % (devserver_hostname, command_get)
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800487
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800488 logging.info('Getting DEPs: %s', command_fetch)
489 _, _, exit_code = self._run_cmd(command_fetch)
490 if exit_code != 0:
491 raise error.TestFail('Error occurred while fetching DEPs.')
492 stdout, _, exit_code = self._run_cmd(command_get)
493 if exit_code != 0:
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800494 raise error.TestFail('Error occurred while getting DEPs.')
495
496 # Download DEPs to DUT.
497 # send_file() relies on rsync over ssh. Couldn't be better.
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800498 deps = json.loads(stdout)
499 for dep in deps[test_name]:
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800500 src = os.path.join(self._telemetry_path, dep)
501 dst = os.path.join(DUT_CHROME_ROOT, dep)
Ting-Yuan Huang8a2c7f72016-03-28 22:01:07 +0800502 if self._devserver:
503 logging.info('Copying: %s -> %s', src, dst)
Chung-yih Wangfd8eb242017-12-09 19:23:04 +0800504 rsync_cmd = utils.sh_escape('rsync %s %s %s:%s' %
505 (self._host.rsync_options(), src,
506 self._host.hostname, dst))
507 utils.run('ssh %s "%s"' % (devserver_hostname, rsync_cmd))
Ting-Yuan Huang8a2c7f72016-03-28 22:01:07 +0800508 else:
509 if not os.path.isfile(src):
510 raise error.TestFail('Error occurred while saving DEPs.')
511 logging.info('Copying: %s -> %s', src, dst)
512 dut.send_file(src, dst)
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800513
514 @staticmethod
515 def convert_chart_json(histogram_set):
516 """
517 Convert from histogram set to chart json format.
518
519 @param histogram_set: result in histogram set format.
520
521 @returns result in chart json format.
522 """
523 value_map = {}
524
525 # Gets generic set values.
526 for obj in histogram_set:
527 if 'type' in obj and obj['type'] == 'GenericSet':
528 value_map[obj['guid']] = obj['values']
529
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800530 charts = {}
531 benchmark_name = ''
532 benchmark_desc = ''
533
534 # Checks the unit test for how this conversion works.
535 for obj in histogram_set:
536 if 'name' not in obj or 'sampleValues' not in obj:
537 continue
538 metric_name = obj['name']
539 diagnostics = obj['diagnostics']
Kuo-Hsin Yang72901f32019-10-28 14:24:58 +0800540 if diagnostics.has_key('stories'):
541 story_name = value_map[diagnostics['stories']][0]
542 else:
543 story_name = 'default'
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800544 local_benchmark_name = value_map[diagnostics['benchmarks']][0]
Kuo-Hsin Yang99622172019-09-16 20:02:53 +0800545 if benchmark_name == '':
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800546 benchmark_name = local_benchmark_name
Kuo-Hsin Yang72901f32019-10-28 14:24:58 +0800547 if diagnostics.has_key('benchmarkDescriptions'):
548 benchmark_desc = value_map[
549 diagnostics['benchmarkDescriptions']][0]
550 if benchmark_name != local_benchmark_name:
551 logging.warning('There are more than 1 benchmark names in the'
Kuo-Hsin Yangb1989752019-12-06 10:46:26 +0800552 'result. old: %s, new: %s',
553 benchmark_name, local_benchmark_name)
Kuo-Hsin Yang72901f32019-10-28 14:24:58 +0800554 continue
Kuo-Hsin Yang99622172019-09-16 20:02:53 +0800555
556 unit = obj['unit']
557 smaller_postfixes = ('_smallerIsBetter', '-')
558 bigger_postfixes = ('_biggerIsBetter', '+')
559 all_postfixes = smaller_postfixes + bigger_postfixes
560
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800561 improvement = 'up'
Kuo-Hsin Yang99622172019-09-16 20:02:53 +0800562 for postfix in smaller_postfixes:
563 if unit.endswith(postfix):
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800564 improvement = 'down'
Kuo-Hsin Yang99622172019-09-16 20:02:53 +0800565 for postfix in all_postfixes:
566 if unit.endswith(postfix):
567 unit = unit[:-len(postfix)]
568 break
569
570 if unit == 'unitless':
571 unit = 'score'
572
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800573 values = [x for x in obj['sampleValues']
574 if isinstance(x, numbers.Number)]
575 if metric_name not in charts:
576 charts[metric_name] = {}
577 charts[metric_name][story_name] = {
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800578 'improvement_direction': improvement,
579 'name': metric_name,
580 'std': numpy.std(values),
581 'type': 'list_of_scalar_values',
582 'units': unit,
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800583 'values': values
584 }
585
586 # Adds summaries.
587 for metric_name in charts:
588 values = []
589 metric_content = charts[metric_name]
590 for story_name in metric_content:
591 story_content = metric_content[story_name]
592 values += story_content['values']
593 metric_type = story_content['type']
594 units = story_content['units']
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800595 improvement = story_content['improvement_direction']
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800596 values.sort()
597 std = numpy.std(values)
598 metric_content['summary'] = {
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800599 'improvement_direction': improvement,
600 'name': metric_name,
601 'std': std,
602 'type': metric_type,
603 'units': units,
604 'values': values
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800605 }
606
607 benchmark_metadata = {
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800608 'description': benchmark_desc,
609 'name': benchmark_name,
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800610 'type': 'telemetry_benchmark'
611 }
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800612 return {
613 'benchmark_description': benchmark_desc,
614 'benchmark_metadata': benchmark_metadata,
615 'benchmark_name': benchmark_name,
616 'charts': charts,
617 'format_version': 1.0
618 }