1# Copyright (c) 2009 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 5import logging 6import os 7import re 8import shutil 9import traceback 10from autotest_lib.client.common_lib import error 11from autotest_lib.client.bin import utils 12from autotest_lib.server import test, autotest 13 14 15LOWER_IS_BETTER_METRICS = set(['rdbytes', 'seconds']) 16 17 18class platform_BootPerfServer(test.test): 19 """A test that reboots the client and collect boot perf data.""" 20 version = 1 21 22 23 def upload_perf_keyvals(self, keyvals): 24 """Upload perf keyvals in dictionary |keyvals| to Chrome perf dashboard. 25 26 This method assumes that the key of a perf keyval is in the format 27 of "units_description". The text before the first underscore represents 28 the units and the rest of the text represents 29 a description of the measured perf value. For instance, 30 'seconds_kernel_to_login', 'rdbytes_kernel_to_startup'. 31 32 @param keyvals: A dictionary that maps a perf metric to its value. 33 34 """ 35 for key, val in keyvals.items(): 36 match = re.match(r'^(.+?)_.+$', key) 37 if match: 38 units = match.group(1) 39 higher_is_better = units not in LOWER_IS_BETTER_METRICS 40 self.output_perf_value( 41 description=key, value=val, 42 units=units, higher_is_better=higher_is_better) 43 44 45 def run_once(self, host=None, upload_perf=False): 46 self.client = host 47 self.client_test = 'platform_BootPerf' 48 49 # Run a login test to complete the OOBE flow, if we haven't already. 50 # This is so that we measure boot times for the stable state. 51 try: 52 self.client.run('ls /home/chronos/.oobe_completed') 53 except error.AutoservRunError: 54 logging.info('Taking client through OOBE.') 55 client_at = autotest.Autotest(self.client) 56 client_at.run_test('login_LoginSuccess', disable_sysinfo=True) 57 58 # Reboot the client 59 logging.info('BootPerfServer: reboot %s', self.client.hostname) 60 try: 61 self.client.reboot(reboot_timeout=90) 62 except error.AutoservRebootError as e: 63 raise error.TestFail('%s.\nTest failed with error %s' % ( 64 traceback.format_exc(), str(e))) 65 66 # Collect the performance metrics by running a client side test 67 logging.info('BootPerfServer: start client test') 68 client_at = autotest.Autotest(self.client) 69 client_at.run_test( 70 self.client_test, last_boot_was_reboot=True, disable_sysinfo=True) 71 72 # In the client results directory are a 'keyval' file, and 73 # various raw bootstat data files. First promote the client 74 # test 'keyval' as our own. 75 logging.info('BootPerfServer: gather client results') 76 client_results_dir = os.path.join( 77 self.outputdir, self.client_test, "results") 78 src = os.path.join(client_results_dir, "keyval") 79 dst = os.path.join(self.resultsdir, "keyval") 80 if os.path.exists(src): 81 client_results = open(src, "r") 82 server_results = open(dst, "a") 83 shutil.copyfileobj(client_results, server_results) 84 server_results.close() 85 client_results.close() 86 else: 87 logging.warning('Unable to locate %s', src) 88 89 # Upload perf keyvals in the client keyval file to perf dashboard. 90 if upload_perf: 91 logging.info('Output perf data for iteration %03d', self.iteration) 92 perf_keyvals = utils.read_keyval(src, type_tag='perf') 93 self.upload_perf_keyvals(perf_keyvals) 94 95 # Everything that isn't the client 'keyval' file is raw data 96 # from the client test: move it to a per-iteration 97 # subdirectory. We move instead of copying so we can be sure 98 # we don't have any stale results in the next iteration 99 if self.iteration is not None: 100 rawdata_dir = "rawdata.%03d" % self.iteration 101 else: 102 rawdata_dir = "rawdata" 103 rawdata_dir = os.path.join(self.resultsdir, rawdata_dir) 104 shutil.move(client_results_dir, rawdata_dir) 105 try: 106 os.remove(os.path.join(rawdata_dir, "keyval")) 107 except Exception: 108 pass 109