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. 4 5import logging 6import time 7 8from autotest_lib.client.common_lib import error 9from autotest_lib.client.common_lib import utils 10from autotest_lib.client.common_lib.cros.network import xmlrpc_datatypes 11from autotest_lib.server.cros.network import netperf_runner 12from autotest_lib.server.cros.network import netperf_session 13from autotest_lib.server.cros.network import wifi_cell_test_base 14 15 16class network_WiFi_Perf(wifi_cell_test_base.WiFiCellTestBase): 17 """Test maximal achievable bandwidth on several channels per band. 18 19 Conducts a performance test for a set of specified router configurations 20 and reports results as keyval pairs. 21 22 """ 23 24 version = 1 25 26 NETPERF_CONFIGS = [ 27 netperf_runner.NetperfConfig( 28 netperf_runner.NetperfConfig.TEST_TYPE_TCP_STREAM), 29 netperf_runner.NetperfConfig( 30 netperf_runner.NetperfConfig.TEST_TYPE_TCP_MAERTS), 31 netperf_runner.NetperfConfig( 32 netperf_runner.NetperfConfig.TEST_TYPE_UDP_STREAM), 33 netperf_runner.NetperfConfig( 34 netperf_runner.NetperfConfig.TEST_TYPE_UDP_MAERTS), 35 ] 36 37 38 def parse_additional_arguments(self, commandline_args, additional_params): 39 """Hook into super class to take control files parameters. 40 41 @param commandline_args dict of parsed parameters from the autotest. 42 @param additional_params list of HostapConfig objects. 43 44 """ 45 if 'governor' in commandline_args: 46 self._governor = commandline_args['governor'] 47 # validate governor string. Not all machines will support all of 48 # these governors, but this at least ensures that a potentially 49 # valid governor was passed in 50 if self._governor not in ('performance', 'powersave', 'userspace', 51 'ondemand', 'conservative', 'schedutil'): 52 logging.warning('Unrecognized CPU governor "%s". Running test ' 53 'without setting CPU governor...' % self._governor) 54 self._governor = None 55 else: 56 self._governor = None 57 self._ap_configs = additional_params 58 59 60 def do_run(self, ap_config, session, power_save, governor): 61 """Run a single set of perf tests, for a given AP and DUT config. 62 63 @param ap_config: the AP configuration that is being used 64 @param session: a netperf session instance 65 @param power_save: whether or not to use power-save mode on the DUT 66 (boolean) 67 68 """ 69 def get_current_governor(host): 70 """ 71 @ return the CPU governor name used on a machine. If cannot find 72 the governor info of the host, or if there are multiple 73 different governors being used on different cores, return 74 'default'. 75 """ 76 try: 77 governors = set(utils.get_scaling_governor_states(host)) 78 if len(governors) != 1: 79 return 'default' 80 return next(iter(governors)) 81 except: 82 return 'default' 83 if governor: 84 client_governor = utils.get_scaling_governor_states( 85 self.context.client.host) 86 router_governor = utils.get_scaling_governor_states( 87 self.context.router.host) 88 utils.set_scaling_governors(governor, self.context.client.host) 89 utils.set_scaling_governors(governor, self.context.router.host) 90 governor_name = governor 91 else: 92 # try to get machine's current governor 93 governor_name = get_current_governor(self.context.client.host) 94 if governor_name != get_current_governor(self.context.router.host): 95 governor_name = 'default' 96 if governor_name == self._governor: 97 # If CPU governor is already set to self._governor, don't 98 # perform the run twice 99 return 100 101 self.context.client.powersave_switch(power_save) 102 session.warmup_stations() 103 ps_tag = 'PS%s' % ('on' if power_save else 'off') 104 governor_tag = 'governor-%s' % governor_name 105 ap_config_tag = '_'.join([ap_config.perf_loggable_description, 106 ps_tag, governor_tag]) 107 signal_level = self.context.client.wifi_signal_level 108 signal_description = '_'.join([ap_config_tag, 'signal']) 109 self.write_perf_keyval({signal_description: signal_level}) 110 for config in self.NETPERF_CONFIGS: 111 results = session.run(config) 112 if not results: 113 logging.error('Failed to take measurement for %s', 114 config.tag) 115 continue 116 values = [result.throughput for result in results] 117 self.output_perf_value(config.tag, values, units='Mbps', 118 higher_is_better=True, 119 graph=ap_config_tag) 120 result = netperf_runner.NetperfResult.from_samples(results) 121 self.write_perf_keyval(result.get_keyval( 122 prefix='_'.join([ap_config_tag, config.tag]))) 123 if governor: 124 utils.restore_scaling_governor_states(client_governor, 125 self.context.client.host) 126 utils.restore_scaling_governor_states(router_governor, 127 self.context.router.host) 128 129 130 def run_once(self): 131 """Test body.""" 132 start_time = time.time() 133 for ap_config in self._ap_configs: 134 # Set up the router and associate the client with it. 135 self.context.configure(ap_config) 136 # self.context.configure has a similar check - but that one only 137 # errors out if the AP *requires* VHT i.e. AP is requesting 138 # MODE_11AC_PURE and the client does not support it. 139 # For wifi_perf, we don't want to run MODE_11AC_MIXED on the AP if 140 # the client does not support VHT, as we are guaranteed to get the 141 # same results at 802.11n/HT40 in that case. 142 if ap_config.is_11ac and not self.context.client.is_vht_supported(): 143 raise error.TestNAError('Client does not have AC support') 144 assoc_params = xmlrpc_datatypes.AssociationParameters( 145 ssid=self.context.router.get_ssid(), 146 security_config=ap_config.security_config) 147 self.context.assert_connect_wifi(assoc_params) 148 session = netperf_session.NetperfSession(self.context.client, 149 self.context.router) 150 151 # Flag a test error if we disconnect for any reason. 152 with self.context.client.assert_no_disconnects(): 153 # Conduct the performance tests while toggling powersave mode. 154 for power_save in (True, False): 155 for governor in sorted(set([None, self._governor])): 156 self.do_run(ap_config, session, power_save, governor) 157 158 # Clean up router and client state for the next run. 159 self.context.client.shill.disconnect(self.context.router.get_ssid()) 160 self.context.router.deconfig() 161 end_time = time.time() 162 logging.info('Running time %0.1f seconds.', end_time - start_time) 163