blob: cd49e2b7934aa06a6bf1513f829f2dce16669955 [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
Ting-Yuan Huang85dcde82016-04-08 17:41:32 +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:
82 run_benchmark --browser=cros-chrome --remote=[dut] [test]
83
84 local=True, telemetry_on_dut=True:
85 ssh [dut] run_benchmark --browser=system [test]
86
87 local=False, telemetry_on_dut=False:
88 ssh [devserver] run_benchmark --browser=cros-chrome --remote=[dut] [test]
89
90 local=False, telemetry_on_dut=True:
91 ssh [devserver] ssh [dut] run_benchmark --browser=system [test]
92
Luis Lozano23ae3192013-11-08 16:22:46 -080093 @param host: Host where the test will be run.
94 @param local: If set, no devserver will be used, test will be run
95 locally.
Ting-Yuan Huange5b19132016-03-22 13:02:41 +080096 If not set, "ssh [devserver] " will be appended to test
97 commands.
98 @param telemetry_on_dut: If set, telemetry itself (the test harness)
99 will run on dut.
100 It decides browser=[system|cros-chrome]
Simran Basi833814b2013-01-29 13:13:43 -0800101 """
102 self._host = host
Ilja H. Friedelc7bf3102014-05-13 17:31:25 -0700103 self._devserver = None
104 self._telemetry_path = None
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800105 self._telemetry_on_dut = telemetry_on_dut
Luis Lozano23ae3192013-11-08 16:22:46 -0800106 # TODO (llozano crbug.com/324964). Remove conditional code.
107 # Use a class hierarchy instead.
108 if local:
109 self._setup_local_telemetry()
110 else:
111 self._setup_devserver_telemetry()
112
113 logging.debug('Telemetry Path: %s', self._telemetry_path)
114
115
116 def _setup_devserver_telemetry(self):
117 """Setup Telemetry to use the devserver."""
118 logging.debug('Setting up telemetry for devserver testing')
Simran Basi833814b2013-01-29 13:13:43 -0800119 logging.debug('Grabbing build from AFE.')
Prathmesh Prabhucfff58a2017-02-06 10:07:43 -0800120 info = self._host.host_info_store.get()
121 if not info.build:
Simran Basi833814b2013-01-29 13:13:43 -0800122 logging.error('Unable to locate build label for host: %s.',
Dean Liaoe3e75f62017-11-14 10:36:43 +0800123 self._host.host_port)
Simran Basi833814b2013-01-29 13:13:43 -0800124 raise error.AutotestError('Failed to grab build for host %s.' %
Dean Liaoe3e75f62017-11-14 10:36:43 +0800125 self._host.host_port)
Simran Basi833814b2013-01-29 13:13:43 -0800126
Prathmesh Prabhucfff58a2017-02-06 10:07:43 -0800127 logging.debug('Setting up telemetry for build: %s', info.build)
Simran Basi833814b2013-01-29 13:13:43 -0800128
Prathmesh Prabhucfff58a2017-02-06 10:07:43 -0800129 self._devserver = dev_server.ImageServer.resolve(
130 info.build, hostname=self._host.hostname)
131 self._devserver.stage_artifacts(info.build, ['autotest_packages'])
132 self._telemetry_path = self._devserver.setup_telemetry(build=info.build)
Luis Lozano23ae3192013-11-08 16:22:46 -0800133
134
135 def _setup_local_telemetry(self):
136 """Setup Telemetry to use local path to its sources.
137
138 First look for chrome source root, either externally mounted, or inside
139 the chroot. Prefer chrome-src-internal source tree to chrome-src.
140 """
141 TELEMETRY_DIR = 'src'
142 CHROME_LOCAL_SRC = '/var/cache/chromeos-cache/distfiles/target/'
Josh Triplett05208c92014-07-17 13:21:29 -0700143 CHROME_EXTERNAL_SRC = os.path.expanduser('~/chrome_root/')
Luis Lozano23ae3192013-11-08 16:22:46 -0800144
145 logging.debug('Setting up telemetry for local testing')
146
147 sources_list = ('chrome-src-internal', 'chrome-src')
Josh Triplett05208c92014-07-17 13:21:29 -0700148 dir_list = [CHROME_EXTERNAL_SRC]
Luis Lozano23ae3192013-11-08 16:22:46 -0800149 dir_list.extend(
150 [os.path.join(CHROME_LOCAL_SRC, x) for x in sources_list])
151 if 'CHROME_ROOT' in os.environ:
152 dir_list.insert(0, os.environ['CHROME_ROOT'])
153
154 telemetry_src = ''
155 for dir in dir_list:
156 if os.path.exists(dir):
157 telemetry_src = os.path.join(dir, TELEMETRY_DIR)
158 break
159 else:
160 raise error.TestError('Telemetry source directory not found.')
161
162 self._devserver = None
163 self._telemetry_path = telemetry_src
164
165
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800166 def _get_telemetry_cmd(self, script, test_or_benchmark, output_format,
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700167 *args, **kwargs):
Luis Lozano23ae3192013-11-08 16:22:46 -0800168 """Build command to execute telemetry based on script and benchmark.
169
170 @param script: Telemetry script we want to run. For example:
171 [path_to_telemetry_src]/src/tools/telemetry/run_tests.
172 @param test_or_benchmark: Name of the test or benchmark we want to run,
173 with the page_set (if required) as part of
174 the string.
Luis Lozano814c7182015-09-08 11:20:47 -0700175 @param args: additional list of arguments to pass to the script.
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700176 @param kwargs: additional list of keyword arguments to pass to the
177 script.
Luis Lozano814c7182015-09-08 11:20:47 -0700178
Luis Lozano23ae3192013-11-08 16:22:46 -0800179 @returns Full telemetry command to execute the script.
180 """
181 telemetry_cmd = []
182 if self._devserver:
Allen Lia5cfb972016-12-27 17:17:22 -0800183 devserver_hostname = self._devserver.hostname
Luis Lozano23ae3192013-11-08 16:22:46 -0800184 telemetry_cmd.extend(['ssh', devserver_hostname])
185
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700186 results_dir = kwargs.get('results_dir', '')
187 no_verbose = kwargs.get('no_verbose', False)
188
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800189 if self._telemetry_on_dut:
190 telemetry_cmd.extend(
Dean Liaoe3e75f62017-11-14 10:36:43 +0800191 [self._host.ssh_command(alive_interval=900,
192 connection_attempts=4),
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800193 'python',
194 script,
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800195 '--output-format=%s' % output_format,
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800196 '--output-dir=%s' % DUT_CHROME_ROOT,
197 '--browser=system'])
198 else:
199 telemetry_cmd.extend(
200 ['python',
201 script,
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800202 '--browser=cros-chrome',
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800203 '--output-format=%s' % output_format,
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700204 '--output-dir=%s' %
205 (results_dir if results_dir else self._telemetry_path),
Dean Liaoe3e75f62017-11-14 10:36:43 +0800206 '--remote=%s' % self._host.host_port])
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700207 if not no_verbose:
208 telemetry_cmd.append('--verbose')
Luis Lozano814c7182015-09-08 11:20:47 -0700209 telemetry_cmd.extend(args)
210 telemetry_cmd.append(test_or_benchmark)
211
Keith Haddow1e5c7012016-03-09 16:05:37 -0800212 return ' '.join(telemetry_cmd)
213
214
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800215 def _scp_telemetry_results_cmd(self, perf_results_dir, output_format):
Keith Haddow1e5c7012016-03-09 16:05:37 -0800216 """Build command to copy the telemetry results from the devserver.
217
218 @param perf_results_dir: directory path where test output is to be
219 collected.
220 @returns SCP command to copy the results json to the specified directory.
221 """
Dean Liaoe3e75f62017-11-14 10:36:43 +0800222 if not perf_results_dir:
223 return ''
224
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800225 output_filename = CHART_JSON_RESULT
226 if output_format == 'histograms':
227 output_filename = HISTOGRAM_SET_RESULT
Dean Liaoe3e75f62017-11-14 10:36:43 +0800228 scp_cmd = ['scp']
229 if self._telemetry_on_dut:
230 scp_cmd.append(self._host.make_ssh_options(alive_interval=900,
231 connection_attempts=4))
232 if not self._host.is_default_port:
233 scp_cmd.append('-P %d' % self._host.port)
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800234 src = 'root@%s:%s/%s' % (self._host.hostname, DUT_CHROME_ROOT,
235 output_filename)
Dean Liaoe3e75f62017-11-14 10:36:43 +0800236 else:
237 devserver_hostname = ''
Ricky Liangd186f3e2016-03-15 16:50:55 +0800238 if self._devserver:
Allen Lia5cfb972016-12-27 17:17:22 -0800239 devserver_hostname = self._devserver.hostname + ':'
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800240 src = '%s%s/%s' % (devserver_hostname, self._telemetry_path,
241 output_filename)
Keith Haddow1e5c7012016-03-09 16:05:37 -0800242
Dean Liaoe3e75f62017-11-14 10:36:43 +0800243 scp_cmd.extend([src, perf_results_dir])
Keith Haddow1e5c7012016-03-09 16:05:37 -0800244 return ' '.join(scp_cmd)
245
246
247 def _run_cmd(self, cmd):
248 """Execute an command in a external shell and capture the output.
249
250 @param cmd: String of is a valid shell command.
251
252 @returns The standard out, standard error and the integer exit code of
253 the executed command.
254 """
255 logging.debug('Running: %s', cmd)
256
257 output = StringIO.StringIO()
258 error_output = StringIO.StringIO()
259 exit_code = 0
260 try:
261 result = utils.run(cmd, stdout_tee=output,
262 stderr_tee=error_output,
263 timeout=TELEMETRY_TIMEOUT_MINS*60)
264 exit_code = result.exit_status
265 except error.CmdError as e:
266 logging.debug('Error occurred executing.')
267 exit_code = e.result_obj.exit_status
268
269 stdout = output.getvalue()
270 stderr = error_output.getvalue()
271 logging.debug('Completed with exit code: %d.\nstdout:%s\n'
272 'stderr:%s', exit_code, stdout, stderr)
273 return stdout, stderr, exit_code
Simran Basi833814b2013-01-29 13:13:43 -0800274
275
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700276 def _run_telemetry(self, script, test_or_benchmark, output_format,
277 *args, **kwargs):
Simran Basi833814b2013-01-29 13:13:43 -0800278 """Runs telemetry on a dut.
279
280 @param script: Telemetry script we want to run. For example:
Luis Lozano23ae3192013-11-08 16:22:46 -0800281 [path_to_telemetry_src]/src/tools/telemetry/run_tests.
Simran Basi833814b2013-01-29 13:13:43 -0800282 @param test_or_benchmark: Name of the test or benchmark we want to run,
283 with the page_set (if required) as part of the
284 string.
Luis Lozano814c7182015-09-08 11:20:47 -0700285 @param args: additional list of arguments to pass to the script.
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700286 @param kwargs: additional list of keyword arguments to pass to the
287 script.
Simran Basi833814b2013-01-29 13:13:43 -0800288
289 @returns A TelemetryResult Instance with the results of this telemetry
290 execution.
291 """
Simran Basi1dbfc132013-05-02 10:11:02 -0700292 # TODO (sbasi crbug.com/239933) add support for incognito mode.
Simran Basi833814b2013-01-29 13:13:43 -0800293
Luis Lozano814c7182015-09-08 11:20:47 -0700294 telemetry_cmd = self._get_telemetry_cmd(script,
295 test_or_benchmark,
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800296 output_format,
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700297 *args,
298 **kwargs)
299 logging.info('Running Telemetry: %s', telemetry_cmd)
Luis Lozano23ae3192013-11-08 16:22:46 -0800300
Keith Haddow1e5c7012016-03-09 16:05:37 -0800301 stdout, stderr, exit_code = self._run_cmd(telemetry_cmd)
Simran Basi833814b2013-01-29 13:13:43 -0800302
303 return TelemetryResult(exit_code=exit_code, stdout=stdout,
304 stderr=stderr)
305
306
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800307 def _run_scp(self, perf_results_dir, output_format):
Keith Haddow1e5c7012016-03-09 16:05:37 -0800308 """Runs telemetry on a dut.
309
310 @param perf_results_dir: The local directory that results are being
311 collected.
312 """
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800313 scp_cmd = self._scp_telemetry_results_cmd(perf_results_dir,
314 output_format)
Keith Haddow1e5c7012016-03-09 16:05:37 -0800315 logging.debug('Retrieving Results: %s', scp_cmd)
Dean Liaoe4773c72017-11-09 16:15:38 +0800316 _, _, exit_code = self._run_cmd(scp_cmd)
317 if exit_code != 0:
318 raise error.TestFail('Unable to retrieve results.')
Keith Haddow1e5c7012016-03-09 16:05:37 -0800319
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800320 if output_format == 'histograms':
321 # Converts to chart json format.
322 input_filename = os.path.join(perf_results_dir,
323 HISTOGRAM_SET_RESULT)
324 output_filename = os.path.join(perf_results_dir,
325 CHART_JSON_RESULT)
326 histograms = json.loads(open(input_filename).read())
327 chartjson = TelemetryRunner.convert_chart_json(histograms)
328 with open(output_filename, 'w') as fout:
329 fout.write(json.dumps(chartjson, indent=2))
Keith Haddow1e5c7012016-03-09 16:05:37 -0800330
Luis Lozano814c7182015-09-08 11:20:47 -0700331 def _run_test(self, script, test, *args):
Simran Basi1dbfc132013-05-02 10:11:02 -0700332 """Runs a telemetry test on a dut.
333
334 @param script: Which telemetry test script we want to run. Can be
335 telemetry's base test script or the Chrome OS specific
336 test script.
337 @param test: Telemetry test we want to run.
Luis Lozano814c7182015-09-08 11:20:47 -0700338 @param args: additional list of arguments to pass to the script.
Simran Basi1dbfc132013-05-02 10:11:02 -0700339
340 @returns A TelemetryResult Instance with the results of this telemetry
341 execution.
342 """
343 logging.debug('Running telemetry test: %s', test)
344 telemetry_script = os.path.join(self._telemetry_path, script)
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800345 result = self._run_telemetry(telemetry_script, test, 'chartjson', *args)
Simran Basi1dbfc132013-05-02 10:11:02 -0700346 if result.status is FAILED_STATUS:
Ilja H. Friedelc7bf3102014-05-13 17:31:25 -0700347 raise error.TestFail('Telemetry test %s failed.' % test)
Simran Basi1dbfc132013-05-02 10:11:02 -0700348 return result
349
350
Luis Lozano814c7182015-09-08 11:20:47 -0700351 def run_telemetry_test(self, test, *args):
Simran Basi833814b2013-01-29 13:13:43 -0800352 """Runs a telemetry test on a dut.
353
354 @param test: Telemetry test we want to run.
Luis Lozano814c7182015-09-08 11:20:47 -0700355 @param args: additional list of arguments to pass to the telemetry
356 execution script.
Simran Basi833814b2013-01-29 13:13:43 -0800357
358 @returns A TelemetryResult Instance with the results of this telemetry
359 execution.
360 """
Luis Lozano814c7182015-09-08 11:20:47 -0700361 return self._run_test(TELEMETRY_RUN_TESTS_SCRIPT, test, *args)
Simran Basi1dbfc132013-05-02 10:11:02 -0700362
363
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700364 def run_telemetry_benchmark(self,
365 benchmark,
366 perf_value_writer=None,
367 *args,
368 **kwargs):
Simran Basi833814b2013-01-29 13:13:43 -0800369 """Runs a telemetry benchmark on a dut.
370
371 @param benchmark: Benchmark we want to run.
Fang Denge689e712013-11-13 18:27:06 -0800372 @param perf_value_writer: Should be an instance with the function
373 output_perf_value(), if None, no perf value
374 will be written. Typically this will be the
375 job object from an autotest test.
Luis Lozano814c7182015-09-08 11:20:47 -0700376 @param args: additional list of arguments to pass to the telemetry
377 execution script.
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700378 @param kwargs: additional list of keyword arguments to pass to the
379 telemetry execution script.
Simran Basi833814b2013-01-29 13:13:43 -0800380
381 @returns A TelemetryResult Instance with the results of this telemetry
382 execution.
383 """
Dave Tu6a404e62013-11-05 15:54:48 -0800384 logging.debug('Running telemetry benchmark: %s', benchmark)
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800385
Kuo-Hsin Yang07da7b62018-08-08 16:56:06 +0800386 if benchmark in ON_DUT_BLACKLIST:
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800387 self._telemetry_on_dut = False
388
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700389 output_format = kwargs.get('ex_output_format', '')
390
391 if not output_format:
Kuo-Hsin Yang72901f32019-10-28 14:24:58 +0800392 output_format = 'histograms'
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800393
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800394 if self._telemetry_on_dut:
395 telemetry_script = os.path.join(DUT_CHROME_ROOT,
396 TELEMETRY_RUN_BENCHMARKS_SCRIPT)
397 self._ensure_deps(self._host, benchmark)
398 else:
399 telemetry_script = os.path.join(self._telemetry_path,
400 TELEMETRY_RUN_BENCHMARKS_SCRIPT)
401
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800402 result = self._run_telemetry(telemetry_script, benchmark,
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700403 output_format, *args, **kwargs)
Simran Basi833814b2013-01-29 13:13:43 -0800404
405 if result.status is WARNING_STATUS:
Dave Tu6a404e62013-11-05 15:54:48 -0800406 raise error.TestWarn('Telemetry Benchmark: %s'
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700407 ' exited with Warnings.\nOutput:\n%s\n' %
408 (benchmark, result.output))
409 elif result.status is FAILED_STATUS:
Dave Tu6a404e62013-11-05 15:54:48 -0800410 raise error.TestFail('Telemetry Benchmark: %s'
Zhizhou Yangf32fda02019-09-25 14:01:45 -0700411 ' failed to run.\nOutput:\n%s\n' %
412 (benchmark, result.output))
413 elif '[ PASSED ] 0 tests.' in result.output:
414 raise error.TestWarn('Telemetry Benchmark: %s exited successfully,'
415 ' but no test actually passed.\nOutput\n%s\n'
416 % (benchmark, result.output))
Keith Haddow1e5c7012016-03-09 16:05:37 -0800417 if perf_value_writer:
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800418 self._run_scp(perf_value_writer.resultsdir, output_format)
Simran Basi833814b2013-01-29 13:13:43 -0800419 return result
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800420
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700421
422 def run_gpu_integration_test(self, test, *args):
423 """Runs a gpu test on a dut.
424
425 @param test: Gpu test we want to run.
426 @param args: additional list of arguments to pass to the telemetry
427 execution script.
428
Drew Davenport84395922018-09-10 10:42:37 -0600429 @returns A TelemetryResult instance with the results of this telemetry
430 execution.
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700431 """
432 script = os.path.join(DUT_CHROME_ROOT,
433 TELEMETRY_RUN_GPU_TESTS_SCRIPT)
434 cmd = []
435 if self._devserver:
436 devserver_hostname = self._devserver.hostname
437 cmd.extend(['ssh', devserver_hostname])
438
439 cmd.extend(
Dean Liaoe3e75f62017-11-14 10:36:43 +0800440 [self._host.ssh_command(alive_interval=900, connection_attempts=4),
441 'python', script])
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700442 cmd.extend(args)
443 cmd.append(test)
444 cmd = ' '.join(cmd)
445 stdout, stderr, exit_code = self._run_cmd(cmd)
446
Drew Davenport84395922018-09-10 10:42:37 -0600447 if exit_code:
448 raise error.TestFail('Gpu Integration Test: %s'
449 ' failed to run.' % test)
450
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700451 return TelemetryResult(exit_code=exit_code, stdout=stdout,
452 stderr=stderr)
453
454
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800455 def _ensure_deps(self, dut, test_name):
456 """
457 Ensure the dependencies are locally available on DUT.
458
459 @param dut: The autotest host object representing DUT.
460 @param test_name: Name of the telemetry test.
461 """
462 # Get DEPs using host's telemetry.
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800463 # Example output, fetch_benchmark_deps.py --output-deps=deps octane:
464 # {'octane': ['tools/perf/page_sets/data/octane_002.wprgo']}
465 perf_path = os.path.join(self._telemetry_path, 'tools', 'perf')
466 deps_path = os.path.join(perf_path, 'fetch_benchmark_deps_result.json')
467 fetch_path = os.path.join(perf_path, 'fetch_benchmark_deps.py')
468 format_fetch = ('python %s --output-deps=%s %s')
469 command_fetch = format_fetch % (fetch_path, deps_path, test_name)
470 command_get = 'cat %s' % deps_path
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800471
472 if self._devserver:
473 devserver_hostname = self._devserver.url().split(
474 'http://')[1].split(':')[0]
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800475 command_fetch = 'ssh %s %s' % (devserver_hostname, command_fetch)
476 command_get = 'ssh %s %s' % (devserver_hostname, command_get)
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800477
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800478 logging.info('Getting DEPs: %s', command_fetch)
479 _, _, exit_code = self._run_cmd(command_fetch)
480 if exit_code != 0:
481 raise error.TestFail('Error occurred while fetching DEPs.')
482 stdout, _, exit_code = self._run_cmd(command_get)
483 if exit_code != 0:
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800484 raise error.TestFail('Error occurred while getting DEPs.')
485
486 # Download DEPs to DUT.
487 # send_file() relies on rsync over ssh. Couldn't be better.
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800488 deps = json.loads(stdout)
489 for dep in deps[test_name]:
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800490 src = os.path.join(self._telemetry_path, dep)
491 dst = os.path.join(DUT_CHROME_ROOT, dep)
Ting-Yuan Huang8a2c7f72016-03-28 22:01:07 +0800492 if self._devserver:
493 logging.info('Copying: %s -> %s', src, dst)
Chung-yih Wangfd8eb242017-12-09 19:23:04 +0800494 rsync_cmd = utils.sh_escape('rsync %s %s %s:%s' %
495 (self._host.rsync_options(), src,
496 self._host.hostname, dst))
497 utils.run('ssh %s "%s"' % (devserver_hostname, rsync_cmd))
Ting-Yuan Huang8a2c7f72016-03-28 22:01:07 +0800498 else:
499 if not os.path.isfile(src):
500 raise error.TestFail('Error occurred while saving DEPs.')
501 logging.info('Copying: %s -> %s', src, dst)
502 dut.send_file(src, dst)
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800503
504 @staticmethod
505 def convert_chart_json(histogram_set):
506 """
507 Convert from histogram set to chart json format.
508
509 @param histogram_set: result in histogram set format.
510
511 @returns result in chart json format.
512 """
513 value_map = {}
514
515 # Gets generic set values.
516 for obj in histogram_set:
517 if 'type' in obj and obj['type'] == 'GenericSet':
518 value_map[obj['guid']] = obj['values']
519
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800520 charts = {}
521 benchmark_name = ''
522 benchmark_desc = ''
523
524 # Checks the unit test for how this conversion works.
525 for obj in histogram_set:
526 if 'name' not in obj or 'sampleValues' not in obj:
527 continue
528 metric_name = obj['name']
529 diagnostics = obj['diagnostics']
Kuo-Hsin Yang72901f32019-10-28 14:24:58 +0800530 if diagnostics.has_key('stories'):
531 story_name = value_map[diagnostics['stories']][0]
532 else:
533 story_name = 'default'
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800534 local_benchmark_name = value_map[diagnostics['benchmarks']][0]
Kuo-Hsin Yang99622172019-09-16 20:02:53 +0800535 if benchmark_name == '':
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800536 benchmark_name = local_benchmark_name
Kuo-Hsin Yang72901f32019-10-28 14:24:58 +0800537 if diagnostics.has_key('benchmarkDescriptions'):
538 benchmark_desc = value_map[
539 diagnostics['benchmarkDescriptions']][0]
540 if benchmark_name != local_benchmark_name:
541 logging.warning('There are more than 1 benchmark names in the'
542 'result. old: %s, new: %s' %
543 (benchmark_name, local_benchmark_name))
544 continue
Kuo-Hsin Yang99622172019-09-16 20:02:53 +0800545
546 unit = obj['unit']
547 smaller_postfixes = ('_smallerIsBetter', '-')
548 bigger_postfixes = ('_biggerIsBetter', '+')
549 all_postfixes = smaller_postfixes + bigger_postfixes
550
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800551 improvement = 'up'
Kuo-Hsin Yang99622172019-09-16 20:02:53 +0800552 for postfix in smaller_postfixes:
553 if unit.endswith(postfix):
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800554 improvement = 'down'
Kuo-Hsin Yang99622172019-09-16 20:02:53 +0800555 for postfix in all_postfixes:
556 if unit.endswith(postfix):
557 unit = unit[:-len(postfix)]
558 break
559
560 if unit == 'unitless':
561 unit = 'score'
562
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800563 values = [x for x in obj['sampleValues']
564 if isinstance(x, numbers.Number)]
565 if metric_name not in charts:
566 charts[metric_name] = {}
567 charts[metric_name][story_name] = {
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800568 'improvement_direction': improvement,
569 'name': metric_name,
570 'std': numpy.std(values),
571 'type': 'list_of_scalar_values',
572 'units': unit,
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800573 'values': values
574 }
575
576 # Adds summaries.
577 for metric_name in charts:
578 values = []
579 metric_content = charts[metric_name]
580 for story_name in metric_content:
581 story_content = metric_content[story_name]
582 values += story_content['values']
583 metric_type = story_content['type']
584 units = story_content['units']
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800585 improvement = story_content['improvement_direction']
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800586 values.sort()
587 std = numpy.std(values)
588 metric_content['summary'] = {
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800589 'improvement_direction': improvement,
590 'name': metric_name,
591 'std': std,
592 'type': metric_type,
593 'units': units,
594 'values': values
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800595 }
596
597 benchmark_metadata = {
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800598 'description': benchmark_desc,
599 'name': benchmark_name,
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800600 'type': 'telemetry_benchmark'
601 }
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800602 return {
603 'benchmark_description': benchmark_desc,
604 'benchmark_metadata': benchmark_metadata,
605 'benchmark_name': benchmark_name,
606 'charts': charts,
607 'format_version': 1.0
608 }
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800609