blob: 425461a564c54935047ba8d8bce167125696795d [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,
176 *args):
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.
185
Luis Lozano23ae3192013-11-08 16:22:46 -0800186 @returns Full telemetry command to execute the script.
187 """
188 telemetry_cmd = []
189 if self._devserver:
Allen Lia5cfb972016-12-27 17:17:22 -0800190 devserver_hostname = self._devserver.hostname
Luis Lozano23ae3192013-11-08 16:22:46 -0800191 telemetry_cmd.extend(['ssh', devserver_hostname])
192
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800193 if self._telemetry_on_dut:
194 telemetry_cmd.extend(
Dean Liaoe3e75f62017-11-14 10:36:43 +0800195 [self._host.ssh_command(alive_interval=900,
196 connection_attempts=4),
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800197 'python',
198 script,
199 '--verbose',
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800200 '--output-format=%s' % output_format,
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800201 '--output-dir=%s' % DUT_CHROME_ROOT,
202 '--browser=system'])
203 else:
204 telemetry_cmd.extend(
205 ['python',
206 script,
207 '--verbose',
208 '--browser=cros-chrome',
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800209 '--output-format=%s' % output_format,
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800210 '--output-dir=%s' % self._telemetry_path,
Dean Liaoe3e75f62017-11-14 10:36:43 +0800211 '--remote=%s' % self._host.host_port])
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
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800279 def _run_telemetry(self, script, test_or_benchmark, output_format, *args):
Simran Basi833814b2013-01-29 13:13:43 -0800280 """Runs telemetry on a dut.
281
282 @param script: Telemetry script we want to run. For example:
Luis Lozano23ae3192013-11-08 16:22:46 -0800283 [path_to_telemetry_src]/src/tools/telemetry/run_tests.
Simran Basi833814b2013-01-29 13:13:43 -0800284 @param test_or_benchmark: Name of the test or benchmark we want to run,
285 with the page_set (if required) as part of the
286 string.
Luis Lozano814c7182015-09-08 11:20:47 -0700287 @param args: additional list of arguments to pass to the 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,
Luis Lozano814c7182015-09-08 11:20:47 -0700297 *args)
Keith Haddow1e5c7012016-03-09 16:05:37 -0800298 logging.debug('Running Telemetry: %s', telemetry_cmd)
Luis Lozano23ae3192013-11-08 16:22:46 -0800299
Keith Haddow1e5c7012016-03-09 16:05:37 -0800300 stdout, stderr, exit_code = self._run_cmd(telemetry_cmd)
Simran Basi833814b2013-01-29 13:13:43 -0800301
302 return TelemetryResult(exit_code=exit_code, stdout=stdout,
303 stderr=stderr)
304
305
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800306 def _run_scp(self, perf_results_dir, output_format):
Keith Haddow1e5c7012016-03-09 16:05:37 -0800307 """Runs telemetry on a dut.
308
309 @param perf_results_dir: The local directory that results are being
310 collected.
311 """
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800312 scp_cmd = self._scp_telemetry_results_cmd(perf_results_dir,
313 output_format)
Keith Haddow1e5c7012016-03-09 16:05:37 -0800314 logging.debug('Retrieving Results: %s', scp_cmd)
Dean Liaoe4773c72017-11-09 16:15:38 +0800315 _, _, exit_code = self._run_cmd(scp_cmd)
316 if exit_code != 0:
317 raise error.TestFail('Unable to retrieve results.')
Keith Haddow1e5c7012016-03-09 16:05:37 -0800318
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800319 if output_format == 'histograms':
320 # Converts to chart json format.
321 input_filename = os.path.join(perf_results_dir,
322 HISTOGRAM_SET_RESULT)
323 output_filename = os.path.join(perf_results_dir,
324 CHART_JSON_RESULT)
325 histograms = json.loads(open(input_filename).read())
326 chartjson = TelemetryRunner.convert_chart_json(histograms)
327 with open(output_filename, 'w') as fout:
328 fout.write(json.dumps(chartjson, indent=2))
Keith Haddow1e5c7012016-03-09 16:05:37 -0800329
Luis Lozano814c7182015-09-08 11:20:47 -0700330 def _run_test(self, script, test, *args):
Simran Basi1dbfc132013-05-02 10:11:02 -0700331 """Runs a telemetry test on a dut.
332
333 @param script: Which telemetry test script we want to run. Can be
334 telemetry's base test script or the Chrome OS specific
335 test script.
336 @param test: Telemetry test we want to run.
Luis Lozano814c7182015-09-08 11:20:47 -0700337 @param args: additional list of arguments to pass to the script.
Simran Basi1dbfc132013-05-02 10:11:02 -0700338
339 @returns A TelemetryResult Instance with the results of this telemetry
340 execution.
341 """
342 logging.debug('Running telemetry test: %s', test)
343 telemetry_script = os.path.join(self._telemetry_path, script)
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800344 result = self._run_telemetry(telemetry_script, test, 'chartjson', *args)
Simran Basi1dbfc132013-05-02 10:11:02 -0700345 if result.status is FAILED_STATUS:
Ilja H. Friedelc7bf3102014-05-13 17:31:25 -0700346 raise error.TestFail('Telemetry test %s failed.' % test)
Simran Basi1dbfc132013-05-02 10:11:02 -0700347 return result
348
349
Luis Lozano814c7182015-09-08 11:20:47 -0700350 def run_telemetry_test(self, test, *args):
Simran Basi833814b2013-01-29 13:13:43 -0800351 """Runs a telemetry test on a dut.
352
353 @param test: Telemetry test we want to run.
Luis Lozano814c7182015-09-08 11:20:47 -0700354 @param args: additional list of arguments to pass to the telemetry
355 execution script.
Simran Basi833814b2013-01-29 13:13:43 -0800356
357 @returns A TelemetryResult Instance with the results of this telemetry
358 execution.
359 """
Luis Lozano814c7182015-09-08 11:20:47 -0700360 return self._run_test(TELEMETRY_RUN_TESTS_SCRIPT, test, *args)
Simran Basi1dbfc132013-05-02 10:11:02 -0700361
362
Luis Lozano814c7182015-09-08 11:20:47 -0700363 def run_telemetry_benchmark(self, benchmark, perf_value_writer=None,
364 *args):
Simran Basi833814b2013-01-29 13:13:43 -0800365 """Runs a telemetry benchmark on a dut.
366
367 @param benchmark: Benchmark we want to run.
Fang Denge689e712013-11-13 18:27:06 -0800368 @param perf_value_writer: Should be an instance with the function
369 output_perf_value(), if None, no perf value
370 will be written. Typically this will be the
371 job object from an autotest test.
Luis Lozano814c7182015-09-08 11:20:47 -0700372 @param args: additional list of arguments to pass to the telemetry
373 execution script.
Simran Basi833814b2013-01-29 13:13:43 -0800374
375 @returns A TelemetryResult Instance with the results of this telemetry
376 execution.
377 """
Dave Tu6a404e62013-11-05 15:54:48 -0800378 logging.debug('Running telemetry benchmark: %s', benchmark)
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800379
Kuo-Hsin Yang07da7b62018-08-08 16:56:06 +0800380 if benchmark in ON_DUT_BLACKLIST:
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800381 self._telemetry_on_dut = False
382
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800383 output_format = 'chartjson'
384 if benchmark in HISTOGRAMS_WHITELIST:
385 output_format = 'histograms'
386
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800387 if self._telemetry_on_dut:
388 telemetry_script = os.path.join(DUT_CHROME_ROOT,
389 TELEMETRY_RUN_BENCHMARKS_SCRIPT)
390 self._ensure_deps(self._host, benchmark)
391 else:
392 telemetry_script = os.path.join(self._telemetry_path,
393 TELEMETRY_RUN_BENCHMARKS_SCRIPT)
394
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800395 result = self._run_telemetry(telemetry_script, benchmark,
396 output_format, *args)
Simran Basi833814b2013-01-29 13:13:43 -0800397
398 if result.status is WARNING_STATUS:
Dave Tu6a404e62013-11-05 15:54:48 -0800399 raise error.TestWarn('Telemetry Benchmark: %s'
400 ' exited with Warnings.' % benchmark)
Simran Basi833814b2013-01-29 13:13:43 -0800401 if result.status is FAILED_STATUS:
Dave Tu6a404e62013-11-05 15:54:48 -0800402 raise error.TestFail('Telemetry Benchmark: %s'
403 ' failed to run.' % benchmark)
Keith Haddow1e5c7012016-03-09 16:05:37 -0800404 if perf_value_writer:
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800405 self._run_scp(perf_value_writer.resultsdir, output_format)
Simran Basi833814b2013-01-29 13:13:43 -0800406 return result
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800407
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700408
409 def run_gpu_integration_test(self, test, *args):
410 """Runs a gpu test on a dut.
411
412 @param test: Gpu test we want to run.
413 @param args: additional list of arguments to pass to the telemetry
414 execution script.
415
Drew Davenport84395922018-09-10 10:42:37 -0600416 @returns A TelemetryResult instance with the results of this telemetry
417 execution.
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700418 """
419 script = os.path.join(DUT_CHROME_ROOT,
420 TELEMETRY_RUN_GPU_TESTS_SCRIPT)
421 cmd = []
422 if self._devserver:
423 devserver_hostname = self._devserver.hostname
424 cmd.extend(['ssh', devserver_hostname])
425
426 cmd.extend(
Dean Liaoe3e75f62017-11-14 10:36:43 +0800427 [self._host.ssh_command(alive_interval=900, connection_attempts=4),
428 'python', script])
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700429 cmd.extend(args)
430 cmd.append(test)
431 cmd = ' '.join(cmd)
432 stdout, stderr, exit_code = self._run_cmd(cmd)
433
Drew Davenport84395922018-09-10 10:42:37 -0600434 if exit_code:
435 raise error.TestFail('Gpu Integration Test: %s'
436 ' failed to run.' % test)
437
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700438 return TelemetryResult(exit_code=exit_code, stdout=stdout,
439 stderr=stderr)
440
441
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800442 def _ensure_deps(self, dut, test_name):
443 """
444 Ensure the dependencies are locally available on DUT.
445
446 @param dut: The autotest host object representing DUT.
447 @param test_name: Name of the telemetry test.
448 """
449 # Get DEPs using host's telemetry.
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800450 # Example output, fetch_benchmark_deps.py --output-deps=deps octane:
451 # {'octane': ['tools/perf/page_sets/data/octane_002.wprgo']}
452 perf_path = os.path.join(self._telemetry_path, 'tools', 'perf')
453 deps_path = os.path.join(perf_path, 'fetch_benchmark_deps_result.json')
454 fetch_path = os.path.join(perf_path, 'fetch_benchmark_deps.py')
455 format_fetch = ('python %s --output-deps=%s %s')
456 command_fetch = format_fetch % (fetch_path, deps_path, test_name)
457 command_get = 'cat %s' % deps_path
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800458
459 if self._devserver:
460 devserver_hostname = self._devserver.url().split(
461 'http://')[1].split(':')[0]
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800462 command_fetch = 'ssh %s %s' % (devserver_hostname, command_fetch)
463 command_get = 'ssh %s %s' % (devserver_hostname, command_get)
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800464
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800465 logging.info('Getting DEPs: %s', command_fetch)
466 _, _, exit_code = self._run_cmd(command_fetch)
467 if exit_code != 0:
468 raise error.TestFail('Error occurred while fetching DEPs.')
469 stdout, _, exit_code = self._run_cmd(command_get)
470 if exit_code != 0:
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800471 raise error.TestFail('Error occurred while getting DEPs.')
472
473 # Download DEPs to DUT.
474 # send_file() relies on rsync over ssh. Couldn't be better.
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800475 deps = json.loads(stdout)
476 for dep in deps[test_name]:
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800477 src = os.path.join(self._telemetry_path, dep)
478 dst = os.path.join(DUT_CHROME_ROOT, dep)
Ting-Yuan Huang8a2c7f72016-03-28 22:01:07 +0800479 if self._devserver:
480 logging.info('Copying: %s -> %s', src, dst)
Chung-yih Wangfd8eb242017-12-09 19:23:04 +0800481 rsync_cmd = utils.sh_escape('rsync %s %s %s:%s' %
482 (self._host.rsync_options(), src,
483 self._host.hostname, dst))
484 utils.run('ssh %s "%s"' % (devserver_hostname, rsync_cmd))
Ting-Yuan Huang8a2c7f72016-03-28 22:01:07 +0800485 else:
486 if not os.path.isfile(src):
487 raise error.TestFail('Error occurred while saving DEPs.')
488 logging.info('Copying: %s -> %s', src, dst)
489 dut.send_file(src, dst)
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800490
491 @staticmethod
492 def convert_chart_json(histogram_set):
493 """
494 Convert from histogram set to chart json format.
495
496 @param histogram_set: result in histogram set format.
497
498 @returns result in chart json format.
499 """
500 value_map = {}
501
502 # Gets generic set values.
503 for obj in histogram_set:
504 if 'type' in obj and obj['type'] == 'GenericSet':
505 value_map[obj['guid']] = obj['values']
506
507 # Mapping histogram set units to chart json units.
508 units_map = {'ms_smallerIsBetter': 'ms',
509 'unitless_biggerIsBetter': 'score'}
510
511 charts = {}
512 benchmark_name = ''
513 benchmark_desc = ''
514
515 # Checks the unit test for how this conversion works.
516 for obj in histogram_set:
517 if 'name' not in obj or 'sampleValues' not in obj:
518 continue
519 metric_name = obj['name']
520 diagnostics = obj['diagnostics']
521 story_name = value_map[diagnostics['stories']][0]
522 local_benchmark_name = value_map[diagnostics['benchmarks']][0]
523 if benchmark_name is '':
524 benchmark_name = local_benchmark_name
525 benchmark_desc = value_map[
526 diagnostics['benchmarkDescriptions']][0]
527 assert(benchmark_name == local_benchmark_name,
528 'There are more than 1 benchmark names in the result, '
529 'could not parse.')
530 unit = units_map.get(obj['unit'], '')
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800531 improvement = 'up'
532 if obj['unit'].endswith('smallerIsBetter'):
533 improvement = 'down'
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800534 values = [x for x in obj['sampleValues']
535 if isinstance(x, numbers.Number)]
536 if metric_name not in charts:
537 charts[metric_name] = {}
538 charts[metric_name][story_name] = {
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800539 'improvement_direction': improvement,
540 'name': metric_name,
541 'std': numpy.std(values),
542 'type': 'list_of_scalar_values',
543 'units': unit,
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800544 'values': values
545 }
546
547 # Adds summaries.
548 for metric_name in charts:
549 values = []
550 metric_content = charts[metric_name]
551 for story_name in metric_content:
552 story_content = metric_content[story_name]
553 values += story_content['values']
554 metric_type = story_content['type']
555 units = story_content['units']
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800556 improvement = story_content['improvement_direction']
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800557 values.sort()
558 std = numpy.std(values)
559 metric_content['summary'] = {
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800560 'improvement_direction': improvement,
561 'name': metric_name,
562 'std': std,
563 'type': metric_type,
564 'units': units,
565 'values': values
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800566 }
567
568 benchmark_metadata = {
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800569 'description': benchmark_desc,
570 'name': benchmark_name,
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800571 'type': 'telemetry_benchmark'
572 }
Kuo-Hsin Yange01ff602019-06-14 11:33:31 +0800573 return {
574 'benchmark_description': benchmark_desc,
575 'benchmark_metadata': benchmark_metadata,
576 'benchmark_name': benchmark_name,
577 'charts': charts,
578 'format_version': 1.0
579 }
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800580