blob: 3f412a7d39bbba654b1e899383d3ba9e262f4e88 [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
39class TelemetryResult(object):
40 """Class to represent the results of a telemetry run.
41
42 This class represents the results of a telemetry run, whether it ran
43 successful, failed or had warnings.
44 """
45
46
47 def __init__(self, exit_code=0, stdout='', stderr=''):
48 """Initializes this TelemetryResultObject instance.
49
50 @param status: Status of the telemtry run.
51 @param stdout: Stdout of the telemetry run.
52 @param stderr: Stderr of the telemetry run.
53 """
54 if exit_code == 0:
55 self.status = SUCCESS_STATUS
56 else:
57 self.status = FAILED_STATUS
58
Simran Basi833814b2013-01-29 13:13:43 -080059 self._stdout = stdout
60 self._stderr = stderr
61 self.output = '\n'.join([stdout, stderr])
62
63
Simran Basi833814b2013-01-29 13:13:43 -080064class TelemetryRunner(object):
65 """Class responsible for telemetry for a given build.
66
67 This class will extract and install telemetry on the devserver and is
68 responsible for executing the telemetry benchmarks and returning their
69 output to the caller.
70 """
71
Kuo-Hsin Yang66324262019-12-10 10:36:34 +080072 def __init__(self, host, local=False, telemetry_on_dut=True):
Simran Basi833814b2013-01-29 13:13:43 -080073 """Initializes this telemetry runner instance.
74
75 If telemetry is not installed for this build, it will be.
Luis Lozano23ae3192013-11-08 16:22:46 -080076
Ting-Yuan Huange5b19132016-03-22 13:02:41 +080077 Basically, the following commands on the local pc on which test_that
78 will be executed, depending on the 4 possible combinations of
79 local x telemetry_on_dut:
80
81 local=True, telemetry_on_dut=False:
Kuo-Hsin Yang66324262019-12-10 10:36:34 +080082 python2 run_benchmark --browser=cros-chrome --remote=[dut] [test]
Ting-Yuan Huange5b19132016-03-22 13:02:41 +080083
84 local=True, telemetry_on_dut=True:
Kuo-Hsin Yang66324262019-12-10 10:36:34 +080085 ssh [dut] python2 run_benchmark --browser=system [test]
Ting-Yuan Huange5b19132016-03-22 13:02:41 +080086
87 local=False, telemetry_on_dut=False:
Kuo-Hsin Yang66324262019-12-10 10:36:34 +080088 ssh [devserver] python2 run_benchmark --browser=cros-chrome
89 --remote=[dut] [test]
Ting-Yuan Huange5b19132016-03-22 13:02:41 +080090
91 local=False, telemetry_on_dut=True:
Kuo-Hsin Yang66324262019-12-10 10:36:34 +080092 ssh [devserver] ssh [dut] python2 run_benchmark --browser=system [test]
Ting-Yuan Huange5b19132016-03-22 13:02:41 +080093
Luis Lozano23ae3192013-11-08 16:22:46 -080094 @param host: Host where the test will be run.
95 @param local: If set, no devserver will be used, test will be run
96 locally.
Ting-Yuan Huange5b19132016-03-22 13:02:41 +080097 If not set, "ssh [devserver] " will be appended to test
98 commands.
99 @param telemetry_on_dut: If set, telemetry itself (the test harness)
100 will run on dut.
101 It decides browser=[system|cros-chrome]
Simran Basi833814b2013-01-29 13:13:43 -0800102 """
103 self._host = host
Ilja H. Friedelc7bf3102014-05-13 17:31:25 -0700104 self._devserver = None
105 self._telemetry_path = None
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800106 self._telemetry_on_dut = telemetry_on_dut
Luis Lozano23ae3192013-11-08 16:22:46 -0800107 # TODO (llozano crbug.com/324964). Remove conditional code.
108 # Use a class hierarchy instead.
109 if local:
110 self._setup_local_telemetry()
111 else:
112 self._setup_devserver_telemetry()
113
114 logging.debug('Telemetry Path: %s', self._telemetry_path)
115
116
117 def _setup_devserver_telemetry(self):
118 """Setup Telemetry to use the devserver."""
119 logging.debug('Setting up telemetry for devserver testing')
Simran Basi833814b2013-01-29 13:13:43 -0800120 logging.debug('Grabbing build from AFE.')
Prathmesh Prabhucfff58a2017-02-06 10:07:43 -0800121 info = self._host.host_info_store.get()
122 if not info.build:
Simran Basi833814b2013-01-29 13:13:43 -0800123 logging.error('Unable to locate build label for host: %s.',
Dean Liaoe3e75f62017-11-14 10:36:43 +0800124 self._host.host_port)
Simran Basi833814b2013-01-29 13:13:43 -0800125 raise error.AutotestError('Failed to grab build for host %s.' %
Dean Liaoe3e75f62017-11-14 10:36:43 +0800126 self._host.host_port)
Simran Basi833814b2013-01-29 13:13:43 -0800127
Prathmesh Prabhucfff58a2017-02-06 10:07:43 -0800128 logging.debug('Setting up telemetry for build: %s', info.build)
Simran Basi833814b2013-01-29 13:13:43 -0800129
Prathmesh Prabhucfff58a2017-02-06 10:07:43 -0800130 self._devserver = dev_server.ImageServer.resolve(
131 info.build, hostname=self._host.hostname)
132 self._devserver.stage_artifacts(info.build, ['autotest_packages'])
133 self._telemetry_path = self._devserver.setup_telemetry(build=info.build)
Luis Lozano23ae3192013-11-08 16:22:46 -0800134
135
136 def _setup_local_telemetry(self):
137 """Setup Telemetry to use local path to its sources.
138
139 First look for chrome source root, either externally mounted, or inside
140 the chroot. Prefer chrome-src-internal source tree to chrome-src.
141 """
142 TELEMETRY_DIR = 'src'
143 CHROME_LOCAL_SRC = '/var/cache/chromeos-cache/distfiles/target/'
Josh Triplett05208c92014-07-17 13:21:29 -0700144 CHROME_EXTERNAL_SRC = os.path.expanduser('~/chrome_root/')
Luis Lozano23ae3192013-11-08 16:22:46 -0800145
146 logging.debug('Setting up telemetry for local testing')
147
148 sources_list = ('chrome-src-internal', 'chrome-src')
Josh Triplett05208c92014-07-17 13:21:29 -0700149 dir_list = [CHROME_EXTERNAL_SRC]
Luis Lozano23ae3192013-11-08 16:22:46 -0800150 dir_list.extend(
151 [os.path.join(CHROME_LOCAL_SRC, x) for x in sources_list])
152 if 'CHROME_ROOT' in os.environ:
153 dir_list.insert(0, os.environ['CHROME_ROOT'])
154
155 telemetry_src = ''
156 for dir in dir_list:
157 if os.path.exists(dir):
158 telemetry_src = os.path.join(dir, TELEMETRY_DIR)
159 break
160 else:
161 raise error.TestError('Telemetry source directory not found.')
162
163 self._devserver = None
164 self._telemetry_path = telemetry_src
165
166
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800167 def _get_telemetry_cmd(self, script, test_or_benchmark, output_format,
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700168 *args, **kwargs):
Luis Lozano23ae3192013-11-08 16:22:46 -0800169 """Build command to execute telemetry based on script and benchmark.
170
171 @param script: Telemetry script we want to run. For example:
172 [path_to_telemetry_src]/src/tools/telemetry/run_tests.
173 @param test_or_benchmark: Name of the test or benchmark we want to run,
174 with the page_set (if required) as part of
175 the string.
Luis Lozano814c7182015-09-08 11:20:47 -0700176 @param args: additional list of arguments to pass to the script.
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700177 @param kwargs: additional list of keyword arguments to pass to the
178 script.
Luis Lozano814c7182015-09-08 11:20:47 -0700179
Luis Lozano23ae3192013-11-08 16:22:46 -0800180 @returns Full telemetry command to execute the script.
181 """
182 telemetry_cmd = []
183 if self._devserver:
Allen Lia5cfb972016-12-27 17:17:22 -0800184 devserver_hostname = self._devserver.hostname
Luis Lozano23ae3192013-11-08 16:22:46 -0800185 telemetry_cmd.extend(['ssh', devserver_hostname])
186
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700187 results_dir = kwargs.get('results_dir', '')
188 no_verbose = kwargs.get('no_verbose', False)
189
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800190 if self._telemetry_on_dut:
Denis Nikitinfdc2c712019-11-15 15:33:52 -0800191 telemetry_cmd.extend([
192 self._host.ssh_command(alive_interval=900,
193 connection_attempts=4),
Kuo-Hsin Yang66324262019-12-10 10:36:34 +0800194 'python2',
Denis Nikitinfdc2c712019-11-15 15:33:52 -0800195 script,
196 '--output-format=%s' % output_format,
197 '--output-dir=%s' % DUT_CHROME_ROOT,
198 '--browser=system',
199 ])
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800200 else:
Denis Nikitinfdc2c712019-11-15 15:33:52 -0800201 telemetry_cmd.extend([
Kuo-Hsin Yang66324262019-12-10 10:36:34 +0800202 'python2',
Denis Nikitinfdc2c712019-11-15 15:33:52 -0800203 script,
204 '--browser=cros-chrome',
205 '--output-format=%s' % output_format,
206 '--output-dir=%s' %
207 (results_dir if results_dir else self._telemetry_path),
208 '--remote=%s' % self._host.host_port,
209 ])
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700210 if not no_verbose:
211 telemetry_cmd.append('--verbose')
Luis Lozano814c7182015-09-08 11:20:47 -0700212 telemetry_cmd.extend(args)
213 telemetry_cmd.append(test_or_benchmark)
214
Keith Haddow1e5c7012016-03-09 16:05:37 -0800215 return ' '.join(telemetry_cmd)
216
217
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800218 def _scp_telemetry_results_cmd(self, perf_results_dir, output_format):
Keith Haddow1e5c7012016-03-09 16:05:37 -0800219 """Build command to copy the telemetry results from the devserver.
220
221 @param perf_results_dir: directory path where test output is to be
222 collected.
223 @returns SCP command to copy the results json to the specified directory.
224 """
Dean Liaoe3e75f62017-11-14 10:36:43 +0800225 if not perf_results_dir:
226 return ''
227
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800228 output_filename = CHART_JSON_RESULT
229 if output_format == 'histograms':
230 output_filename = HISTOGRAM_SET_RESULT
Dean Liaoe3e75f62017-11-14 10:36:43 +0800231 scp_cmd = ['scp']
232 if self._telemetry_on_dut:
233 scp_cmd.append(self._host.make_ssh_options(alive_interval=900,
234 connection_attempts=4))
235 if not self._host.is_default_port:
236 scp_cmd.append('-P %d' % self._host.port)
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800237 src = 'root@%s:%s/%s' % (self._host.hostname, DUT_CHROME_ROOT,
238 output_filename)
Dean Liaoe3e75f62017-11-14 10:36:43 +0800239 else:
240 devserver_hostname = ''
Ricky Liangd186f3e2016-03-15 16:50:55 +0800241 if self._devserver:
Allen Lia5cfb972016-12-27 17:17:22 -0800242 devserver_hostname = self._devserver.hostname + ':'
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800243 src = '%s%s/%s' % (devserver_hostname, self._telemetry_path,
244 output_filename)
Keith Haddow1e5c7012016-03-09 16:05:37 -0800245
Dean Liaoe3e75f62017-11-14 10:36:43 +0800246 scp_cmd.extend([src, perf_results_dir])
Keith Haddow1e5c7012016-03-09 16:05:37 -0800247 return ' '.join(scp_cmd)
248
249
250 def _run_cmd(self, cmd):
251 """Execute an command in a external shell and capture the output.
252
253 @param cmd: String of is a valid shell command.
254
255 @returns The standard out, standard error and the integer exit code of
256 the executed command.
257 """
258 logging.debug('Running: %s', cmd)
259
260 output = StringIO.StringIO()
261 error_output = StringIO.StringIO()
262 exit_code = 0
263 try:
264 result = utils.run(cmd, stdout_tee=output,
265 stderr_tee=error_output,
266 timeout=TELEMETRY_TIMEOUT_MINS*60)
267 exit_code = result.exit_status
268 except error.CmdError as e:
269 logging.debug('Error occurred executing.')
270 exit_code = e.result_obj.exit_status
271
272 stdout = output.getvalue()
273 stderr = error_output.getvalue()
274 logging.debug('Completed with exit code: %d.\nstdout:%s\n'
275 'stderr:%s', exit_code, stdout, stderr)
276 return stdout, stderr, exit_code
Simran Basi833814b2013-01-29 13:13:43 -0800277
278
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700279 def _run_telemetry(self, script, test_or_benchmark, output_format,
280 *args, **kwargs):
Simran Basi833814b2013-01-29 13:13:43 -0800281 """Runs telemetry on a dut.
282
283 @param script: Telemetry script we want to run. For example:
Luis Lozano23ae3192013-11-08 16:22:46 -0800284 [path_to_telemetry_src]/src/tools/telemetry/run_tests.
Simran Basi833814b2013-01-29 13:13:43 -0800285 @param test_or_benchmark: Name of the test or benchmark we want to run,
286 with the page_set (if required) as part of the
287 string.
Luis Lozano814c7182015-09-08 11:20:47 -0700288 @param args: additional list of arguments to pass to the script.
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700289 @param kwargs: additional list of keyword arguments to pass to the
290 script.
Simran Basi833814b2013-01-29 13:13:43 -0800291
292 @returns A TelemetryResult Instance with the results of this telemetry
293 execution.
294 """
Simran Basi1dbfc132013-05-02 10:11:02 -0700295 # TODO (sbasi crbug.com/239933) add support for incognito mode.
Simran Basi833814b2013-01-29 13:13:43 -0800296
Luis Lozano814c7182015-09-08 11:20:47 -0700297 telemetry_cmd = self._get_telemetry_cmd(script,
298 test_or_benchmark,
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800299 output_format,
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700300 *args,
301 **kwargs)
302 logging.info('Running Telemetry: %s', telemetry_cmd)
Luis Lozano23ae3192013-11-08 16:22:46 -0800303
Keith Haddow1e5c7012016-03-09 16:05:37 -0800304 stdout, stderr, exit_code = self._run_cmd(telemetry_cmd)
Simran Basi833814b2013-01-29 13:13:43 -0800305
306 return TelemetryResult(exit_code=exit_code, stdout=stdout,
307 stderr=stderr)
308
309
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800310 def _run_scp(self, perf_results_dir, output_format):
Keith Haddow1e5c7012016-03-09 16:05:37 -0800311 """Runs telemetry on a dut.
312
313 @param perf_results_dir: The local directory that results are being
314 collected.
315 """
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800316 scp_cmd = self._scp_telemetry_results_cmd(perf_results_dir,
317 output_format)
Keith Haddow1e5c7012016-03-09 16:05:37 -0800318 logging.debug('Retrieving Results: %s', scp_cmd)
Dean Liaoe4773c72017-11-09 16:15:38 +0800319 _, _, exit_code = self._run_cmd(scp_cmd)
320 if exit_code != 0:
321 raise error.TestFail('Unable to retrieve results.')
Keith Haddow1e5c7012016-03-09 16:05:37 -0800322
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800323 if output_format == 'histograms':
324 # Converts to chart json format.
325 input_filename = os.path.join(perf_results_dir,
326 HISTOGRAM_SET_RESULT)
327 output_filename = os.path.join(perf_results_dir,
328 CHART_JSON_RESULT)
329 histograms = json.loads(open(input_filename).read())
330 chartjson = TelemetryRunner.convert_chart_json(histograms)
331 with open(output_filename, 'w') as fout:
332 fout.write(json.dumps(chartjson, indent=2))
Keith Haddow1e5c7012016-03-09 16:05:37 -0800333
Luis Lozano814c7182015-09-08 11:20:47 -0700334 def _run_test(self, script, test, *args):
Simran Basi1dbfc132013-05-02 10:11:02 -0700335 """Runs a telemetry test on a dut.
336
337 @param script: Which telemetry test script we want to run. Can be
338 telemetry's base test script or the Chrome OS specific
339 test script.
340 @param test: Telemetry test we want to run.
Luis Lozano814c7182015-09-08 11:20:47 -0700341 @param args: additional list of arguments to pass to the script.
Simran Basi1dbfc132013-05-02 10:11:02 -0700342
343 @returns A TelemetryResult Instance with the results of this telemetry
344 execution.
345 """
346 logging.debug('Running telemetry test: %s', test)
347 telemetry_script = os.path.join(self._telemetry_path, script)
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800348 result = self._run_telemetry(telemetry_script, test, 'chartjson', *args)
Simran Basi1dbfc132013-05-02 10:11:02 -0700349 if result.status is FAILED_STATUS:
Ilja H. Friedelc7bf3102014-05-13 17:31:25 -0700350 raise error.TestFail('Telemetry test %s failed.' % test)
Simran Basi1dbfc132013-05-02 10:11:02 -0700351 return result
352
353
Luis Lozano814c7182015-09-08 11:20:47 -0700354 def run_telemetry_test(self, test, *args):
Simran Basi833814b2013-01-29 13:13:43 -0800355 """Runs a telemetry test on a dut.
356
357 @param test: Telemetry test we want to run.
Luis Lozano814c7182015-09-08 11:20:47 -0700358 @param args: additional list of arguments to pass to the telemetry
359 execution script.
Simran Basi833814b2013-01-29 13:13:43 -0800360
361 @returns A TelemetryResult Instance with the results of this telemetry
362 execution.
363 """
Luis Lozano814c7182015-09-08 11:20:47 -0700364 return self._run_test(TELEMETRY_RUN_TESTS_SCRIPT, test, *args)
Simran Basi1dbfc132013-05-02 10:11:02 -0700365
366
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700367 def run_telemetry_benchmark(self,
368 benchmark,
369 perf_value_writer=None,
370 *args,
371 **kwargs):
Simran Basi833814b2013-01-29 13:13:43 -0800372 """Runs a telemetry benchmark on a dut.
373
374 @param benchmark: Benchmark we want to run.
Fang Denge689e712013-11-13 18:27:06 -0800375 @param perf_value_writer: Should be an instance with the function
376 output_perf_value(), if None, no perf value
377 will be written. Typically this will be the
378 job object from an autotest test.
Luis Lozano814c7182015-09-08 11:20:47 -0700379 @param args: additional list of arguments to pass to the telemetry
380 execution script.
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700381 @param kwargs: additional list of keyword arguments to pass to the
382 telemetry execution script.
Simran Basi833814b2013-01-29 13:13:43 -0800383
384 @returns A TelemetryResult Instance with the results of this telemetry
385 execution.
386 """
Dave Tu6a404e62013-11-05 15:54:48 -0800387 logging.debug('Running telemetry benchmark: %s', benchmark)
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800388
Kuo-Hsin Yang07da7b62018-08-08 16:56:06 +0800389 if benchmark in ON_DUT_BLACKLIST:
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800390 self._telemetry_on_dut = False
391
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700392 output_format = kwargs.get('ex_output_format', '')
393
394 if not output_format:
Kuo-Hsin Yang72901f32019-10-28 14:24:58 +0800395 output_format = 'histograms'
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800396
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800397 if self._telemetry_on_dut:
398 telemetry_script = os.path.join(DUT_CHROME_ROOT,
399 TELEMETRY_RUN_BENCHMARKS_SCRIPT)
400 self._ensure_deps(self._host, benchmark)
401 else:
402 telemetry_script = os.path.join(self._telemetry_path,
403 TELEMETRY_RUN_BENCHMARKS_SCRIPT)
404
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800405 result = self._run_telemetry(telemetry_script, benchmark,
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700406 output_format, *args, **kwargs)
Simran Basi833814b2013-01-29 13:13:43 -0800407
408 if result.status is WARNING_STATUS:
Dave Tu6a404e62013-11-05 15:54:48 -0800409 raise error.TestWarn('Telemetry Benchmark: %s'
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700410 ' exited with Warnings.\nOutput:\n%s\n' %
411 (benchmark, result.output))
412 elif result.status is FAILED_STATUS:
Dave Tu6a404e62013-11-05 15:54:48 -0800413 raise error.TestFail('Telemetry Benchmark: %s'
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700414 ' failed to run.\nOutput:\n%s\n' %
415 (benchmark, result.output))
416 elif '[ PASSED ] 0 tests.' in result.output:
417 raise error.TestWarn('Telemetry Benchmark: %s exited successfully,'
418 ' but no test actually passed.\nOutput\n%s\n'
419 % (benchmark, result.output))
Keith Haddow1e5c7012016-03-09 16:05:37 -0800420 if perf_value_writer:
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800421 self._run_scp(perf_value_writer.resultsdir, output_format)
Simran Basi833814b2013-01-29 13:13:43 -0800422 return result
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800423
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700424
425 def run_gpu_integration_test(self, test, *args):
426 """Runs a gpu test on a dut.
427
428 @param test: Gpu test we want to run.
429 @param args: additional list of arguments to pass to the telemetry
430 execution script.
431
Drew Davenport84395922018-09-10 10:42:37 -0600432 @returns A TelemetryResult instance with the results of this telemetry
433 execution.
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700434 """
435 script = os.path.join(DUT_CHROME_ROOT,
436 TELEMETRY_RUN_GPU_TESTS_SCRIPT)
437 cmd = []
438 if self._devserver:
439 devserver_hostname = self._devserver.hostname
440 cmd.extend(['ssh', devserver_hostname])
441
442 cmd.extend(
Dean Liaoe3e75f62017-11-14 10:36:43 +0800443 [self._host.ssh_command(alive_interval=900, connection_attempts=4),
Kuo-Hsin Yang66324262019-12-10 10:36:34 +0800444 'python2', script])
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700445 cmd.extend(args)
446 cmd.append(test)
447 cmd = ' '.join(cmd)
448 stdout, stderr, exit_code = self._run_cmd(cmd)
449
Drew Davenport84395922018-09-10 10:42:37 -0600450 if exit_code:
451 raise error.TestFail('Gpu Integration Test: %s'
452 ' failed to run.' % test)
453
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700454 return TelemetryResult(exit_code=exit_code, stdout=stdout,
455 stderr=stderr)
456
457
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800458 def _ensure_deps(self, dut, test_name):
459 """
460 Ensure the dependencies are locally available on DUT.
461
462 @param dut: The autotest host object representing DUT.
463 @param test_name: Name of the telemetry test.
464 """
465 # Get DEPs using host's telemetry.
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800466 # Example output, fetch_benchmark_deps.py --output-deps=deps octane:
467 # {'octane': ['tools/perf/page_sets/data/octane_002.wprgo']}
468 perf_path = os.path.join(self._telemetry_path, 'tools', 'perf')
469 deps_path = os.path.join(perf_path, 'fetch_benchmark_deps_result.json')
470 fetch_path = os.path.join(perf_path, 'fetch_benchmark_deps.py')
Kuo-Hsin Yang66324262019-12-10 10:36:34 +0800471 format_fetch = ('python2 %s --output-deps=%s %s')
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800472 command_fetch = format_fetch % (fetch_path, deps_path, test_name)
473 command_get = 'cat %s' % deps_path
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800474
475 if self._devserver:
476 devserver_hostname = self._devserver.url().split(
477 'http://')[1].split(':')[0]
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800478 command_fetch = 'ssh %s %s' % (devserver_hostname, command_fetch)
479 command_get = 'ssh %s %s' % (devserver_hostname, command_get)
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800480
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800481 logging.info('Getting DEPs: %s', command_fetch)
482 _, _, exit_code = self._run_cmd(command_fetch)
483 if exit_code != 0:
484 raise error.TestFail('Error occurred while fetching DEPs.')
485 stdout, _, exit_code = self._run_cmd(command_get)
486 if exit_code != 0:
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800487 raise error.TestFail('Error occurred while getting DEPs.')
488
489 # Download DEPs to DUT.
490 # send_file() relies on rsync over ssh. Couldn't be better.
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800491 deps = json.loads(stdout)
492 for dep in deps[test_name]:
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800493 src = os.path.join(self._telemetry_path, dep)
494 dst = os.path.join(DUT_CHROME_ROOT, dep)
Ting-Yuan Huang8a2c7f72016-03-28 22:01:07 +0800495 if self._devserver:
496 logging.info('Copying: %s -> %s', src, dst)
Chung-yih Wangfd8eb242017-12-09 19:23:04 +0800497 rsync_cmd = utils.sh_escape('rsync %s %s %s:%s' %
498 (self._host.rsync_options(), src,
499 self._host.hostname, dst))
500 utils.run('ssh %s "%s"' % (devserver_hostname, rsync_cmd))
Ting-Yuan Huang8a2c7f72016-03-28 22:01:07 +0800501 else:
502 if not os.path.isfile(src):
503 raise error.TestFail('Error occurred while saving DEPs.')
504 logging.info('Copying: %s -> %s', src, dst)
505 dut.send_file(src, dst)
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800506
507 @staticmethod
508 def convert_chart_json(histogram_set):
509 """
510 Convert from histogram set to chart json format.
511
512 @param histogram_set: result in histogram set format.
513
514 @returns result in chart json format.
515 """
516 value_map = {}
517
518 # Gets generic set values.
519 for obj in histogram_set:
520 if 'type' in obj and obj['type'] == 'GenericSet':
521 value_map[obj['guid']] = obj['values']
522
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800523 charts = {}
524 benchmark_name = ''
525 benchmark_desc = ''
526
527 # Checks the unit test for how this conversion works.
528 for obj in histogram_set:
529 if 'name' not in obj or 'sampleValues' not in obj:
530 continue
531 metric_name = obj['name']
532 diagnostics = obj['diagnostics']
Kuo-Hsin Yang72901f32019-10-28 14:24:58 +0800533 if diagnostics.has_key('stories'):
534 story_name = value_map[diagnostics['stories']][0]
535 else:
536 story_name = 'default'
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800537 local_benchmark_name = value_map[diagnostics['benchmarks']][0]
Kuo-Hsin Yang99622172019-09-16 20:02:53 +0800538 if benchmark_name == '':
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800539 benchmark_name = local_benchmark_name
Kuo-Hsin Yang72901f32019-10-28 14:24:58 +0800540 if diagnostics.has_key('benchmarkDescriptions'):
541 benchmark_desc = value_map[
542 diagnostics['benchmarkDescriptions']][0]
543 if benchmark_name != local_benchmark_name:
544 logging.warning('There are more than 1 benchmark names in the'
Kuo-Hsin Yangb1989752019-12-06 10:46:26 +0800545 'result. old: %s, new: %s',
546 benchmark_name, local_benchmark_name)
Kuo-Hsin Yang72901f32019-10-28 14:24:58 +0800547 continue
Kuo-Hsin Yang99622172019-09-16 20:02:53 +0800548
549 unit = obj['unit']
550 smaller_postfixes = ('_smallerIsBetter', '-')
551 bigger_postfixes = ('_biggerIsBetter', '+')
552 all_postfixes = smaller_postfixes + bigger_postfixes
553
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800554 improvement = 'up'
Kuo-Hsin Yang99622172019-09-16 20:02:53 +0800555 for postfix in smaller_postfixes:
556 if unit.endswith(postfix):
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800557 improvement = 'down'
Kuo-Hsin Yang99622172019-09-16 20:02:53 +0800558 for postfix in all_postfixes:
559 if unit.endswith(postfix):
560 unit = unit[:-len(postfix)]
561 break
562
563 if unit == 'unitless':
564 unit = 'score'
565
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800566 values = [x for x in obj['sampleValues']
567 if isinstance(x, numbers.Number)]
568 if metric_name not in charts:
569 charts[metric_name] = {}
570 charts[metric_name][story_name] = {
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800571 'improvement_direction': improvement,
572 'name': metric_name,
573 'std': numpy.std(values),
574 'type': 'list_of_scalar_values',
575 'units': unit,
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800576 'values': values
577 }
578
579 # Adds summaries.
580 for metric_name in charts:
581 values = []
582 metric_content = charts[metric_name]
583 for story_name in metric_content:
584 story_content = metric_content[story_name]
585 values += story_content['values']
586 metric_type = story_content['type']
587 units = story_content['units']
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800588 improvement = story_content['improvement_direction']
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800589 values.sort()
590 std = numpy.std(values)
591 metric_content['summary'] = {
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800592 'improvement_direction': improvement,
593 'name': metric_name,
594 'std': std,
595 'type': metric_type,
596 'units': units,
597 'values': values
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800598 }
599
600 benchmark_metadata = {
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800601 'description': benchmark_desc,
602 'name': benchmark_name,
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800603 'type': 'telemetry_benchmark'
604 }
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800605 return {
606 'benchmark_description': benchmark_desc,
607 'benchmark_metadata': benchmark_metadata,
608 'benchmark_name': benchmark_name,
609 'charts': charts,
610 'format_version': 1.0
611 }
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800612