blob: 33022a638d5c6ca199c376801d7671455544549f [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
Simran Basi833814b2013-01-29 13:13:43 -080010import StringIO
11
Simran Basi833814b2013-01-29 13:13:43 -080012from autotest_lib.client.common_lib import error, utils
13from autotest_lib.client.common_lib.cros import dev_server
14
15
Dave Tu6a404e62013-11-05 15:54:48 -080016TELEMETRY_RUN_BENCHMARKS_SCRIPT = 'tools/perf/run_benchmark'
Ilja H. Friedel086bc3f2014-02-27 22:17:55 -080017TELEMETRY_RUN_TESTS_SCRIPT = 'tools/telemetry/run_tests'
Gurchetan Singhfaf75e92017-04-17 18:09:44 -070018TELEMETRY_RUN_GPU_TESTS_SCRIPT = 'content/test/gpu/run_gpu_integration_test.py'
Mao Huangc9642d72017-09-28 16:50:02 +080019TELEMETRY_TIMEOUT_MINS = 150
Simran Basi833814b2013-01-29 13:13:43 -080020
Ting-Yuan Huange5b19132016-03-22 13:02:41 +080021DUT_CHROME_ROOT = '/usr/local/telemetry/src'
22
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +080023CHART_JSON_RESULT = 'results-chart.json'
24HISTOGRAM_SET_RESULT = 'histograms.json'
25
Simran Basi833814b2013-01-29 13:13:43 -080026# Result Statuses
27SUCCESS_STATUS = 'SUCCESS'
28WARNING_STATUS = 'WARNING'
29FAILED_STATUS = 'FAILED'
30
Kuo-Hsin Yang07da7b62018-08-08 16:56:06 +080031# A list of telemetry tests that cannot run on dut.
Kuo-Hsin Yange0915472018-09-10 10:36:16 +080032ON_DUT_BLACKLIST = [
Kuo-Hsin Yang120c2042019-06-21 17:09:32 +080033 'cros_ui_smoothness', # crbug/976839
Kuo-Hsin Yange0915472018-09-10 10:36:16 +080034 'loading.desktop', # crbug/882299
35 'rendering.desktop', # crbug/882291
36 'system_health.memory_desktop', # crbug/874386
37]
Simran Basi833814b2013-01-29 13:13:43 -080038
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +080039# A list of telemetry tests that output histograms.
40HISTOGRAMS_WHITELIST = [
Tiancong Wanga45919e2019-09-05 16:00:57 -070041 'loading.desktop',
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +080042 'rendering.desktop',
Tiancong Wanga45919e2019-09-05 16:00:57 -070043 'octane',
44 'kraken',
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +080045 'speedometer2',
46]
47
Simran Basi833814b2013-01-29 13:13:43 -080048class TelemetryResult(object):
49 """Class to represent the results of a telemetry run.
50
51 This class represents the results of a telemetry run, whether it ran
52 successful, failed or had warnings.
53 """
54
55
56 def __init__(self, exit_code=0, stdout='', stderr=''):
57 """Initializes this TelemetryResultObject instance.
58
59 @param status: Status of the telemtry run.
60 @param stdout: Stdout of the telemetry run.
61 @param stderr: Stderr of the telemetry run.
62 """
63 if exit_code == 0:
64 self.status = SUCCESS_STATUS
65 else:
66 self.status = FAILED_STATUS
67
Simran Basi833814b2013-01-29 13:13:43 -080068 self._stdout = stdout
69 self._stderr = stderr
70 self.output = '\n'.join([stdout, stderr])
71
72
Simran Basi833814b2013-01-29 13:13:43 -080073class TelemetryRunner(object):
74 """Class responsible for telemetry for a given build.
75
76 This class will extract and install telemetry on the devserver and is
77 responsible for executing the telemetry benchmarks and returning their
78 output to the caller.
79 """
80
Ting-Yuan Huang85dcde82016-04-08 17:41:32 +080081 def __init__(self, host, local=False, telemetry_on_dut=True):
Simran Basi833814b2013-01-29 13:13:43 -080082 """Initializes this telemetry runner instance.
83
84 If telemetry is not installed for this build, it will be.
Luis Lozano23ae3192013-11-08 16:22:46 -080085
Ting-Yuan Huange5b19132016-03-22 13:02:41 +080086 Basically, the following commands on the local pc on which test_that
87 will be executed, depending on the 4 possible combinations of
88 local x telemetry_on_dut:
89
90 local=True, telemetry_on_dut=False:
91 run_benchmark --browser=cros-chrome --remote=[dut] [test]
92
93 local=True, telemetry_on_dut=True:
94 ssh [dut] run_benchmark --browser=system [test]
95
96 local=False, telemetry_on_dut=False:
97 ssh [devserver] run_benchmark --browser=cros-chrome --remote=[dut] [test]
98
99 local=False, telemetry_on_dut=True:
100 ssh [devserver] ssh [dut] run_benchmark --browser=system [test]
101
Luis Lozano23ae3192013-11-08 16:22:46 -0800102 @param host: Host where the test will be run.
103 @param local: If set, no devserver will be used, test will be run
104 locally.
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800105 If not set, "ssh [devserver] " will be appended to test
106 commands.
107 @param telemetry_on_dut: If set, telemetry itself (the test harness)
108 will run on dut.
109 It decides browser=[system|cros-chrome]
Simran Basi833814b2013-01-29 13:13:43 -0800110 """
111 self._host = host
Ilja H. Friedelc7bf3102014-05-13 17:31:25 -0700112 self._devserver = None
113 self._telemetry_path = None
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800114 self._telemetry_on_dut = telemetry_on_dut
Luis Lozano23ae3192013-11-08 16:22:46 -0800115 # TODO (llozano crbug.com/324964). Remove conditional code.
116 # Use a class hierarchy instead.
117 if local:
118 self._setup_local_telemetry()
119 else:
120 self._setup_devserver_telemetry()
121
122 logging.debug('Telemetry Path: %s', self._telemetry_path)
123
124
125 def _setup_devserver_telemetry(self):
126 """Setup Telemetry to use the devserver."""
127 logging.debug('Setting up telemetry for devserver testing')
Simran Basi833814b2013-01-29 13:13:43 -0800128 logging.debug('Grabbing build from AFE.')
Prathmesh Prabhucfff58a2017-02-06 10:07:43 -0800129 info = self._host.host_info_store.get()
130 if not info.build:
Simran Basi833814b2013-01-29 13:13:43 -0800131 logging.error('Unable to locate build label for host: %s.',
Dean Liaoe3e75f62017-11-14 10:36:43 +0800132 self._host.host_port)
Simran Basi833814b2013-01-29 13:13:43 -0800133 raise error.AutotestError('Failed to grab build for host %s.' %
Dean Liaoe3e75f62017-11-14 10:36:43 +0800134 self._host.host_port)
Simran Basi833814b2013-01-29 13:13:43 -0800135
Prathmesh Prabhucfff58a2017-02-06 10:07:43 -0800136 logging.debug('Setting up telemetry for build: %s', info.build)
Simran Basi833814b2013-01-29 13:13:43 -0800137
Prathmesh Prabhucfff58a2017-02-06 10:07:43 -0800138 self._devserver = dev_server.ImageServer.resolve(
139 info.build, hostname=self._host.hostname)
140 self._devserver.stage_artifacts(info.build, ['autotest_packages'])
141 self._telemetry_path = self._devserver.setup_telemetry(build=info.build)
Luis Lozano23ae3192013-11-08 16:22:46 -0800142
143
144 def _setup_local_telemetry(self):
145 """Setup Telemetry to use local path to its sources.
146
147 First look for chrome source root, either externally mounted, or inside
148 the chroot. Prefer chrome-src-internal source tree to chrome-src.
149 """
150 TELEMETRY_DIR = 'src'
151 CHROME_LOCAL_SRC = '/var/cache/chromeos-cache/distfiles/target/'
Josh Triplett05208c92014-07-17 13:21:29 -0700152 CHROME_EXTERNAL_SRC = os.path.expanduser('~/chrome_root/')
Luis Lozano23ae3192013-11-08 16:22:46 -0800153
154 logging.debug('Setting up telemetry for local testing')
155
156 sources_list = ('chrome-src-internal', 'chrome-src')
Josh Triplett05208c92014-07-17 13:21:29 -0700157 dir_list = [CHROME_EXTERNAL_SRC]
Luis Lozano23ae3192013-11-08 16:22:46 -0800158 dir_list.extend(
159 [os.path.join(CHROME_LOCAL_SRC, x) for x in sources_list])
160 if 'CHROME_ROOT' in os.environ:
161 dir_list.insert(0, os.environ['CHROME_ROOT'])
162
163 telemetry_src = ''
164 for dir in dir_list:
165 if os.path.exists(dir):
166 telemetry_src = os.path.join(dir, TELEMETRY_DIR)
167 break
168 else:
169 raise error.TestError('Telemetry source directory not found.')
170
171 self._devserver = None
172 self._telemetry_path = telemetry_src
173
174
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800175 def _get_telemetry_cmd(self, script, test_or_benchmark, output_format,
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700176 *args, **kwargs):
Luis Lozano23ae3192013-11-08 16:22:46 -0800177 """Build command to execute telemetry based on script and benchmark.
178
179 @param script: Telemetry script we want to run. For example:
180 [path_to_telemetry_src]/src/tools/telemetry/run_tests.
181 @param test_or_benchmark: Name of the test or benchmark we want to run,
182 with the page_set (if required) as part of
183 the string.
Luis Lozano814c7182015-09-08 11:20:47 -0700184 @param args: additional list of arguments to pass to the script.
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700185 @param kwargs: additional list of keyword arguments to pass to the
186 script.
Luis Lozano814c7182015-09-08 11:20:47 -0700187
Luis Lozano23ae3192013-11-08 16:22:46 -0800188 @returns Full telemetry command to execute the script.
189 """
190 telemetry_cmd = []
191 if self._devserver:
Allen Lia5cfb972016-12-27 17:17:22 -0800192 devserver_hostname = self._devserver.hostname
Luis Lozano23ae3192013-11-08 16:22:46 -0800193 telemetry_cmd.extend(['ssh', devserver_hostname])
194
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700195 results_dir = kwargs.get('results_dir', '')
196 no_verbose = kwargs.get('no_verbose', False)
197
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800198 if self._telemetry_on_dut:
199 telemetry_cmd.extend(
Dean Liaoe3e75f62017-11-14 10:36:43 +0800200 [self._host.ssh_command(alive_interval=900,
201 connection_attempts=4),
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800202 'python',
203 script,
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800204 '--output-format=%s' % output_format,
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800205 '--output-dir=%s' % DUT_CHROME_ROOT,
206 '--browser=system'])
207 else:
208 telemetry_cmd.extend(
209 ['python',
210 script,
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800211 '--browser=cros-chrome',
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800212 '--output-format=%s' % output_format,
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700213 '--output-dir=%s' %
214 (results_dir if results_dir else self._telemetry_path),
Dean Liaoe3e75f62017-11-14 10:36:43 +0800215 '--remote=%s' % self._host.host_port])
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700216 if not no_verbose:
217 telemetry_cmd.append('--verbose')
Luis Lozano814c7182015-09-08 11:20:47 -0700218 telemetry_cmd.extend(args)
219 telemetry_cmd.append(test_or_benchmark)
220
Keith Haddow1e5c7012016-03-09 16:05:37 -0800221 return ' '.join(telemetry_cmd)
222
223
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800224 def _scp_telemetry_results_cmd(self, perf_results_dir, output_format):
Keith Haddow1e5c7012016-03-09 16:05:37 -0800225 """Build command to copy the telemetry results from the devserver.
226
227 @param perf_results_dir: directory path where test output is to be
228 collected.
229 @returns SCP command to copy the results json to the specified directory.
230 """
Dean Liaoe3e75f62017-11-14 10:36:43 +0800231 if not perf_results_dir:
232 return ''
233
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800234 output_filename = CHART_JSON_RESULT
235 if output_format == 'histograms':
236 output_filename = HISTOGRAM_SET_RESULT
Dean Liaoe3e75f62017-11-14 10:36:43 +0800237 scp_cmd = ['scp']
238 if self._telemetry_on_dut:
239 scp_cmd.append(self._host.make_ssh_options(alive_interval=900,
240 connection_attempts=4))
241 if not self._host.is_default_port:
242 scp_cmd.append('-P %d' % self._host.port)
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800243 src = 'root@%s:%s/%s' % (self._host.hostname, DUT_CHROME_ROOT,
244 output_filename)
Dean Liaoe3e75f62017-11-14 10:36:43 +0800245 else:
246 devserver_hostname = ''
Ricky Liangd186f3e2016-03-15 16:50:55 +0800247 if self._devserver:
Allen Lia5cfb972016-12-27 17:17:22 -0800248 devserver_hostname = self._devserver.hostname + ':'
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800249 src = '%s%s/%s' % (devserver_hostname, self._telemetry_path,
250 output_filename)
Keith Haddow1e5c7012016-03-09 16:05:37 -0800251
Dean Liaoe3e75f62017-11-14 10:36:43 +0800252 scp_cmd.extend([src, perf_results_dir])
Keith Haddow1e5c7012016-03-09 16:05:37 -0800253 return ' '.join(scp_cmd)
254
255
256 def _run_cmd(self, cmd):
257 """Execute an command in a external shell and capture the output.
258
259 @param cmd: String of is a valid shell command.
260
261 @returns The standard out, standard error and the integer exit code of
262 the executed command.
263 """
264 logging.debug('Running: %s', cmd)
265
266 output = StringIO.StringIO()
267 error_output = StringIO.StringIO()
268 exit_code = 0
269 try:
270 result = utils.run(cmd, stdout_tee=output,
271 stderr_tee=error_output,
272 timeout=TELEMETRY_TIMEOUT_MINS*60)
273 exit_code = result.exit_status
274 except error.CmdError as e:
275 logging.debug('Error occurred executing.')
276 exit_code = e.result_obj.exit_status
277
278 stdout = output.getvalue()
279 stderr = error_output.getvalue()
280 logging.debug('Completed with exit code: %d.\nstdout:%s\n'
281 'stderr:%s', exit_code, stdout, stderr)
282 return stdout, stderr, exit_code
Simran Basi833814b2013-01-29 13:13:43 -0800283
284
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700285 def _run_telemetry(self, script, test_or_benchmark, output_format,
286 *args, **kwargs):
Simran Basi833814b2013-01-29 13:13:43 -0800287 """Runs telemetry on a dut.
288
289 @param script: Telemetry script we want to run. For example:
Luis Lozano23ae3192013-11-08 16:22:46 -0800290 [path_to_telemetry_src]/src/tools/telemetry/run_tests.
Simran Basi833814b2013-01-29 13:13:43 -0800291 @param test_or_benchmark: Name of the test or benchmark we want to run,
292 with the page_set (if required) as part of the
293 string.
Luis Lozano814c7182015-09-08 11:20:47 -0700294 @param args: additional list of arguments to pass to the script.
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700295 @param kwargs: additional list of keyword arguments to pass to the
296 script.
Simran Basi833814b2013-01-29 13:13:43 -0800297
298 @returns A TelemetryResult Instance with the results of this telemetry
299 execution.
300 """
Simran Basi1dbfc132013-05-02 10:11:02 -0700301 # TODO (sbasi crbug.com/239933) add support for incognito mode.
Simran Basi833814b2013-01-29 13:13:43 -0800302
Luis Lozano814c7182015-09-08 11:20:47 -0700303 telemetry_cmd = self._get_telemetry_cmd(script,
304 test_or_benchmark,
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800305 output_format,
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700306 *args,
307 **kwargs)
308 logging.info('Running Telemetry: %s', telemetry_cmd)
Luis Lozano23ae3192013-11-08 16:22:46 -0800309
Keith Haddow1e5c7012016-03-09 16:05:37 -0800310 stdout, stderr, exit_code = self._run_cmd(telemetry_cmd)
Simran Basi833814b2013-01-29 13:13:43 -0800311
312 return TelemetryResult(exit_code=exit_code, stdout=stdout,
313 stderr=stderr)
314
315
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800316 def _run_scp(self, perf_results_dir, output_format):
Keith Haddow1e5c7012016-03-09 16:05:37 -0800317 """Runs telemetry on a dut.
318
319 @param perf_results_dir: The local directory that results are being
320 collected.
321 """
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800322 scp_cmd = self._scp_telemetry_results_cmd(perf_results_dir,
323 output_format)
Keith Haddow1e5c7012016-03-09 16:05:37 -0800324 logging.debug('Retrieving Results: %s', scp_cmd)
Dean Liaoe4773c72017-11-09 16:15:38 +0800325 _, _, exit_code = self._run_cmd(scp_cmd)
326 if exit_code != 0:
327 raise error.TestFail('Unable to retrieve results.')
Keith Haddow1e5c7012016-03-09 16:05:37 -0800328
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800329 if output_format == 'histograms':
330 # Converts to chart json format.
331 input_filename = os.path.join(perf_results_dir,
332 HISTOGRAM_SET_RESULT)
333 output_filename = os.path.join(perf_results_dir,
334 CHART_JSON_RESULT)
335 histograms = json.loads(open(input_filename).read())
336 chartjson = TelemetryRunner.convert_chart_json(histograms)
337 with open(output_filename, 'w') as fout:
338 fout.write(json.dumps(chartjson, indent=2))
Keith Haddow1e5c7012016-03-09 16:05:37 -0800339
Luis Lozano814c7182015-09-08 11:20:47 -0700340 def _run_test(self, script, test, *args):
Simran Basi1dbfc132013-05-02 10:11:02 -0700341 """Runs a telemetry test on a dut.
342
343 @param script: Which telemetry test script we want to run. Can be
344 telemetry's base test script or the Chrome OS specific
345 test script.
346 @param test: Telemetry test we want to run.
Luis Lozano814c7182015-09-08 11:20:47 -0700347 @param args: additional list of arguments to pass to the script.
Simran Basi1dbfc132013-05-02 10:11:02 -0700348
349 @returns A TelemetryResult Instance with the results of this telemetry
350 execution.
351 """
352 logging.debug('Running telemetry test: %s', test)
353 telemetry_script = os.path.join(self._telemetry_path, script)
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800354 result = self._run_telemetry(telemetry_script, test, 'chartjson', *args)
Simran Basi1dbfc132013-05-02 10:11:02 -0700355 if result.status is FAILED_STATUS:
Ilja H. Friedelc7bf3102014-05-13 17:31:25 -0700356 raise error.TestFail('Telemetry test %s failed.' % test)
Simran Basi1dbfc132013-05-02 10:11:02 -0700357 return result
358
359
Luis Lozano814c7182015-09-08 11:20:47 -0700360 def run_telemetry_test(self, test, *args):
Simran Basi833814b2013-01-29 13:13:43 -0800361 """Runs a telemetry test on a dut.
362
363 @param test: Telemetry test we want to run.
Luis Lozano814c7182015-09-08 11:20:47 -0700364 @param args: additional list of arguments to pass to the telemetry
365 execution script.
Simran Basi833814b2013-01-29 13:13:43 -0800366
367 @returns A TelemetryResult Instance with the results of this telemetry
368 execution.
369 """
Luis Lozano814c7182015-09-08 11:20:47 -0700370 return self._run_test(TELEMETRY_RUN_TESTS_SCRIPT, test, *args)
Simran Basi1dbfc132013-05-02 10:11:02 -0700371
372
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700373 def run_telemetry_benchmark(self,
374 benchmark,
375 perf_value_writer=None,
376 *args,
377 **kwargs):
Simran Basi833814b2013-01-29 13:13:43 -0800378 """Runs a telemetry benchmark on a dut.
379
380 @param benchmark: Benchmark we want to run.
Fang Denge689e712013-11-13 18:27:06 -0800381 @param perf_value_writer: Should be an instance with the function
382 output_perf_value(), if None, no perf value
383 will be written. Typically this will be the
384 job object from an autotest test.
Luis Lozano814c7182015-09-08 11:20:47 -0700385 @param args: additional list of arguments to pass to the telemetry
386 execution script.
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700387 @param kwargs: additional list of keyword arguments to pass to the
388 telemetry execution script.
Simran Basi833814b2013-01-29 13:13:43 -0800389
390 @returns A TelemetryResult Instance with the results of this telemetry
391 execution.
392 """
Dave Tu6a404e62013-11-05 15:54:48 -0800393 logging.debug('Running telemetry benchmark: %s', benchmark)
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800394
Kuo-Hsin Yang07da7b62018-08-08 16:56:06 +0800395 if benchmark in ON_DUT_BLACKLIST:
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800396 self._telemetry_on_dut = False
397
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700398 output_format = kwargs.get('ex_output_format', '')
399
400 if not output_format:
401 output_format = 'chartjson'
402 if benchmark in HISTOGRAMS_WHITELIST:
403 output_format = 'histograms'
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800404
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800405 if self._telemetry_on_dut:
406 telemetry_script = os.path.join(DUT_CHROME_ROOT,
407 TELEMETRY_RUN_BENCHMARKS_SCRIPT)
408 self._ensure_deps(self._host, benchmark)
409 else:
410 telemetry_script = os.path.join(self._telemetry_path,
411 TELEMETRY_RUN_BENCHMARKS_SCRIPT)
412
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800413 result = self._run_telemetry(telemetry_script, benchmark,
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700414 output_format, *args, **kwargs)
Simran Basi833814b2013-01-29 13:13:43 -0800415
416 if result.status is WARNING_STATUS:
Dave Tu6a404e62013-11-05 15:54:48 -0800417 raise error.TestWarn('Telemetry Benchmark: %s'
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700418 ' exited with Warnings.\nOutput:\n%s\n' %
419 (benchmark, result.output))
420 elif result.status is FAILED_STATUS:
Dave Tu6a404e62013-11-05 15:54:48 -0800421 raise error.TestFail('Telemetry Benchmark: %s'
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700422 ' failed to run.\nOutput:\n%s\n' %
423 (benchmark, result.output))
424 elif '[ PASSED ] 0 tests.' in result.output:
425 raise error.TestWarn('Telemetry Benchmark: %s exited successfully,'
426 ' but no test actually passed.\nOutput\n%s\n'
427 % (benchmark, result.output))
Keith Haddow1e5c7012016-03-09 16:05:37 -0800428 if perf_value_writer:
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800429 self._run_scp(perf_value_writer.resultsdir, output_format)
Simran Basi833814b2013-01-29 13:13:43 -0800430 return result
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800431
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700432
433 def run_gpu_integration_test(self, test, *args):
434 """Runs a gpu test on a dut.
435
436 @param test: Gpu test we want to run.
437 @param args: additional list of arguments to pass to the telemetry
438 execution script.
439
Drew Davenport84395922018-09-10 10:42:37 -0600440 @returns A TelemetryResult instance with the results of this telemetry
441 execution.
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700442 """
443 script = os.path.join(DUT_CHROME_ROOT,
444 TELEMETRY_RUN_GPU_TESTS_SCRIPT)
445 cmd = []
446 if self._devserver:
447 devserver_hostname = self._devserver.hostname
448 cmd.extend(['ssh', devserver_hostname])
449
450 cmd.extend(
Dean Liaoe3e75f62017-11-14 10:36:43 +0800451 [self._host.ssh_command(alive_interval=900, connection_attempts=4),
452 'python', script])
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700453 cmd.extend(args)
454 cmd.append(test)
455 cmd = ' '.join(cmd)
456 stdout, stderr, exit_code = self._run_cmd(cmd)
457
Drew Davenport84395922018-09-10 10:42:37 -0600458 if exit_code:
459 raise error.TestFail('Gpu Integration Test: %s'
460 ' failed to run.' % test)
461
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700462 return TelemetryResult(exit_code=exit_code, stdout=stdout,
463 stderr=stderr)
464
465
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800466 def _ensure_deps(self, dut, test_name):
467 """
468 Ensure the dependencies are locally available on DUT.
469
470 @param dut: The autotest host object representing DUT.
471 @param test_name: Name of the telemetry test.
472 """
473 # Get DEPs using host's telemetry.
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800474 # Example output, fetch_benchmark_deps.py --output-deps=deps octane:
475 # {'octane': ['tools/perf/page_sets/data/octane_002.wprgo']}
476 perf_path = os.path.join(self._telemetry_path, 'tools', 'perf')
477 deps_path = os.path.join(perf_path, 'fetch_benchmark_deps_result.json')
478 fetch_path = os.path.join(perf_path, 'fetch_benchmark_deps.py')
479 format_fetch = ('python %s --output-deps=%s %s')
480 command_fetch = format_fetch % (fetch_path, deps_path, test_name)
481 command_get = 'cat %s' % deps_path
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800482
483 if self._devserver:
484 devserver_hostname = self._devserver.url().split(
485 'http://')[1].split(':')[0]
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800486 command_fetch = 'ssh %s %s' % (devserver_hostname, command_fetch)
487 command_get = 'ssh %s %s' % (devserver_hostname, command_get)
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800488
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800489 logging.info('Getting DEPs: %s', command_fetch)
490 _, _, exit_code = self._run_cmd(command_fetch)
491 if exit_code != 0:
492 raise error.TestFail('Error occurred while fetching DEPs.')
493 stdout, _, exit_code = self._run_cmd(command_get)
494 if exit_code != 0:
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800495 raise error.TestFail('Error occurred while getting DEPs.')
496
497 # Download DEPs to DUT.
498 # send_file() relies on rsync over ssh. Couldn't be better.
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800499 deps = json.loads(stdout)
500 for dep in deps[test_name]:
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800501 src = os.path.join(self._telemetry_path, dep)
502 dst = os.path.join(DUT_CHROME_ROOT, dep)
Ting-Yuan Huang8a2c7f72016-03-28 22:01:07 +0800503 if self._devserver:
504 logging.info('Copying: %s -> %s', src, dst)
Chung-yih Wangfd8eb242017-12-09 19:23:04 +0800505 rsync_cmd = utils.sh_escape('rsync %s %s %s:%s' %
506 (self._host.rsync_options(), src,
507 self._host.hostname, dst))
508 utils.run('ssh %s "%s"' % (devserver_hostname, rsync_cmd))
Ting-Yuan Huang8a2c7f72016-03-28 22:01:07 +0800509 else:
510 if not os.path.isfile(src):
511 raise error.TestFail('Error occurred while saving DEPs.')
512 logging.info('Copying: %s -> %s', src, dst)
513 dut.send_file(src, dst)
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800514
515 @staticmethod
516 def convert_chart_json(histogram_set):
517 """
518 Convert from histogram set to chart json format.
519
520 @param histogram_set: result in histogram set format.
521
522 @returns result in chart json format.
523 """
524 value_map = {}
525
526 # Gets generic set values.
527 for obj in histogram_set:
528 if 'type' in obj and obj['type'] == 'GenericSet':
529 value_map[obj['guid']] = obj['values']
530
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800531 charts = {}
532 benchmark_name = ''
533 benchmark_desc = ''
534
535 # Checks the unit test for how this conversion works.
536 for obj in histogram_set:
537 if 'name' not in obj or 'sampleValues' not in obj:
538 continue
539 metric_name = obj['name']
540 diagnostics = obj['diagnostics']
541 story_name = value_map[diagnostics['stories']][0]
542 local_benchmark_name = value_map[diagnostics['benchmarks']][0]
Kuo-Hsin Yang99622172019-09-16 20:02:53 +0800543 if benchmark_name == '':
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800544 benchmark_name = local_benchmark_name
545 benchmark_desc = value_map[
546 diagnostics['benchmarkDescriptions']][0]
Kuo-Hsin Yang99622172019-09-16 20:02:53 +0800547 assert benchmark_name == local_benchmark_name, ('There are more '
548 'than 1 benchmark names in the result, could not parse.')
549
550 unit = obj['unit']
551 smaller_postfixes = ('_smallerIsBetter', '-')
552 bigger_postfixes = ('_biggerIsBetter', '+')
553 all_postfixes = smaller_postfixes + bigger_postfixes
554
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800555 improvement = 'up'
Kuo-Hsin Yang99622172019-09-16 20:02:53 +0800556 for postfix in smaller_postfixes:
557 if unit.endswith(postfix):
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800558 improvement = 'down'
Kuo-Hsin Yang99622172019-09-16 20:02:53 +0800559 for postfix in all_postfixes:
560 if unit.endswith(postfix):
561 unit = unit[:-len(postfix)]
562 break
563
564 if unit == 'unitless':
565 unit = 'score'
566
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800567 values = [x for x in obj['sampleValues']
568 if isinstance(x, numbers.Number)]
569 if metric_name not in charts:
570 charts[metric_name] = {}
571 charts[metric_name][story_name] = {
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800572 'improvement_direction': improvement,
573 'name': metric_name,
574 'std': numpy.std(values),
575 'type': 'list_of_scalar_values',
576 'units': unit,
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800577 'values': values
578 }
579
580 # Adds summaries.
581 for metric_name in charts:
582 values = []
583 metric_content = charts[metric_name]
584 for story_name in metric_content:
585 story_content = metric_content[story_name]
586 values += story_content['values']
587 metric_type = story_content['type']
588 units = story_content['units']
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800589 improvement = story_content['improvement_direction']
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800590 values.sort()
591 std = numpy.std(values)
592 metric_content['summary'] = {
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800593 'improvement_direction': improvement,
594 'name': metric_name,
595 'std': std,
596 'type': metric_type,
597 'units': units,
598 'values': values
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800599 }
600
601 benchmark_metadata = {
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800602 'description': benchmark_desc,
603 'name': benchmark_name,
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800604 'type': 'telemetry_benchmark'
605 }
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800606 return {
607 'benchmark_description': benchmark_desc,
608 'benchmark_metadata': benchmark_metadata,
609 'benchmark_name': benchmark_name,
610 'charts': charts,
611 'format_version': 1.0
612 }
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800613