| # Copyright 2016 Google Inc. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import io |
| import json |
| import logging |
| import os |
| import subprocess |
| |
| from mobly import utils |
| |
| MOBLY_CONTROLLER_CONFIG_NAME = "IPerfServer" |
| |
| |
| def create(configs): |
| results = [] |
| for c in configs: |
| try: |
| results.append(IPerfServer(c, logging.log_path)) |
| except: |
| pass |
| return results |
| |
| |
| def destroy(objs): |
| for ipf in objs: |
| try: |
| ipf.stop() |
| except: |
| pass |
| |
| |
| class IPerfResult: |
| |
| def __init__(self, result_path): |
| try: |
| with io.open(result_path, 'r', encoding='utf-8') as f: |
| self.result = json.load(f) |
| except ValueError: |
| with io.open(result_path, 'r', encoding='utf-8') as f: |
| # Possibly a result from interrupted iperf run, skip first line |
| # and try again. |
| lines = f.readlines()[1:] |
| self.result = json.loads(''.join(lines)) |
| |
| def _has_data(self): |
| """Checks if the iperf result has valid throughput data. |
| |
| Returns: |
| True if the result contains throughput data. False otherwise. |
| """ |
| return ('end' in self.result) and ('sum' in self.result["end"]) |
| |
| def get_json(self): |
| """ |
| Returns: |
| The raw json output from iPerf. |
| """ |
| return self.result |
| |
| @property |
| def error(self): |
| if 'error' not in self.result: |
| return None |
| return self.result['error'] |
| |
| @property |
| def avg_rate(self): |
| """Average receiving rate in MB/s over the entire run. |
| |
| If the result is not from a success run, this property is None. |
| """ |
| if not self._has_data or 'sum' not in self.result['end']: |
| return None |
| bps = self.result['end']['sum']['bits_per_second'] |
| return bps / 8 / 1024 / 1024 |
| |
| @property |
| def avg_receive_rate(self): |
| """Average receiving rate in MB/s over the entire run. This data may |
| not exist if iperf was interrupted. |
| |
| If the result is not from a success run, this property is None. |
| """ |
| if not self._has_data or 'sum_received' not in self.result['end']: |
| return None |
| bps = self.result['end']['sum_received']['bits_per_second'] |
| return bps / 8 / 1024 / 1024 |
| |
| @property |
| def avg_send_rate(self): |
| """Average sending rate in MB/s over the entire run. This data may |
| not exist if iperf was interrupted. |
| |
| If the result is not from a success run, this property is None. |
| """ |
| if not self._has_data or 'sum_sent' not in self.result['end']: |
| return None |
| bps = self.result['end']['sum_sent']['bits_per_second'] |
| return bps / 8 / 1024 / 1024 |
| |
| |
| class IPerfServer(): |
| """Class that handles iperf3 operations. |
| """ |
| |
| def __init__(self, port, log_path): |
| self.port = port |
| self.log_path = os.path.join(log_path, "iPerf{}".format(self.port)) |
| self.iperf_str = "iperf3 -s -J -p {}".format(port) |
| self.iperf_process = None |
| self.log_files = [] |
| self.started = False |
| |
| def start(self, extra_args="", tag=""): |
| """Starts iperf server on specified port. |
| |
| Args: |
| extra_args: A string representing extra arguments to start iperf |
| server with. |
| tag: Appended to log file name to identify logs from different |
| iperf runs. |
| """ |
| if self.started: |
| return |
| utils.create_dir(self.log_path) |
| if tag: |
| tag = tag + ',' |
| out_file_name = "IPerfServer,{},{}{}.log".format(self.port, tag, |
| len(self.log_files)) |
| full_out_path = os.path.join(self.log_path, out_file_name) |
| cmd = '%s %s > %s' % (self.iperf_str, extra_args, full_out_path) |
| self.iperf_process = utils.start_standing_subprocess(cmd, shell=True) |
| self.log_files.append(full_out_path) |
| self.started = True |
| |
| def stop(self): |
| if self.started: |
| utils.stop_standing_subprocess(self.iperf_process) |
| self.started = False |