1#!/usr/bin/env python3.4 2# 3# Copyright 2018 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the 'License'); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an 'AS IS' BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import os 18import statistics 19import time 20import acts.controllers.iperf_server as ipf 21 22 23class IperfHelper(object): 24 """ Helps with iperf config and processing the results 25 26 This class can be used to process the results of multiple iperf servers 27 (for example, dual traffic scenarios). It also helps in setting the 28 correct arguments for when using the phone as an iperf server 29 """ 30 IPERF_CLIENT_RESULT_FILE_LOC_PHONE = '/sdcard/Download/' 31 32 def __init__(self, config): 33 self.traffic_type = config['traffic_type'] 34 self.traffic_direction = config['traffic_direction'] 35 self.duration = config['duration'] 36 self.port = config['port'] 37 self.server_idx = config['server_idx'] 38 self.use_client_output = False 39 if 'bandwidth' in config: 40 self.bandwidth = config['bandwidth'] 41 else: 42 self.bandwidth = None 43 if 'start_meas_time' in config: 44 self.start_meas_time = config['start_meas_time'] 45 else: 46 self.start_meas_time = 0 47 48 iperf_args = '-i 1 -t {} -p {} -J'.format(self.duration, self.port) 49 50 if self.traffic_type == "UDP": 51 iperf_args = iperf_args + ' -u' 52 if self.traffic_direction == "DL": 53 iperf_args = iperf_args + ' -R' 54 self.use_client_output = True 55 # Set bandwidth in Mbit/s 56 if self.bandwidth is not None: 57 iperf_args = iperf_args + ' -b {}M'.format(self.bandwidth) 58 59 # Set the TCP window size 60 self.window = config.get("window", None) 61 if self.window: 62 iperf_args += ' -w {}M'.format(self.window) 63 64 # Parse the client side data to a file saved on the phone 65 self.results_filename_phone = self.IPERF_CLIENT_RESULT_FILE_LOC_PHONE \ 66 + 'iperf_client_port_{}_{}.log'.format( \ 67 self.port, self.traffic_direction) 68 iperf_args = iperf_args + ' > %s' % self.results_filename_phone 69 70 self.iperf_args = iperf_args 71 72 def process_iperf_results(self, dut, log, iperf_servers, test_name): 73 """Gets the iperf results from the phone and computes the average rate 74 75 Returns: 76 throughput: the average throughput (Mbit/s). 77 """ 78 # Stopping the server (as safety to get the result file) 79 iperf_servers[self.server_idx].stop() 80 time.sleep(1) 81 82 # Get IPERF results and add this to the plot title 83 RESULTS_DESTINATION = os.path.join( 84 iperf_servers[self.server_idx].log_path, 85 'iperf_client_output_{}.log'.format(test_name)) 86 87 PULL_FILE = '{} {}'.format(self.results_filename_phone, 88 RESULTS_DESTINATION) 89 dut.adb.pull(PULL_FILE) 90 91 # Calculate the average throughput 92 if self.use_client_output: 93 iperf_file = RESULTS_DESTINATION 94 else: 95 iperf_file = iperf_servers[self.server_idx].log_files[-1] 96 try: 97 iperf_result = ipf.IPerfResult(iperf_file) 98 99 # Get instantaneous rates after measuring starts 100 samples = iperf_result.instantaneous_rates[self.start_meas_time:-1] 101 102 # Convert values to Mbit/s 103 samples = [rate * 8 * (1.024**2) for rate in samples] 104 105 # compute mean, var and max_dev 106 mean = statistics.mean(samples) 107 var = statistics.variance(samples) 108 max_dev = 0 109 for rate in samples: 110 if abs(rate - mean) > max_dev: 111 max_dev = abs(rate - mean) 112 113 log.info('The average throughput is {}. Variance is {} and max ' 114 'deviation is {}.'.format( 115 round(mean, 2), round(var, 2), round(max_dev, 2))) 116 117 except: 118 log.warning('Cannot get iperf result.') 119 mean = 0 120 121 return mean 122