blob: d86bc41a1a10b537794a19c95d118ccab3e5b691 [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 = [
33 'loading.desktop', # crbug/882299
34 'rendering.desktop', # crbug/882291
35 'system_health.memory_desktop', # crbug/874386
36]
Simran Basi833814b2013-01-29 13:13:43 -080037
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +080038# A list of telemetry tests that output histograms.
39HISTOGRAMS_WHITELIST = [
40 'rendering.desktop',
41 'speedometer2',
42]
43
Simran Basi833814b2013-01-29 13:13:43 -080044class TelemetryResult(object):
45 """Class to represent the results of a telemetry run.
46
47 This class represents the results of a telemetry run, whether it ran
48 successful, failed or had warnings.
49 """
50
51
52 def __init__(self, exit_code=0, stdout='', stderr=''):
53 """Initializes this TelemetryResultObject instance.
54
55 @param status: Status of the telemtry run.
56 @param stdout: Stdout of the telemetry run.
57 @param stderr: Stderr of the telemetry run.
58 """
59 if exit_code == 0:
60 self.status = SUCCESS_STATUS
61 else:
62 self.status = FAILED_STATUS
63
Simran Basi833814b2013-01-29 13:13:43 -080064 self._stdout = stdout
65 self._stderr = stderr
66 self.output = '\n'.join([stdout, stderr])
67
68
Simran Basi833814b2013-01-29 13:13:43 -080069class TelemetryRunner(object):
70 """Class responsible for telemetry for a given build.
71
72 This class will extract and install telemetry on the devserver and is
73 responsible for executing the telemetry benchmarks and returning their
74 output to the caller.
75 """
76
Ting-Yuan Huang85dcde82016-04-08 17:41:32 +080077 def __init__(self, host, local=False, telemetry_on_dut=True):
Simran Basi833814b2013-01-29 13:13:43 -080078 """Initializes this telemetry runner instance.
79
80 If telemetry is not installed for this build, it will be.
Luis Lozano23ae3192013-11-08 16:22:46 -080081
Ting-Yuan Huange5b19132016-03-22 13:02:41 +080082 Basically, the following commands on the local pc on which test_that
83 will be executed, depending on the 4 possible combinations of
84 local x telemetry_on_dut:
85
86 local=True, telemetry_on_dut=False:
87 run_benchmark --browser=cros-chrome --remote=[dut] [test]
88
89 local=True, telemetry_on_dut=True:
90 ssh [dut] run_benchmark --browser=system [test]
91
92 local=False, telemetry_on_dut=False:
93 ssh [devserver] run_benchmark --browser=cros-chrome --remote=[dut] [test]
94
95 local=False, telemetry_on_dut=True:
96 ssh [devserver] ssh [dut] run_benchmark --browser=system [test]
97
Luis Lozano23ae3192013-11-08 16:22:46 -080098 @param host: Host where the test will be run.
99 @param local: If set, no devserver will be used, test will be run
100 locally.
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800101 If not set, "ssh [devserver] " will be appended to test
102 commands.
103 @param telemetry_on_dut: If set, telemetry itself (the test harness)
104 will run on dut.
105 It decides browser=[system|cros-chrome]
Simran Basi833814b2013-01-29 13:13:43 -0800106 """
107 self._host = host
Ilja H. Friedelc7bf3102014-05-13 17:31:25 -0700108 self._devserver = None
109 self._telemetry_path = None
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800110 self._telemetry_on_dut = telemetry_on_dut
Luis Lozano23ae3192013-11-08 16:22:46 -0800111 # TODO (llozano crbug.com/324964). Remove conditional code.
112 # Use a class hierarchy instead.
113 if local:
114 self._setup_local_telemetry()
115 else:
116 self._setup_devserver_telemetry()
117
118 logging.debug('Telemetry Path: %s', self._telemetry_path)
119
120
121 def _setup_devserver_telemetry(self):
122 """Setup Telemetry to use the devserver."""
123 logging.debug('Setting up telemetry for devserver testing')
Simran Basi833814b2013-01-29 13:13:43 -0800124 logging.debug('Grabbing build from AFE.')
Prathmesh Prabhucfff58a2017-02-06 10:07:43 -0800125 info = self._host.host_info_store.get()
126 if not info.build:
Simran Basi833814b2013-01-29 13:13:43 -0800127 logging.error('Unable to locate build label for host: %s.',
Dean Liaoe3e75f62017-11-14 10:36:43 +0800128 self._host.host_port)
Simran Basi833814b2013-01-29 13:13:43 -0800129 raise error.AutotestError('Failed to grab build for host %s.' %
Dean Liaoe3e75f62017-11-14 10:36:43 +0800130 self._host.host_port)
Simran Basi833814b2013-01-29 13:13:43 -0800131
Prathmesh Prabhucfff58a2017-02-06 10:07:43 -0800132 logging.debug('Setting up telemetry for build: %s', info.build)
Simran Basi833814b2013-01-29 13:13:43 -0800133
Prathmesh Prabhucfff58a2017-02-06 10:07:43 -0800134 self._devserver = dev_server.ImageServer.resolve(
135 info.build, hostname=self._host.hostname)
136 self._devserver.stage_artifacts(info.build, ['autotest_packages'])
137 self._telemetry_path = self._devserver.setup_telemetry(build=info.build)
Luis Lozano23ae3192013-11-08 16:22:46 -0800138
139
140 def _setup_local_telemetry(self):
141 """Setup Telemetry to use local path to its sources.
142
143 First look for chrome source root, either externally mounted, or inside
144 the chroot. Prefer chrome-src-internal source tree to chrome-src.
145 """
146 TELEMETRY_DIR = 'src'
147 CHROME_LOCAL_SRC = '/var/cache/chromeos-cache/distfiles/target/'
Josh Triplett05208c92014-07-17 13:21:29 -0700148 CHROME_EXTERNAL_SRC = os.path.expanduser('~/chrome_root/')
Luis Lozano23ae3192013-11-08 16:22:46 -0800149
150 logging.debug('Setting up telemetry for local testing')
151
152 sources_list = ('chrome-src-internal', 'chrome-src')
Josh Triplett05208c92014-07-17 13:21:29 -0700153 dir_list = [CHROME_EXTERNAL_SRC]
Luis Lozano23ae3192013-11-08 16:22:46 -0800154 dir_list.extend(
155 [os.path.join(CHROME_LOCAL_SRC, x) for x in sources_list])
156 if 'CHROME_ROOT' in os.environ:
157 dir_list.insert(0, os.environ['CHROME_ROOT'])
158
159 telemetry_src = ''
160 for dir in dir_list:
161 if os.path.exists(dir):
162 telemetry_src = os.path.join(dir, TELEMETRY_DIR)
163 break
164 else:
165 raise error.TestError('Telemetry source directory not found.')
166
167 self._devserver = None
168 self._telemetry_path = telemetry_src
169
170
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800171 def _get_telemetry_cmd(self, script, test_or_benchmark, output_format,
172 *args):
Luis Lozano23ae3192013-11-08 16:22:46 -0800173 """Build command to execute telemetry based on script and benchmark.
174
175 @param script: Telemetry script we want to run. For example:
176 [path_to_telemetry_src]/src/tools/telemetry/run_tests.
177 @param test_or_benchmark: Name of the test or benchmark we want to run,
178 with the page_set (if required) as part of
179 the string.
Luis Lozano814c7182015-09-08 11:20:47 -0700180 @param args: additional list of arguments to pass to the script.
181
Luis Lozano23ae3192013-11-08 16:22:46 -0800182 @returns Full telemetry command to execute the script.
183 """
184 telemetry_cmd = []
185 if self._devserver:
Allen Lia5cfb972016-12-27 17:17:22 -0800186 devserver_hostname = self._devserver.hostname
Luis Lozano23ae3192013-11-08 16:22:46 -0800187 telemetry_cmd.extend(['ssh', devserver_hostname])
188
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,
195 '--verbose',
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800196 '--output-format=%s' % output_format,
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800197 '--output-dir=%s' % DUT_CHROME_ROOT,
198 '--browser=system'])
199 else:
200 telemetry_cmd.extend(
201 ['python',
202 script,
203 '--verbose',
204 '--browser=cros-chrome',
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800205 '--output-format=%s' % output_format,
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800206 '--output-dir=%s' % self._telemetry_path,
Dean Liaoe3e75f62017-11-14 10:36:43 +0800207 '--remote=%s' % self._host.host_port])
Luis Lozano814c7182015-09-08 11:20:47 -0700208 telemetry_cmd.extend(args)
209 telemetry_cmd.append(test_or_benchmark)
210
Keith Haddow1e5c7012016-03-09 16:05:37 -0800211 return ' '.join(telemetry_cmd)
212
213
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800214 def _scp_telemetry_results_cmd(self, perf_results_dir, output_format):
Keith Haddow1e5c7012016-03-09 16:05:37 -0800215 """Build command to copy the telemetry results from the devserver.
216
217 @param perf_results_dir: directory path where test output is to be
218 collected.
219 @returns SCP command to copy the results json to the specified directory.
220 """
Dean Liaoe3e75f62017-11-14 10:36:43 +0800221 if not perf_results_dir:
222 return ''
223
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800224 output_filename = CHART_JSON_RESULT
225 if output_format == 'histograms':
226 output_filename = HISTOGRAM_SET_RESULT
Dean Liaoe3e75f62017-11-14 10:36:43 +0800227 scp_cmd = ['scp']
228 if self._telemetry_on_dut:
229 scp_cmd.append(self._host.make_ssh_options(alive_interval=900,
230 connection_attempts=4))
231 if not self._host.is_default_port:
232 scp_cmd.append('-P %d' % self._host.port)
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800233 src = 'root@%s:%s/%s' % (self._host.hostname, DUT_CHROME_ROOT,
234 output_filename)
Dean Liaoe3e75f62017-11-14 10:36:43 +0800235 else:
236 devserver_hostname = ''
Ricky Liangd186f3e2016-03-15 16:50:55 +0800237 if self._devserver:
Allen Lia5cfb972016-12-27 17:17:22 -0800238 devserver_hostname = self._devserver.hostname + ':'
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800239 src = '%s%s/%s' % (devserver_hostname, self._telemetry_path,
240 output_filename)
Keith Haddow1e5c7012016-03-09 16:05:37 -0800241
Dean Liaoe3e75f62017-11-14 10:36:43 +0800242 scp_cmd.extend([src, perf_results_dir])
Keith Haddow1e5c7012016-03-09 16:05:37 -0800243 return ' '.join(scp_cmd)
244
245
246 def _run_cmd(self, cmd):
247 """Execute an command in a external shell and capture the output.
248
249 @param cmd: String of is a valid shell command.
250
251 @returns The standard out, standard error and the integer exit code of
252 the executed command.
253 """
254 logging.debug('Running: %s', cmd)
255
256 output = StringIO.StringIO()
257 error_output = StringIO.StringIO()
258 exit_code = 0
259 try:
260 result = utils.run(cmd, stdout_tee=output,
261 stderr_tee=error_output,
262 timeout=TELEMETRY_TIMEOUT_MINS*60)
263 exit_code = result.exit_status
264 except error.CmdError as e:
265 logging.debug('Error occurred executing.')
266 exit_code = e.result_obj.exit_status
267
268 stdout = output.getvalue()
269 stderr = error_output.getvalue()
270 logging.debug('Completed with exit code: %d.\nstdout:%s\n'
271 'stderr:%s', exit_code, stdout, stderr)
272 return stdout, stderr, exit_code
Simran Basi833814b2013-01-29 13:13:43 -0800273
274
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800275 def _run_telemetry(self, script, test_or_benchmark, output_format, *args):
Simran Basi833814b2013-01-29 13:13:43 -0800276 """Runs telemetry on a dut.
277
278 @param script: Telemetry script we want to run. For example:
Luis Lozano23ae3192013-11-08 16:22:46 -0800279 [path_to_telemetry_src]/src/tools/telemetry/run_tests.
Simran Basi833814b2013-01-29 13:13:43 -0800280 @param test_or_benchmark: Name of the test or benchmark we want to run,
281 with the page_set (if required) as part of the
282 string.
Luis Lozano814c7182015-09-08 11:20:47 -0700283 @param args: additional list of arguments to pass to the script.
Simran Basi833814b2013-01-29 13:13:43 -0800284
285 @returns A TelemetryResult Instance with the results of this telemetry
286 execution.
287 """
Simran Basi1dbfc132013-05-02 10:11:02 -0700288 # TODO (sbasi crbug.com/239933) add support for incognito mode.
Simran Basi833814b2013-01-29 13:13:43 -0800289
Luis Lozano814c7182015-09-08 11:20:47 -0700290 telemetry_cmd = self._get_telemetry_cmd(script,
291 test_or_benchmark,
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800292 output_format,
Luis Lozano814c7182015-09-08 11:20:47 -0700293 *args)
Keith Haddow1e5c7012016-03-09 16:05:37 -0800294 logging.debug('Running Telemetry: %s', telemetry_cmd)
Luis Lozano23ae3192013-11-08 16:22:46 -0800295
Keith Haddow1e5c7012016-03-09 16:05:37 -0800296 stdout, stderr, exit_code = self._run_cmd(telemetry_cmd)
Simran Basi833814b2013-01-29 13:13:43 -0800297
298 return TelemetryResult(exit_code=exit_code, stdout=stdout,
299 stderr=stderr)
300
301
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800302 def _run_scp(self, perf_results_dir, output_format):
Keith Haddow1e5c7012016-03-09 16:05:37 -0800303 """Runs telemetry on a dut.
304
305 @param perf_results_dir: The local directory that results are being
306 collected.
307 """
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800308 scp_cmd = self._scp_telemetry_results_cmd(perf_results_dir,
309 output_format)
Keith Haddow1e5c7012016-03-09 16:05:37 -0800310 logging.debug('Retrieving Results: %s', scp_cmd)
Dean Liaoe4773c72017-11-09 16:15:38 +0800311 _, _, exit_code = self._run_cmd(scp_cmd)
312 if exit_code != 0:
313 raise error.TestFail('Unable to retrieve results.')
Keith Haddow1e5c7012016-03-09 16:05:37 -0800314
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800315 if output_format == 'histograms':
316 # Converts to chart json format.
317 input_filename = os.path.join(perf_results_dir,
318 HISTOGRAM_SET_RESULT)
319 output_filename = os.path.join(perf_results_dir,
320 CHART_JSON_RESULT)
321 histograms = json.loads(open(input_filename).read())
322 chartjson = TelemetryRunner.convert_chart_json(histograms)
323 with open(output_filename, 'w') as fout:
324 fout.write(json.dumps(chartjson, indent=2))
Keith Haddow1e5c7012016-03-09 16:05:37 -0800325
Luis Lozano814c7182015-09-08 11:20:47 -0700326 def _run_test(self, script, test, *args):
Simran Basi1dbfc132013-05-02 10:11:02 -0700327 """Runs a telemetry test on a dut.
328
329 @param script: Which telemetry test script we want to run. Can be
330 telemetry's base test script or the Chrome OS specific
331 test script.
332 @param test: Telemetry test we want to run.
Luis Lozano814c7182015-09-08 11:20:47 -0700333 @param args: additional list of arguments to pass to the script.
Simran Basi1dbfc132013-05-02 10:11:02 -0700334
335 @returns A TelemetryResult Instance with the results of this telemetry
336 execution.
337 """
338 logging.debug('Running telemetry test: %s', test)
339 telemetry_script = os.path.join(self._telemetry_path, script)
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800340 result = self._run_telemetry(telemetry_script, test, 'chartjson', *args)
Simran Basi1dbfc132013-05-02 10:11:02 -0700341 if result.status is FAILED_STATUS:
Ilja H. Friedelc7bf3102014-05-13 17:31:25 -0700342 raise error.TestFail('Telemetry test %s failed.' % test)
Simran Basi1dbfc132013-05-02 10:11:02 -0700343 return result
344
345
Luis Lozano814c7182015-09-08 11:20:47 -0700346 def run_telemetry_test(self, test, *args):
Simran Basi833814b2013-01-29 13:13:43 -0800347 """Runs a telemetry test on a dut.
348
349 @param test: Telemetry test we want to run.
Luis Lozano814c7182015-09-08 11:20:47 -0700350 @param args: additional list of arguments to pass to the telemetry
351 execution script.
Simran Basi833814b2013-01-29 13:13:43 -0800352
353 @returns A TelemetryResult Instance with the results of this telemetry
354 execution.
355 """
Luis Lozano814c7182015-09-08 11:20:47 -0700356 return self._run_test(TELEMETRY_RUN_TESTS_SCRIPT, test, *args)
Simran Basi1dbfc132013-05-02 10:11:02 -0700357
358
Luis Lozano814c7182015-09-08 11:20:47 -0700359 def run_telemetry_benchmark(self, benchmark, perf_value_writer=None,
360 *args):
Simran Basi833814b2013-01-29 13:13:43 -0800361 """Runs a telemetry benchmark on a dut.
362
363 @param benchmark: Benchmark we want to run.
Fang Denge689e712013-11-13 18:27:06 -0800364 @param perf_value_writer: Should be an instance with the function
365 output_perf_value(), if None, no perf value
366 will be written. Typically this will be the
367 job object from an autotest test.
Luis Lozano814c7182015-09-08 11:20:47 -0700368 @param args: additional list of arguments to pass to the telemetry
369 execution script.
Simran Basi833814b2013-01-29 13:13:43 -0800370
371 @returns A TelemetryResult Instance with the results of this telemetry
372 execution.
373 """
Dave Tu6a404e62013-11-05 15:54:48 -0800374 logging.debug('Running telemetry benchmark: %s', benchmark)
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800375
Kuo-Hsin Yang07da7b62018-08-08 16:56:06 +0800376 if benchmark in ON_DUT_BLACKLIST:
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800377 self._telemetry_on_dut = False
378
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800379 output_format = 'chartjson'
380 if benchmark in HISTOGRAMS_WHITELIST:
381 output_format = 'histograms'
382
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800383 if self._telemetry_on_dut:
384 telemetry_script = os.path.join(DUT_CHROME_ROOT,
385 TELEMETRY_RUN_BENCHMARKS_SCRIPT)
386 self._ensure_deps(self._host, benchmark)
387 else:
388 telemetry_script = os.path.join(self._telemetry_path,
389 TELEMETRY_RUN_BENCHMARKS_SCRIPT)
390
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800391 result = self._run_telemetry(telemetry_script, benchmark,
392 output_format, *args)
Simran Basi833814b2013-01-29 13:13:43 -0800393
394 if result.status is WARNING_STATUS:
Dave Tu6a404e62013-11-05 15:54:48 -0800395 raise error.TestWarn('Telemetry Benchmark: %s'
396 ' exited with Warnings.' % benchmark)
Simran Basi833814b2013-01-29 13:13:43 -0800397 if result.status is FAILED_STATUS:
Dave Tu6a404e62013-11-05 15:54:48 -0800398 raise error.TestFail('Telemetry Benchmark: %s'
399 ' failed to run.' % benchmark)
Keith Haddow1e5c7012016-03-09 16:05:37 -0800400 if perf_value_writer:
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800401 self._run_scp(perf_value_writer.resultsdir, output_format)
Simran Basi833814b2013-01-29 13:13:43 -0800402 return result
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800403
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700404
405 def run_gpu_integration_test(self, test, *args):
406 """Runs a gpu test on a dut.
407
408 @param test: Gpu test we want to run.
409 @param args: additional list of arguments to pass to the telemetry
410 execution script.
411
Drew Davenport84395922018-09-10 10:42:37 -0600412 @returns A TelemetryResult instance with the results of this telemetry
413 execution.
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700414 """
415 script = os.path.join(DUT_CHROME_ROOT,
416 TELEMETRY_RUN_GPU_TESTS_SCRIPT)
417 cmd = []
418 if self._devserver:
419 devserver_hostname = self._devserver.hostname
420 cmd.extend(['ssh', devserver_hostname])
421
422 cmd.extend(
Dean Liaoe3e75f62017-11-14 10:36:43 +0800423 [self._host.ssh_command(alive_interval=900, connection_attempts=4),
424 'python', script])
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700425 cmd.extend(args)
426 cmd.append(test)
427 cmd = ' '.join(cmd)
428 stdout, stderr, exit_code = self._run_cmd(cmd)
429
Drew Davenport84395922018-09-10 10:42:37 -0600430 if exit_code:
431 raise error.TestFail('Gpu Integration Test: %s'
432 ' failed to run.' % test)
433
Gurchetan Singhfaf75e92017-04-17 18:09:44 -0700434 return TelemetryResult(exit_code=exit_code, stdout=stdout,
435 stderr=stderr)
436
437
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800438 def _ensure_deps(self, dut, test_name):
439 """
440 Ensure the dependencies are locally available on DUT.
441
442 @param dut: The autotest host object representing DUT.
443 @param test_name: Name of the telemetry test.
444 """
445 # Get DEPs using host's telemetry.
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800446 # Example output, fetch_benchmark_deps.py --output-deps=deps octane:
447 # {'octane': ['tools/perf/page_sets/data/octane_002.wprgo']}
448 perf_path = os.path.join(self._telemetry_path, 'tools', 'perf')
449 deps_path = os.path.join(perf_path, 'fetch_benchmark_deps_result.json')
450 fetch_path = os.path.join(perf_path, 'fetch_benchmark_deps.py')
451 format_fetch = ('python %s --output-deps=%s %s')
452 command_fetch = format_fetch % (fetch_path, deps_path, test_name)
453 command_get = 'cat %s' % deps_path
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800454
455 if self._devserver:
456 devserver_hostname = self._devserver.url().split(
457 'http://')[1].split(':')[0]
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800458 command_fetch = 'ssh %s %s' % (devserver_hostname, command_fetch)
459 command_get = 'ssh %s %s' % (devserver_hostname, command_get)
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800460
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800461 logging.info('Getting DEPs: %s', command_fetch)
462 _, _, exit_code = self._run_cmd(command_fetch)
463 if exit_code != 0:
464 raise error.TestFail('Error occurred while fetching DEPs.')
465 stdout, _, exit_code = self._run_cmd(command_get)
466 if exit_code != 0:
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800467 raise error.TestFail('Error occurred while getting DEPs.')
468
469 # Download DEPs to DUT.
470 # send_file() relies on rsync over ssh. Couldn't be better.
Kuo-Hsin Yang4a006172018-04-25 14:44:55 +0800471 deps = json.loads(stdout)
472 for dep in deps[test_name]:
Ting-Yuan Huange5b19132016-03-22 13:02:41 +0800473 src = os.path.join(self._telemetry_path, dep)
474 dst = os.path.join(DUT_CHROME_ROOT, dep)
Ting-Yuan Huang8a2c7f72016-03-28 22:01:07 +0800475 if self._devserver:
476 logging.info('Copying: %s -> %s', src, dst)
Chung-yih Wangfd8eb242017-12-09 19:23:04 +0800477 rsync_cmd = utils.sh_escape('rsync %s %s %s:%s' %
478 (self._host.rsync_options(), src,
479 self._host.hostname, dst))
480 utils.run('ssh %s "%s"' % (devserver_hostname, rsync_cmd))
Ting-Yuan Huang8a2c7f72016-03-28 22:01:07 +0800481 else:
482 if not os.path.isfile(src):
483 raise error.TestFail('Error occurred while saving DEPs.')
484 logging.info('Copying: %s -> %s', src, dst)
485 dut.send_file(src, dst)
Kuo-Hsin Yang14d002b2019-06-06 13:18:04 +0800486
487 @staticmethod
488 def convert_chart_json(histogram_set):
489 """
490 Convert from histogram set to chart json format.
491
492 @param histogram_set: result in histogram set format.
493
494 @returns result in chart json format.
495 """
496 value_map = {}
497
498 # Gets generic set values.
499 for obj in histogram_set:
500 if 'type' in obj and obj['type'] == 'GenericSet':
501 value_map[obj['guid']] = obj['values']
502
503 # Mapping histogram set units to chart json units.
504 units_map = {'ms_smallerIsBetter': 'ms',
505 'unitless_biggerIsBetter': 'score'}
506
507 charts = {}
508 benchmark_name = ''
509 benchmark_desc = ''
510
511 # Checks the unit test for how this conversion works.
512 for obj in histogram_set:
513 if 'name' not in obj or 'sampleValues' not in obj:
514 continue
515 metric_name = obj['name']
516 diagnostics = obj['diagnostics']
517 story_name = value_map[diagnostics['stories']][0]
518 local_benchmark_name = value_map[diagnostics['benchmarks']][0]
519 if benchmark_name is '':
520 benchmark_name = local_benchmark_name
521 benchmark_desc = value_map[
522 diagnostics['benchmarkDescriptions']][0]
523 assert(benchmark_name == local_benchmark_name,
524 'There are more than 1 benchmark names in the result, '
525 'could not parse.')
526 unit = units_map.get(obj['unit'], '')
527 values = [x for x in obj['sampleValues']
528 if isinstance(x, numbers.Number)]
529 if metric_name not in charts:
530 charts[metric_name] = {}
531 charts[metric_name][story_name] = {
532 'name': metric_name, 'std': numpy.std(values),
533 'type': 'list_of_scalar_values', 'units': unit,
534 'values': values
535 }
536
537 # Adds summaries.
538 for metric_name in charts:
539 values = []
540 metric_content = charts[metric_name]
541 for story_name in metric_content:
542 story_content = metric_content[story_name]
543 values += story_content['values']
544 metric_type = story_content['type']
545 units = story_content['units']
546 values.sort()
547 std = numpy.std(values)
548 metric_content['summary'] = {
549 'name': metric_name, 'std': std, 'type': metric_type,
550 'units': units, 'values': values
551 }
552
553 benchmark_metadata = {
554 'description': benchmark_desc, 'name': benchmark_name,
555 'type': 'telemetry_benchmark'
556 }
557 return {'benchmark_description': benchmark_desc,
558 'benchmark_metadata': benchmark_metadata,
559 'benchmark_name': benchmark_name, 'charts': charts,
560 'format_version': 1.0}
561