a324c5b85d3c311893f7ca07e8c9cbf816bde00c
[yardstick.git] / yardstick / benchmark / scenarios / networking / iperf3.py
1 ##############################################################################
2 # Copyright (c) 2015 Ericsson AB and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10 # iperf3 scenario
11 # iperf3 homepage at: http://software.es.net/iperf/
12
13 import logging
14 import json
15 import pkg_resources
16
17 import yardstick.ssh as ssh
18 from yardstick.benchmark.scenarios import base
19
20 LOG = logging.getLogger(__name__)
21
22
23 class Iperf(base.Scenario):
24     """Execute iperf3 between two hosts
25
26 By default TCP is used but UDP can also be configured.
27 For more info see http://software.es.net/iperf
28
29   Parameters
30     bytes - number of bytes to transmit
31       only valid with a non duration runner, mutually exclusive with blockcount
32         type:    int
33         unit:    bytes
34         default: 56
35     udp - use UDP rather than TCP
36         type:    bool
37         unit:    na
38         default: false
39     nodelay - set TCP no delay, disabling Nagle's Algorithm
40         type:    bool
41         unit:    na
42         default: false
43     blockcount - number of blocks (packets) to transmit,
44       only valid with a non duration runner, mutually exclusive with bytes
45         type:    int
46         unit:    bytes
47         default: -
48     """
49     __scenario_type__ = "Iperf3"
50
51     def __init__(self, context):
52         self.context = context
53         self.user = context.get('user', 'ubuntu')
54         self.host_ipaddr = context['host']
55         self.target_ipaddr = context['target']
56         self.key_filename = self.context.get('key_filename', '~/.ssh/id_rsa')
57         self.setup_done = False
58
59     def setup(self):
60         LOG.debug("setup, key %s", self.key_filename)
61         LOG.info("host:%s, user:%s", self.host_ipaddr, self.user)
62         self.host = ssh.SSH(self.user, self.host_ipaddr,
63                             key_filename=self.key_filename)
64         self.host.wait(timeout=600)
65
66         LOG.info("target:%s, user:%s", self.target_ipaddr, self.user)
67         self.target = ssh.SSH(self.user, self.target_ipaddr,
68                               key_filename=self.key_filename)
69         self.target.wait(timeout=600)
70
71         cmd = "iperf3 -s -D"
72         LOG.debug("Starting iperf3 server with command: %s", cmd)
73         status, _, stderr = self.target.execute(cmd)
74         if status:
75             raise RuntimeError(stderr)
76
77     def teardown(self):
78         LOG.debug("teardown")
79         self.host.close()
80         status, stdout, stderr = self.target.execute("pkill iperf3")
81         if status:
82             LOG.warn(stderr)
83         self.target.close()
84
85     def run(self, args, result):
86         """execute the benchmark"""
87
88         # if run by a duration runner, get the duration time and setup as arg
89         time = self.context.get('duration', None)
90         options = args['options']
91
92         cmd = "iperf3 -c %s --json" % (self.target_ipaddr)
93
94         # If there are no options specified
95         if not options:
96             options = ""
97
98         use_UDP = False
99         if "udp" in options:
100             cmd += " --udp"
101             use_UDP = True
102             if "bandwidth" in options:
103                 cmd += " --bandwidth %s" % options["bandwidth"]
104         else:
105             # tcp obviously
106             if "nodelay" in options:
107                 cmd += " --nodelay"
108
109         # these options are mutually exclusive in iperf3
110         if time:
111             cmd += " %d" % time
112         elif "bytes" in options:
113             # number of bytes to transmit (instead of --time)
114             cmd += " --bytes %d" % options["bytes"]
115         elif "blockcount" in options:
116             cmd += " --blockcount %d" % options["blockcount"]
117
118         LOG.debug("Executing command: %s", cmd)
119
120         status, stdout, stderr = self.host.execute(cmd)
121         if status:
122             # error cause in json dict on stdout
123             raise RuntimeError(stdout)
124
125         result.update(json.loads(stdout))
126
127         if "sla" in args:
128             sla_iperf = args["sla"]
129             if not use_UDP:
130                 sla_bytes_per_second = int(sla_iperf["bytes_per_second"])
131
132                 # convert bits per second to bytes per second
133                 bit_per_second = \
134                     int(result["end"]["sum_received"]["bits_per_second"])
135                 bytes_per_second = bit_per_second / 8
136                 assert bytes_per_second >= sla_bytes_per_second, \
137                     "bytes_per_second %d < sla:bytes_per_second (%d); " % \
138                     (bytes_per_second, sla_bytes_per_second)
139             else:
140                 sla_jitter = float(sla_iperf["jitter"])
141
142                 jitter_ms = float(result["end"]["sum"]["jitter_ms"])
143                 assert jitter_ms <= sla_jitter, \
144                     "jitter_ms  %f > sla:jitter %f; " % \
145                     (jitter_ms, sla_jitter)
146
147
148 def _test():
149     '''internal test function'''
150
151     logger = logging.getLogger('yardstick')
152     logger.setLevel(logging.DEBUG)
153
154     key_filename = pkg_resources.resource_filename('yardstick.resources',
155                                                    'files/yardstick_key')
156     runner_cfg = {}
157     runner_cfg['type'] = 'Duration'
158     runner_cfg['duration'] = 5
159     runner_cfg['host'] = '10.0.2.33'
160     runner_cfg['target_ipaddr'] = '10.0.2.53'
161     runner_cfg['user'] = 'ubuntu'
162     runner_cfg['output_filename'] = "/tmp/yardstick.out"
163     runner_cfg['key_filename'] = key_filename
164
165     scenario_args = {}
166     scenario_args['options'] = {"bytes": 10000000000}
167     scenario_args['sla'] = \
168         {"bytes_per_second": 2900000000, "action": "monitor"}
169
170     from yardstick.benchmark.runners import base as base_runner
171     runner = base_runner.Runner.get(runner_cfg)
172     runner.run("Iperf3", scenario_args)
173     runner.join()
174     base_runner.Runner.release(runner)
175
176 if __name__ == '__main__':
177     _test()