1# 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. 4import logging 5import re 6import os 7import StringIO 8 9import common 10from autotest_lib.client.common_lib import error 11from autotest_lib.server import test 12from autotest_lib.server import utils 13from autotest_lib.site_utils import test_runner_utils 14from autotest_lib.server.cros import telemetry_runner 15 16 17TELEMETRY_TIMEOUT_MINS = 60 18CHROME_SRC_ROOT = '/var/cache/chromeos-cache/distfiles/target/' 19CLIENT_CHROME_ROOT = '/usr/local/telemetry/src' 20RUN_BENCHMARK = 'tools/perf/run_benchmark' 21 22RSA_KEY = '-i %s' % test_runner_utils.TEST_KEY_PATH 23DUT_CHROME_RESULTS_DIR = '/usr/local/telemetry/src/tools/perf' 24 25# Result Statuses 26SUCCESS_STATUS = 'SUCCESS' 27WARNING_STATUS = 'WARNING' 28FAILED_STATUS = 'FAILED' 29 30# Regex for the RESULT output lines understood by chrome buildbot. 31# Keep in sync with 32# chromium/tools/build/scripts/slave/performance_log_processor.py. 33RESULTS_REGEX = re.compile(r'(?P<IMPORTANT>\*)?RESULT ' 34 r'(?P<GRAPH>[^:]*): (?P<TRACE>[^=]*)= ' 35 r'(?P<VALUE>[\{\[]?[-\d\., ]+[\}\]]?)(' 36 r' ?(?P<UNITS>.+))?') 37HISTOGRAM_REGEX = re.compile(r'(?P<IMPORTANT>\*)?HISTOGRAM ' 38 r'(?P<GRAPH>[^:]*): (?P<TRACE>[^=]*)= ' 39 r'(?P<VALUE_JSON>{.*})(?P<UNITS>.+)?') 40 41 42def _find_chrome_root_dir(): 43 # Look for chrome source root, either externally mounted, or inside 44 # the chroot. Prefer chrome-src-internal source tree to chrome-src. 45 sources_list = ('chrome-src-internal', 'chrome-src') 46 47 dir_list = [os.path.join(CHROME_SRC_ROOT, x) for x in sources_list] 48 if 'CHROME_ROOT' in os.environ: 49 dir_list.insert(0, os.environ['CHROME_ROOT']) 50 51 for dir in dir_list: 52 if os.path.exists(dir): 53 chrome_root_dir = dir 54 break 55 else: 56 raise error.TestError('Chrome source directory not found.') 57 58 logging.info('Using Chrome source tree at %s', chrome_root_dir) 59 return os.path.join(chrome_root_dir, 'src') 60 61 62def _ensure_deps(dut, test_name): 63 """ 64 Ensure the dependencies are locally available on DUT. 65 66 @param dut: The autotest host object representing DUT. 67 @param test_name: Name of the telemetry test. 68 """ 69 # Get DEPs using host's telemetry. 70 chrome_root_dir = _find_chrome_root_dir() 71 format_string = ('python %s/tools/perf/fetch_benchmark_deps.py %s') 72 command = format_string % (chrome_root_dir, test_name) 73 logging.info('Getting DEPs: %s', command) 74 stdout = StringIO.StringIO() 75 stderr = StringIO.StringIO() 76 try: 77 result = utils.run(command, stdout_tee=stdout, 78 stderr_tee=stderr) 79 except error.CmdError as e: 80 logging.debug('Error occurred getting DEPs: %s\n %s\n', 81 stdout.getvalue(), stderr.getvalue()) 82 raise error.TestFail('Error occurred while getting DEPs.') 83 84 # Download DEPs to DUT. 85 # send_file() relies on rsync over ssh. Couldn't be better. 86 stdout_str = stdout.getvalue() 87 stdout.close() 88 stderr.close() 89 for dep in stdout_str.split(): 90 src = os.path.join(chrome_root_dir, dep) 91 dst = os.path.join(CLIENT_CHROME_ROOT, dep) 92 if not os.path.isfile(src): 93 raise error.TestFail('Error occurred while saving DEPs.') 94 logging.info('Copying: %s -> %s', src, dst) 95 try: 96 dut.send_file(src, dst) 97 except: 98 raise error.TestFail('Error occurred while sending DEPs to dut.\n') 99 100 101class telemetry_Crosperf(test.test): 102 """Run one or more telemetry benchmarks under the crosperf script.""" 103 version = 1 104 105 def scp_telemetry_results(self, client_ip, dut): 106 """Copy telemetry results from dut. 107 108 @param client_ip: The ip address of the DUT 109 @param dut: The autotest host object representing DUT. 110 111 @returns status code for scp command. 112 """ 113 cmd=[] 114 src = ('root@%s:%s/results-chart.json' % 115 (dut.hostname if dut else client_ip, DUT_CHROME_RESULTS_DIR)) 116 cmd.extend(['scp', telemetry_runner.DUT_SCP_OPTIONS, RSA_KEY, '-v', 117 src, self.resultsdir]) 118 command = ' '.join(cmd) 119 120 logging.debug('Retrieving Results: %s', command) 121 try: 122 result = utils.run(command, 123 timeout=TELEMETRY_TIMEOUT_MINS * 60) 124 exit_code = result.exit_status 125 except Exception as e: 126 logging.error('Failed to retrieve results: %s', e) 127 raise 128 129 logging.debug('command return value: %d', exit_code) 130 return exit_code 131 132 def run_once(self, args, client_ip='', dut=None): 133 """ 134 Run a single telemetry test. 135 136 @param args: A dictionary of the arguments that were passed 137 to this test. 138 @param client_ip: The ip address of the DUT 139 @param dut: The autotest host object representing DUT. 140 141 @returns A TelemetryResult instance with the results of this execution. 142 """ 143 test_name = args['test'] 144 test_args = '' 145 if 'test_args' in args: 146 test_args = args['test_args'] 147 148 # Decide whether the test will run locally or by a remote server. 149 if args.get('run_local', 'false').lower() == 'true': 150 # The telemetry scripts will run on DUT. 151 _ensure_deps(dut, test_name) 152 format_string = ('python %s --browser=system ' 153 '--output-format=chartjson %s %s') 154 command = format_string % (os.path.join(CLIENT_CHROME_ROOT, 155 RUN_BENCHMARK), 156 test_args, test_name) 157 runner = dut 158 else: 159 # The telemetry scripts will run on server. 160 format_string = ('python %s --browser=cros-chrome --remote=%s ' 161 '--output-format=chartjson %s %s') 162 command = format_string % (os.path.join(_find_chrome_root_dir(), 163 RUN_BENCHMARK), 164 client_ip, test_args, test_name) 165 runner = utils 166 167 # Run the test. 168 stdout = StringIO.StringIO() 169 stderr = StringIO.StringIO() 170 try: 171 logging.info('CMD: %s', command) 172 result = runner.run(command, stdout_tee=stdout, stderr_tee=stderr, 173 timeout=TELEMETRY_TIMEOUT_MINS*60) 174 exit_code = result.exit_status 175 except error.CmdError as e: 176 logging.debug('Error occurred executing telemetry.') 177 exit_code = e.result_obj.exit_status 178 raise error.TestFail('An error occurred while executing ' 179 'telemetry test.') 180 finally: 181 stdout_str = stdout.getvalue() 182 stderr_str = stderr.getvalue() 183 stdout.close() 184 stderr.close() 185 logging.info('Telemetry completed with exit code: %d.' 186 '\nstdout:%s\nstderr:%s', exit_code, 187 stdout_str, stderr_str) 188 189 # Copy the results-chart.json file into the test_that results 190 # directory. 191 if args.get('run_local', 'false').lower() == 'true': 192 result = self.scp_telemetry_results(client_ip, dut) 193 else: 194 src_dir = os.path.dirname(os.path.join(_find_chrome_root_dir(), 195 RUN_BENCHMARK)) 196 197 filepath = os.path.join(src_dir, 'results-chart.json') 198 if os.path.exists(filepath): 199 command = 'cp %s %s' % (filepath, self.resultsdir) 200 result = utils.run(command) 201 else: 202 raise IOError('Missing results file: %s' % filepath) 203 204 205 return result 206