summaryrefslogtreecommitdiffstats
path: root/vstf/vstf/agent/perf
diff options
context:
space:
mode:
authorYiting.Li <liyiting@huawei.com>2015-12-22 17:11:12 -0800
committerYiting.Li <liyiting@huawei.com>2015-12-22 17:11:12 -0800
commit8f1101df131a4d3e03b377738507d88b745831c0 (patch)
tree73f140474fcec2a77c85a453f6946957ca0742d1 /vstf/vstf/agent/perf
parent1a24ebbda3f95600c0e7d5ed8661317a8ff7e265 (diff)
Upload the contribution of vstf as bottleneck network framework.
End to End Performance test JIRA:BOTTLENECK-29 Change-Id: Ib2c553c8b60d6cda9e7a7b52b737c9139f706ebd Signed-off-by: Yiting.Li <liyiting@huawei.com>
Diffstat (limited to 'vstf/vstf/agent/perf')
-rwxr-xr-xvstf/vstf/agent/perf/__init__.py14
-rwxr-xr-xvstf/vstf/agent/perf/affctl.py18
-rwxr-xr-xvstf/vstf/agent/perf/ethtool.py56
-rwxr-xr-xvstf/vstf/agent/perf/iperf.py152
-rwxr-xr-xvstf/vstf/agent/perf/netmap.py166
-rwxr-xr-xvstf/vstf/agent/perf/netns.py103
-rwxr-xr-xvstf/vstf/agent/perf/netperf.py177
-rwxr-xr-xvstf/vstf/agent/perf/pktgen.py149
-rwxr-xr-xvstf/vstf/agent/perf/qperf.py164
-rwxr-xr-xvstf/vstf/agent/perf/sar.py78
-rwxr-xr-xvstf/vstf/agent/perf/utils.py42
-rwxr-xr-xvstf/vstf/agent/perf/vnstat.py106
-rwxr-xr-xvstf/vstf/agent/perf/vstfperf.py105
13 files changed, 1330 insertions, 0 deletions
diff --git a/vstf/vstf/agent/perf/__init__.py b/vstf/vstf/agent/perf/__init__.py
new file mode 100755
index 00000000..89dcd4e2
--- /dev/null
+++ b/vstf/vstf/agent/perf/__init__.py
@@ -0,0 +1,14 @@
+# Copyright Huawei Technologies Co., Ltd. 1998-2015.
+# All Rights Reserved.
+#
+# 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.
diff --git a/vstf/vstf/agent/perf/affctl.py b/vstf/vstf/agent/perf/affctl.py
new file mode 100755
index 00000000..e9b96924
--- /dev/null
+++ b/vstf/vstf/agent/perf/affctl.py
@@ -0,0 +1,18 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+# author: wly
+# date: 2015/11/26
+# see license for license details
+
+from vstf.common.utils import check_call, call, check_output
+
+
+def affctl_load(policy):
+ cmd = "affctl load %s" % policy
+ return check_call(cmd, shell=True)
+
+
+def affctl_list():
+ cmd = "affctl list"
+ return check_output(cmd, shell=True)
+
diff --git a/vstf/vstf/agent/perf/ethtool.py b/vstf/vstf/agent/perf/ethtool.py
new file mode 100755
index 00000000..c214a568
--- /dev/null
+++ b/vstf/vstf/agent/perf/ethtool.py
@@ -0,0 +1,56 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+# author: wly
+# date: 2015/11/12
+# see license for license details
+
+import vstf.common.utils as utils
+
+__all__ = ["autoneg_on", "autoneg_off", "autoneg_query"]
+
+_para_map = {
+ "Autonegotiate": ("-A", "-a", "autoneg"),
+ "RX": ("-A", "-a", "rx"),
+ "TX": ("-A", "-a", "tx"),
+}
+
+
+def autoneg_on(iface, nspace=None):
+ return _set(nspace, iface, Autonegotiate="on", RX="on", TX="on")
+
+
+def autoneg_off(iface, nspace=None):
+ return _set(nspace, iface, Autonegotiate="off", RX="off", TX="off")
+
+
+def autoneg_query(iface, nspace=None):
+ return _query(nspace, iface, "-a")
+
+
+def _set(nspace, iface, **kwargs):
+ cmds = {}
+ for item, value in kwargs.items():
+ opt, _, key = _para_map[item]
+ cmds.setdefault(opt, [])
+ cmds[opt].append(key)
+ cmds[opt].append(value)
+
+ for key, value in cmds.items():
+ cmd = _namespace(nspace)
+ cmd += ["ethtool", key, iface] + value
+ utils.call(cmd)
+
+ return True
+
+
+def _query(nspace, iface, item):
+ cmd = _namespace(nspace)
+ cmd += ["ethtool", item, iface]
+ return utils.check_output(cmd)
+
+
+def _namespace(nspace):
+ result = ""
+ if nspace:
+ result = "ip netns exec %(namespace)s " % {"namespace": nspace}
+ return result.split()
diff --git a/vstf/vstf/agent/perf/iperf.py b/vstf/vstf/agent/perf/iperf.py
new file mode 100755
index 00000000..25728b7e
--- /dev/null
+++ b/vstf/vstf/agent/perf/iperf.py
@@ -0,0 +1,152 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+# author:
+# date: 2015-09-15
+# see license for license details
+
+import subprocess
+import signal
+import os
+import time
+import logging
+
+import vstf.common.decorator as deco
+import vstf.agent.perf.utils as utils
+from vstf.common.utils import kill_by_name
+
+LOG = logging.getLogger(__name__)
+
+
+class Iperf(object):
+ def __init__(self):
+ self._send_processes = []
+ self._receive_processes = []
+ self._typemap = {
+ "tcp_bw": "",
+ "udp_bw": " -u ",
+ }
+
+ @deco.check("protocol", choices=['tcp_bw', 'udp_bw'])
+ @deco.check("namespace", defaults=None)
+ @deco.check("dst")
+ @deco.check("time", defaults=600)
+ @deco.check("size", defaults=64)
+ @deco.check("threads", defaults=1)
+ def send_start(self, **kwargs):
+
+ cmd = self.format_send_start(**kwargs)
+ LOG.debug("cmd:%s", cmd)
+
+ process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ time.sleep(1)
+ ret = process.poll()
+ if ret is None:
+ ret = 0
+ error_str = "start iperf send success"
+ self._send_processes.append(process)
+ else:
+ print ret
+ error_str = "start iperf send failed, %s", (str(kwargs))
+
+ return ret, error_str
+
+ @deco.namespace()
+ def format_send_start(self, **kwargs):
+ cmd = "iperf %(type)s -c %(dst_ip)s -i 1 -l %(pkt_size)s -t %(time)s -P %(threads)s "
+ context = {
+ 'type': self._typemap[kwargs['protocol']],
+ 'dst_ip': kwargs['dst'][0]['ip'],
+ 'time': kwargs['time'],
+ 'pkt_size': kwargs['size'],
+ 'threads': kwargs['threads'],
+ }
+ cmd = cmd % context
+ return cmd
+
+ def send_stop(self):
+ results = []
+ for process in self._send_processes:
+ poll = process.poll()
+ if poll is None:
+ process.kill()
+ ret = 0
+ read = "process is stopped by killed"
+ results.append((ret, read))
+
+ self._send_processes = []
+ return results
+
+ @deco.namespace()
+ def format_receive_start(self, **kwargs):
+ cmd = 'iperf %s -s ' % (self._typemap[kwargs['protocol']])
+ return cmd
+
+ @deco.check("protocol", choices=['tcp_bw', 'udp_bw'])
+ @deco.check("namespace", defaults=None)
+ def receive_start(self, **kwargs):
+ cmd = self.format_receive_start(**kwargs)
+ LOG.debug("cmd:%s", cmd)
+
+ process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ time.sleep(1)
+ ret = process.poll()
+ if ret is None:
+ ret = 0
+ error_str = "start iperf receive success"
+ self._receive_processes.append(process)
+ else:
+ print ret
+ error_str = "start iperf receive failed, %s" % (str(kwargs))
+ return ret, error_str
+
+ def receive_stop(self):
+ ret = 0
+ for process in self._receive_processes:
+ process.kill()
+ ret = process.wait()
+ self._receive_processes = []
+ return ret
+
+ def receive_kill(self):
+ ret = 0
+ receive_pids = utils.get_pid_by_name('iperf')
+ for pid in receive_pids:
+ os.kill(pid, signal.SIGKILL)
+ time.sleep(0.5)
+ error_str = "stop iperf receive success"
+ LOG.debug(error_str)
+ return ret, error_str
+
+ def force_clean(self):
+ LOG.info("%s %s start", self.__class__, self.force_clean.__name__)
+ kill_by_name('iperf')
+ self._send_processes = []
+ self._receive_processes = []
+ return True
+
+
+def unit_test():
+ perf = Iperf()
+ pro = 'udp_bw'
+ print perf.receive_start(namespace='receive', protocol=pro)
+
+ send = {
+ "namespace": "send",
+ "protocol": "udp_bw",
+ "dst": [
+ {"ip": "192.168.1.102"}
+ ],
+ "size": 64,
+ "time": 5,
+ }
+ print perf.send_start(**send)
+ time.sleep(10)
+ print perf.send_stop()
+ print perf.receive_stop()
+
+
+if __name__ == "__main__":
+ from vstf.common.log import setup_logging
+
+ setup_logging(level=logging.DEBUG, log_file="/var/log/vstf-iperf.log", clevel=logging.DEBUG)
+ unit_test()
diff --git a/vstf/vstf/agent/perf/netmap.py b/vstf/vstf/agent/perf/netmap.py
new file mode 100755
index 00000000..c61d2577
--- /dev/null
+++ b/vstf/vstf/agent/perf/netmap.py
@@ -0,0 +1,166 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+# author: wly
+# date: 2015-11-09
+# see license for license details
+
+
+import time
+import subprocess
+import vstf.common.decorator as deco
+from vstf.common.utils import kill_by_name, my_popen
+
+import logging
+
+LOG = logging.getLogger(__name__)
+
+
+class Netmap(object):
+ def __init__(self):
+ self._send_processes = []
+ self._receive_processes = []
+
+ @deco.check("protocol", choices=['udp_bw'], defaults='udp_bw')
+ @deco.check("namespace", defaults=None)
+ @deco.check("dst")
+ @deco.check("src")
+ @deco.check("size", defaults=64)
+ @deco.check("threads", defaults=1)
+ @deco.check("ratep", defaults=0)
+ def send_start(self, **kwargs):
+ cmd = self.format_send_start(**kwargs)
+ LOG.info("cmd:%s", cmd)
+
+ process = my_popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ self._send_processes.append(process)
+ time.sleep(0.5)
+
+ ret = process.poll()
+ if ret is None:
+ ret = 0
+ error_str = "start netmap send success"
+ else:
+ error_str = "start netmap send failed, %s" % (str(kwargs))
+ process.wait()
+ self._send_processes.remove(process)
+
+ return ret, error_str
+
+ def send_stop(self, **kwargs):
+ LOG.info("send_stop")
+ results = []
+ ret = 0
+ for process in self._send_processes:
+ process.kill()
+ process.wait()
+ error_str = "stop netmap send success"
+ results.append((ret, error_str))
+ self._send_processes = []
+ return results
+
+ def format_send_start(self, **kwargs):
+ cmd = "pkt-gen -i %(src_iface)s -f tx -l %(pkt_size)s -p %(threads)s -D %(dst_mac)s -R %(ratep)s"
+ context = {
+ 'src_iface': kwargs['src'][0]['iface'],
+ 'dst_mac': kwargs['dst'][0]['mac'],
+ 'pkt_size': kwargs['size'],
+ 'threads': kwargs['threads'],
+ 'ratep': kwargs['ratep']
+ }
+ cmd = cmd % context
+ return cmd
+
+ @deco.namespace()
+ def format_receive_start(self, **kwargs):
+ cmd = "pkt-gen -i %(iface)s -f rx"
+ context = {
+ 'iface': kwargs['dst'][0]['iface']
+ }
+ cmd = cmd % context
+ return cmd
+
+ @deco.check("protocol", choices=['udp_bw'], defaults='udp_bw')
+ @deco.check("namespace", defaults=None)
+ @deco.check("dst")
+ def receive_start(self, **kwargs):
+
+ cmd = self.format_receive_start(**kwargs)
+ LOG.info("cmd:%s", cmd)
+
+ process = my_popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ self._receive_processes.append(process)
+ time.sleep(0.5)
+
+ ret = process.poll()
+ if ret is None:
+ ret = 0
+ error_str = "start netmap receive success"
+ else:
+ error_str = "start netmap receive failed, %s" % (str(kwargs))
+ process.wait()
+ self._receive_processes.remove(process)
+
+ return ret, error_str
+
+ def receive_stop(self, **kwargs):
+ LOG.info("receive_stop")
+ ret = 0
+ for process in self._receive_processes:
+ process.kill()
+ process.wait()
+ self._receive_processes = []
+ error_str = "stop netmap receive success"
+ self._receive_processes = []
+ return ret, error_str
+
+ def clean(self):
+ self.send_stop()
+ self.receive_stop()
+ return True
+
+ def force_clean(self):
+ LOG.info("%s %s start", self.__class__, self.force_clean.__name__)
+ kill_by_name('pkt-gen')
+ self._send_processes = []
+ self._receive_processes = []
+ return True
+
+
+def unit_test():
+ perf = Netmap()
+ receive = {
+ "protocol": "udp_bw",
+ # "namespace": "receive",
+ "dst": [
+ {"iface": "p57p2"}
+ ],
+ }
+ ret = perf.receive_start(**receive)
+ LOG.info("*********receive_start***********")
+ LOG.info("ret")
+ send = {
+ # "namespace": "send",
+ "protocol": "udp_bw",
+ "src": [
+ {"iface": "eth4", "mac": "90:e2:ba:20:1f:d8"}
+ ],
+ "dst": [
+ {"mac": "90:e2:ba:20:1f:d9"}
+ ],
+ "size": 64,
+ "threads": 1,
+ "ratep": 0
+ }
+ print perf.send_start(**send)
+ print perf._send_processes
+ time.sleep(10)
+
+ print perf.send_stop()
+ print perf.receive_stop()
+
+
+if __name__ == "__main__":
+ from vstf.common.log import setup_logging
+
+ setup_logging(level=logging.DEBUG, log_file="/var/log/vstf/vstf-netmap.log", clevel=logging.INFO)
+ unit_test()
diff --git a/vstf/vstf/agent/perf/netns.py b/vstf/vstf/agent/perf/netns.py
new file mode 100755
index 00000000..d5552fa2
--- /dev/null
+++ b/vstf/vstf/agent/perf/netns.py
@@ -0,0 +1,103 @@
+"""
+Created on 2015-8-6
+
+@author: y00228926
+"""
+import logging
+from vstf.common.utils import IPCommandHelper
+from vstf.agent.perf import ethtool
+from vstf.common.utils import check_call, check_output, ns_cmd, my_popen, my_sleep
+
+LOG = logging.getLogger(__name__)
+
+
+class Netns(object):
+ def __init__(self):
+ super(Netns, self).__init__()
+ self.netns_add_str = "ip netns add %s"
+ self.netns_del_str = " ip netns del %s"
+ self.netns_add_device_str = " ip link set %s netns %s"
+ self.set_link_up_str = "ip link set dev %s up"
+ self.set_link_addr_str = "ip addr replace %s dev %s"
+ self.netns_remove_device_str = "ip netns exec %s ip link set %s netns 1"
+ # self.set_link_addr_str = "ifconfig %s %s up"
+ self.ns_devices = {}
+
+ def clean_all_namespace(self):
+ out = check_output("ip netns list", shell=True)
+ for ns in out.splitlines():
+ self.remove_namespace(ns)
+ return True
+
+ def create_namespace(self, name):
+ if name in (None, 'None', 'none'):
+ return True
+ cmd = self.netns_add_str % name
+ check_call(cmd, shell=True)
+ return True
+
+ def remove_namespace(self, ns):
+ if ns in (None, 'None', 'none'):
+ return True
+ ip_helper = IPCommandHelper(ns)
+ for dev in ip_helper.device_mac_map:
+ cmd = self.netns_remove_device_str % (ns, dev)
+ check_call(cmd, shell=True)
+ self.activate_device(None, dev)
+ cmd = self.netns_del_str % ns
+ check_call(cmd, shell=True)
+ return True
+
+ def add_device(self, ns, device):
+ if ns is None:
+ return True
+ cmd = self.netns_add_device_str % (device, ns)
+ check_call(cmd, shell=True)
+ return True
+
+ def config_ip(self, ns, device, ip):
+ self.activate_device(ns, device)
+ cmd = self.set_link_addr_str % (ip, device)
+ cmd = ns_cmd(ns, cmd)
+ check_call(cmd, shell=True)
+ return True
+
+ def activate_device(self, ns, device):
+ cmd = self.set_link_up_str % device
+ cmd = ns_cmd(ns, cmd)
+ check_call(cmd, shell=True)
+ return True
+
+
+class NetnsManager(object):
+ def __init__(self):
+ super(NetnsManager, self).__init__()
+ self._netns = Netns()
+
+ def config_dev(self, netdev):
+ ns, device, ip = netdev["namespace"], netdev["iface"], netdev['ip_setting'] if "ip_setting" in netdev else \
+ netdev['ip']
+ self._netns.create_namespace(ns)
+ self._netns.add_device(ns, device)
+ self._netns.config_ip(ns, device, ip)
+ my_sleep(1)
+ ethtool.autoneg_off(device, ns)
+ return True
+
+ def recover_dev(self, netdev):
+ ns = netdev["namespace"]
+ return self._netns.remove_namespace(ns)
+
+ def clean_all_namespace(self):
+ return self._netns.clean_all_namespace()
+
+ @staticmethod
+ def ping(ns, ip):
+ cmd = "ping -w2 -c1 %s" % ip
+ cmd = ns_cmd(ns, cmd)
+ child = my_popen(cmd, shell=True)
+ return 0 == child.wait()
+
+
+if __name__ == '__main__':
+ logging.basicConfig(level=logging.DEBUG)
diff --git a/vstf/vstf/agent/perf/netperf.py b/vstf/vstf/agent/perf/netperf.py
new file mode 100755
index 00000000..fab1fc11
--- /dev/null
+++ b/vstf/vstf/agent/perf/netperf.py
@@ -0,0 +1,177 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+# author:
+# date: 2015-09-15
+# see license for license details
+import time
+import subprocess
+import vstf.common.constants as cst
+import vstf.common.decorator as deco
+from vstf.common import perfmark as mark
+from vstf.common.utils import kill_by_name, my_popen
+
+import logging
+
+LOG = logging.getLogger(__name__)
+
+
+class Netperf(object):
+ def __init__(self):
+ self._send_processes = []
+ self._islat = False
+ self._typemap = {
+ "tcp_lat": "TCP_STREAM",
+ "tcp_bw": "TCP_STREAM",
+ "udp_lat": "UDP_STREAM",
+ "udp_bw": "UDP_STREAM",
+ }
+
+ @deco.check("protocol", choices=cst.PROTOCOLS)
+ @deco.check("namespace", defaults=None)
+ @deco.check("dst")
+ @deco.check("time", defaults=0)
+ @deco.check("size", defaults=64)
+ @deco.check("threads", defaults=1)
+ def send_start(self, **kwargs):
+ threads = kwargs.pop('threads')
+ kwargs['buf'] = cst.SOCKET_BUF
+ if kwargs['protocol'] in ['tcp_lat', 'udp_lat']:
+ self._islat = True
+ else:
+ kwargs['time'] = 0
+
+ cmd = self.format_send_start(**kwargs)
+ LOG.info("cmd:%s", cmd)
+
+ for _ in range(threads):
+ process = my_popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ self._send_processes.append(process)
+ time.sleep(0.5)
+ for process in self._send_processes:
+ ret = process.poll()
+ if ret is None:
+ ret = 0
+ error_str = "start netperf send success"
+ else:
+ error_str = "start netperf send failed, %s" % (str(kwargs))
+ process.wait()
+ self._send_processes.remove(process)
+
+ return ret, error_str
+
+ def send_stop(self, **kwargs):
+ LOG.info("send_stop")
+ results = []
+ ret = 0
+ for process in self._send_processes:
+ poll = process.poll()
+ if poll is None:
+ if not self._islat:
+ process.kill()
+ read = "process is stopped by killed"
+ else:
+ ret = process.wait()
+ read = process.stdout.read()
+ read = self._parse_data(read)
+ results.append((ret, read))
+ self._send_processes = []
+ self._islat = False
+ return results
+
+ @staticmethod
+ def _parse_data(data):
+ buf = data.splitlines()
+ data = buf[2].strip().split(',')
+ result = {
+ mark.minLatency: float(data[0]),
+ mark.avgLatency: float(data[1]),
+ mark.maxLatency: float(data[2])
+ }
+ return result
+
+ @deco.namespace()
+ def format_send_start(self, **kwargs):
+ # cmd = "netperf -H %(dst_ip)s -t %(type)s -l %(time)s -- -m %(pkt_size)s "
+ cmd = "netperf -H %(dst_ip)s -t %(type)s -l %(time)s " \
+ "-- -m %(pkt_size)s -s %(buf)s -S %(buf)s -o MIN_LATENCY,MEAN_LATENCY,MAX_LATENCY"
+ context = {
+ 'dst_ip': kwargs['dst'][0]['ip'],
+ 'type': self._typemap[kwargs['protocol']],
+ 'time': kwargs['time'],
+ 'pkt_size': kwargs['size'],
+ 'buf': kwargs['buf'],
+ }
+ cmd = cmd % context
+ return cmd
+
+ @deco.namespace()
+ def format_receive_start(self, **kwargs):
+ cmd = 'netserver'
+ return cmd
+
+ @deco.check("namespace")
+ def receive_start(self, **kwargs):
+
+ cmd = self.format_receive_start(**kwargs)
+ LOG.info("cmd:%s", cmd)
+
+ process = my_popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ time.sleep(0.5)
+ ret = process.poll()
+ if ret:
+ error_str = "start netserver failed, %s" % (str(kwargs))
+ else:
+ ret = 0
+ error_str = "start netserver success"
+
+ return ret, error_str
+
+ def receive_stop(self, **kwargs):
+ LOG.info("receive_stop")
+ ret = 0
+ kill_by_name('netserver')
+ time.sleep(0.5)
+ error_str = "stop netserver success"
+ return ret, error_str
+
+ def clean(self):
+ self.send_stop()
+ self.receive_stop()
+ return True
+
+ def force_clean(self):
+ LOG.info("%s %s start", self.__class__, self.force_clean.__name__)
+ kill_by_name('netserver')
+ kill_by_name('netperf')
+ self._send_processes = []
+ self._receive_processes = []
+ return True
+
+
+def unit_test():
+ perf = Netperf()
+ ret = perf.receive_start(namespace='receive')
+ print "*********receive_start***********"
+ print ret
+ send = {
+ "namespace": "send",
+ "protocol": "udp_lat",
+ "dst": [
+ {"ip": "192.168.1.102"}
+ ],
+ "size": 64,
+ "threads": 1,
+ "time": 10,
+ }
+ print perf.send_start(**send)
+ print perf._send_processes
+ time.sleep(10)
+ print perf.send_stop()
+ print perf.receive_stop()
+
+
+if __name__ == "__main__":
+ from vstf.common.log import setup_logging
+
+ setup_logging(level=logging.DEBUG, log_file="/var/log/vstf/vstf-netperf.log", clevel=logging.DEBUG)
+ unit_test()
diff --git a/vstf/vstf/agent/perf/pktgen.py b/vstf/vstf/agent/perf/pktgen.py
new file mode 100755
index 00000000..58c0e6c8
--- /dev/null
+++ b/vstf/vstf/agent/perf/pktgen.py
@@ -0,0 +1,149 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+# author:
+# date: 2015-09-15
+# see license for license details
+import subprocess
+import time
+import logging
+import vstf.agent.perf.utils as utils
+import vstf.common.decorator as deco
+from vstf.common.utils import my_popen
+
+LOG = logging.getLogger(__name__)
+
+
+class Pktgen(object):
+ def __init__(self):
+ utils.modprobe_pktgen()
+ self._send_processes = []
+
+ def _psetpg(self, dev):
+ self._dev = dev
+
+ def _vsetpg(self, key, value=''):
+ with open(self._dev, 'w') as f:
+ txt = "%(key)s %(value)s\n" % {'key': key, 'value': value}
+ f.write(txt)
+ LOG.info("write(%s) to %s", txt.strip(), self._dev)
+
+ def _start(self):
+ cmd = 'echo start > /proc/net/pktgen/pgctrl'
+ process = my_popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ LOG.info('running pid:%s', process.pid)
+ time.sleep(0.5)
+ ret = process.poll()
+ if ret is None:
+ ret = 0
+ self._send_processes.append(process)
+ error_str = "start pktgen send success"
+ else:
+ error_str = "start pktgen send failed, stdout:%s,stderr:%s" % (process.stdout.read(), process.stderr.read())
+ LOG.info(error_str)
+ return ret, error_str
+
+ def _rem_device_all(self):
+ cpu_num = utils.get_cpu_num()
+ for thread in range(0, cpu_num - 1):
+ self._psetpg("/proc/net/pktgen/kpktgend_%s" % thread)
+ self._vsetpg('rem_device_all')
+ return True
+
+ @deco.check("protocol", choices=['udp_bw'], defaults='udp_bw')
+ @deco.check("namespace", defaults=None)
+ @deco.check("dst")
+ @deco.check("src")
+ @deco.check("size", defaults=64)
+ @deco.check("threads", defaults=utils.get_default_threads())
+ @deco.check("clone_skb", defaults=1)
+ @deco.check("count", defaults=0)
+ @deco.check("ratep", defaults=0)
+ def send_start(self, **kwargs):
+ # ensure that all sends is exit
+ self.send_stop()
+
+ interface_num = len(kwargs['src'])
+ interfaces = []
+ for i in range(interface_num):
+ device = kwargs['src'][i]['iface']
+ interfaces.append(device)
+ utils.iface_up(device)
+
+ self._rem_device_all()
+
+ threads = kwargs['threads']
+ for i in range(interface_num):
+ dev_min = i * threads
+ dev_max = (i + 1) * threads
+ device = interfaces[i]
+ for dev_id in range(dev_min, dev_max):
+ queue_id = dev_id % threads
+ self._psetpg("/proc/net/pktgen/kpktgend_%s" % dev_id)
+ self._vsetpg('add_device', "%s@%s" % (device, queue_id))
+ self._psetpg("/proc/net/pktgen/%s@%s" % (device, queue_id))
+ self._vsetpg('pkt_size', kwargs['size'])
+ self._vsetpg('clone_skb', kwargs['clone_skb'])
+ self._vsetpg('dst_mac', kwargs['dst'][i]['mac'])
+ self._vsetpg('src_mac', kwargs['src'][i]['mac'])
+ self._vsetpg('count', kwargs['count'])
+ if kwargs['ratep']:
+ self._vsetpg('ratep', kwargs['ratep'])
+ return self._start()
+
+ def send_stop(self, **kwargs):
+ results = []
+ ret = 0
+ for process in self._send_processes:
+ process.kill()
+ process.wait()
+ LOG.info("process.kill(pktgen:%s)", process.pid)
+ results.append((ret, process.stdout.read()))
+ self._send_processes = []
+ return results
+
+ def receive_start(self, **kwargs):
+ ret = 0
+ error_str = "%s pktgen neednt receive start" % (self.__class__)
+ LOG.debug(error_str)
+ return ret, error_str
+
+ def receive_stop(self, **kwargs):
+ ret = 0
+ error_str = "pktgen neednt receive stop"
+ LOG.debug(error_str)
+ return ret, error_str
+
+ def clean(self):
+ self.send_stop()
+ return True
+
+ def force_clean(self):
+ LOG.info("%s %s start", self.__class__, self.force_clean.__name__)
+ return self.clean()
+
+
+def unit_test():
+ perf = Pktgen()
+ print perf.receive_start()
+ send = {
+ "src": [
+ {"iface": 'eth4', "mac": "90:e2:ba:20:1f:d8"}
+ ],
+ "dst": [
+ {"mac": '90:e2:ba:20:1f:d9'}
+ ],
+ "size": 64,
+ "threads": 1,
+ 'ratep': 0
+ }
+ print perf.send_start(**send)
+ time.sleep(30)
+ print perf.send_stop()
+ print perf.receive_stop()
+
+
+if __name__ == "__main__":
+ from vstf.common.log import setup_logging
+
+ setup_logging(level=logging.DEBUG, log_file="/var/log/vstf/vstf-pktgen.log", clevel=logging.DEBUG)
+ unit_test()
diff --git a/vstf/vstf/agent/perf/qperf.py b/vstf/vstf/agent/perf/qperf.py
new file mode 100755
index 00000000..3cb9eafd
--- /dev/null
+++ b/vstf/vstf/agent/perf/qperf.py
@@ -0,0 +1,164 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+# author:
+# date: 2015-09-15
+# see license for license details
+
+import subprocess
+import time
+import logging
+import vstf.common.decorator as deco
+from vstf.common import perfmark as mark
+from vstf.common.utils import kill_by_name, my_popen
+
+LOG = logging.getLogger(__name__)
+
+
+class Qperf(object):
+ def __init__(self):
+ self._send_processes = []
+ self._receive_processes = []
+
+ @deco.check("protocol", choices=['tcp_lat', 'udp_lat'])
+ @deco.check("namespace", defaults=None)
+ @deco.check("dst")
+ @deco.check("time", defaults=10)
+ @deco.check("size", defaults=64)
+ def send_start(self, **kwargs):
+ cmd = self.format_send_start(**kwargs)
+ LOG.info("cmd:%s", cmd)
+ process = my_popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ time.sleep(0.5)
+ ret = process.poll()
+ if ret is None:
+ ret = 0
+ error_str = "start qperf send success"
+ self._send_processes.append(process)
+ else:
+ print ret
+ error_str = "start qperf send failed, %s" % (str(kwargs))
+ process.wait()
+
+ return ret, error_str
+
+ @deco.namespace()
+ def format_send_start(self, **kwargs):
+ cmd = "qperf %(dst_ip)s -t %(time)s -m %(pkt_size)s -vu %(type)s "
+ context = {
+ 'dst_ip': kwargs['dst'][0]['ip'],
+ 'type': kwargs['protocol'],
+ 'time': kwargs['time'],
+ 'pkt_size': kwargs['size'],
+ }
+ cmd = cmd % context
+ return cmd
+
+ def send_stop(self, **kwargs):
+ results = []
+ for process in self._send_processes:
+ process.wait()
+ read = process.stdout.read()
+ read = self._parse_data(read)
+ ret = 0
+ results.append((ret, read))
+ self._send_processes = []
+ return results
+
+ @deco.namespace()
+ def format_receive_start(self, **kwargs):
+ cmd = 'qperf'
+ return cmd
+
+ def receive_start(self, **kwargs):
+ cmd = self.format_receive_start(**kwargs)
+ LOG.info("cmd:%s", cmd)
+
+ process = my_popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ time.sleep(0.5)
+ ret = process.poll()
+ if ret is None:
+ ret = 0
+ error_str = "start qperf receive success"
+ self._receive_processes.append(process)
+ else:
+ print ret
+ error_str = "start qperf receive failed, %s" % (str(kwargs))
+ process.wait()
+ raise Exception(error_str)
+ return ret, error_str
+
+ def receive_stop(self, **kwargs):
+ ret = 0
+ for process in self._receive_processes:
+ process.kill()
+ process.wait()
+ self._receive_processes = []
+ error_str = "stop qperf receive success"
+ return ret, error_str
+
+ def receive_kill(self):
+ kill_by_name('qperf')
+ self._receive_processes = []
+ return True
+
+ def clean(self):
+ for process in self._receive_processes:
+ process.kill()
+ process.wait()
+ LOG.info("process.kill(qperf daemon:%s)", process.pid)
+ for process in self._send_processes:
+ LOG.info("process.wait(qperf client:%s)", process.pid)
+ process.wait()
+ self._receive_processes = []
+ self._send_processes = []
+ return True
+
+ def force_clean(self):
+ LOG.info("%s %s start", self.__class__, self.force_clean.__name__)
+ kill_by_name('qperf')
+ self._send_processes = []
+ self._receive_processes = []
+ return True
+
+ def _parse_data(self, data):
+ LOG.info(data)
+ latency = 0
+ if data:
+ buf = data.splitlines()
+ if "latency" in buf[1]:
+ data = buf[1].strip().split()
+ if data[3] == "us":
+ latency = float(data[2]) / 1000
+ else:
+ latency = float(data[2]) / 1000
+ result = {
+ mark.minLatency: latency,
+ mark.avgLatency: latency,
+ mark.maxLatency: latency
+ }
+ return result
+
+
+def unit_test():
+ perf = Qperf()
+ perf.receive_start(namespace='receive')
+
+ send = {
+ "namespace": "send",
+ "protocol": "udp_lat",
+ "dst": [
+ {"ip": "192.168.1.102"}
+ ],
+ "size": 64,
+ }
+ print perf.send_start(**send)
+ time.sleep(10)
+ print perf.send_stop()
+ print perf.receive_stop()
+
+
+if __name__ == "__main__":
+ from vstf.common.log import setup_logging
+
+ setup_logging(level=logging.DEBUG, log_file="/var/log/vstf/vstf-qperf.log", clevel=logging.DEBUG)
+ unit_test()
diff --git a/vstf/vstf/agent/perf/sar.py b/vstf/vstf/agent/perf/sar.py
new file mode 100755
index 00000000..c4688c9c
--- /dev/null
+++ b/vstf/vstf/agent/perf/sar.py
@@ -0,0 +1,78 @@
+"""
+Created on 2015-8-6
+
+@author: y00228926
+"""
+import subprocess
+import logging
+import time
+import os
+from signal import SIGINT
+
+from vstf.common.utils import check_output, my_popen, kill_by_name
+from vstf.agent.env.basic import collect
+
+LOG = logging.getLogger(__name__)
+
+
+class Sar(object):
+ def __init__(self):
+ self.sar_cmd_str = "sar -u %(interval)s"
+ self.child_process = {}
+
+ def start(self, interval=2):
+ cmd = self.sar_cmd_str % {'interval': interval}
+ child = my_popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ time.sleep(1)
+ if child.poll() is not None:
+ print child.poll()
+ raise Exception("start vnstat error, vnstat is not running")
+ self.child_process[child.pid] = child
+ return child.pid
+
+ def stop(self, pid):
+ assert pid in self.child_process
+ os.kill(pid, SIGINT)
+ process = self.child_process.pop(pid)
+ out = process.stdout.read()
+ process.wait()
+ data = {'raw_data': out, 'tool': 'sar', 'type': 'cpu'}
+ cpu_info = collect.Collect().collect_host_info()[1]
+ cpu_num = cpu_info['CPU INFO']['CPU(s)']
+ cpu_mhz = cpu_info['CPU INFO']['CPU MHz']
+ data.update({'cpu_num': float(cpu_num), 'cpu_mhz': float(cpu_mhz)})
+ return data
+
+ def process(self, raw):
+ lines = raw.splitlines()
+ # print lines
+ head = lines[2].split()[3:]
+ average = lines[-1].split()[2:]
+ data = {}
+ for h, d in zip(head, average):
+ data[h.strip('%')] = float(d)
+ cpu_num = check_output('cat /proc/cpuinfo | grep processor | wc -l', shell=True).strip()
+ data.update({'cpu_num': int(cpu_num)})
+ return data
+
+ def clean(self):
+ for _, process in self.child_process.items():
+ process.kill()
+ process.wait()
+ self.child_process = {}
+ return True
+
+ def force_clean(self):
+ LOG.info("%s %s start", self.__class__, self.force_clean.__name__)
+ kill_by_name("sar")
+ self.child_process = {}
+ return True
+
+if __name__ == '__main__':
+ logging.basicConfig(level=logging.DEBUG)
+ q = Sar()
+ pid = q.start()
+ time.sleep(10)
+ raw = q.stop(pid)
+ print raw
+ print q.process(raw['raw_data'])
diff --git a/vstf/vstf/agent/perf/utils.py b/vstf/vstf/agent/perf/utils.py
new file mode 100755
index 00000000..1fb4b92c
--- /dev/null
+++ b/vstf/vstf/agent/perf/utils.py
@@ -0,0 +1,42 @@
+"""
+Created on 2015-8-6
+
+@author: y00228926
+"""
+import logging
+import subprocess
+from vstf.common.utils import check_call, check_output
+
+LOG = logging.getLogger(__name__)
+
+
+def get_pid_by_name(process_name):
+ out = check_output(['ps', '-A'])
+ pids = []
+ for line in out.splitlines():
+ values = line.split()
+ pid, name = values[0], values[3]
+ if process_name == name:
+ pids.append(int(pid))
+ return pids
+
+
+def get_cpu_num():
+ cpu_num = check_output('cat /proc/cpuinfo | grep processor | wc -l', shell=True).strip()
+ cpu_num = int(cpu_num)
+ return cpu_num
+
+
+def get_default_threads():
+ cpu_num = get_cpu_num()
+ return 2 if cpu_num > 3 * 3 else 1
+
+
+def modprobe_pktgen():
+ check_call('modprobe pktgen', shell=True)
+ return True
+
+
+def iface_up(device):
+ check_call("ifconfig %s up" % device, shell=True)
+ return True
diff --git a/vstf/vstf/agent/perf/vnstat.py b/vstf/vstf/agent/perf/vnstat.py
new file mode 100755
index 00000000..7a47af14
--- /dev/null
+++ b/vstf/vstf/agent/perf/vnstat.py
@@ -0,0 +1,106 @@
+"""
+Created on 2015-8-6
+
+@author: y00228926
+"""
+import subprocess
+import time
+import re
+from signal import SIGINT
+import os
+import logging
+from vstf.common.utils import check_call, my_popen, kill_by_name
+
+LOG = logging.getLogger(__name__)
+
+
+class VnStat(object):
+ def __init__(self):
+ self.netns_exec_str = "ip netns exec %s "
+ self.vnstat_cmd_str = "vnstat -l -i %s"
+ self.child_process = {}
+
+ def run_vnstat(self, device, namespace=None):
+ cmd = self.vnstat_cmd_str
+ if namespace:
+ cmd1 = (self.netns_exec_str + "ifconfig %s") % (namespace, device)
+ check_call(cmd1, shell=True)
+ cmd = self.netns_exec_str + cmd
+ cmd = cmd % (namespace, device)
+ else:
+ cmd = cmd % device
+ check_call("which vnstat", shell=True)
+ child = my_popen(cmd.split(), stdout=subprocess.PIPE)
+ self.child_process[child.pid] = child
+ return child.pid
+
+ def kill_vnstat(self, pid, namespace=None):
+ assert pid in self.child_process
+ os.kill(pid, SIGINT)
+ process = self.child_process.pop(pid)
+ out = process.stdout.read()
+ process.wait()
+ LOG.info("os.kill(pid = %s)", pid)
+ data = {'tool': 'vnstat', 'type': 'nic', 'raw_data': out}
+ return data
+
+ def clean(self):
+ for _, process in self.child_process.items():
+ process.kill()
+ process.wait()
+ LOG.info("process.kill(vnstat:%s)", process.pid)
+ self.child_process = {}
+ return True
+
+ def process(self, raw):
+ buf = raw.splitlines()
+ buf = buf[9:]
+ buf = ' '.join(buf)
+ m = {}
+
+ digits = re.compile(r"\d+\.?\d*")
+ units = re.compile("(?:gib|mib|kib|kbit/s|gbits/s|mbit/s|p/s)", re.IGNORECASE | re.MULTILINE)
+ units_arr = units.findall(buf)
+
+ LOG.debug(units_arr)
+
+ digits_arr = digits.findall(buf)
+
+ for i in range(len(digits_arr)):
+ digits_arr[i] = round(float(digits_arr[i]), 2)
+
+ m['rxpck'], m['txpck'] = digits_arr[8], digits_arr[9]
+ m['time'] = digits_arr[-1]
+ digits_arr = digits_arr[:8] + digits_arr[10:-1]
+ index = 0
+ for unit in units_arr:
+ unit = unit.lower()
+ if unit == 'gib':
+ digits_arr[index] *= 1024
+ elif unit == 'kib':
+ digits_arr[index] /= 1024
+ elif unit == 'gbit/s':
+ digits_arr[index] *= 1000
+ elif unit == 'kbit/s':
+ digits_arr[index] /= 1000
+ else:
+ pass
+ index += 1
+
+ for i in range(len(digits_arr)):
+ digits_arr[i] = round(digits_arr[i], 2)
+
+ m['rxmB'], m['txmB'] = digits_arr[0:2]
+ m['rxmB_max/s'], m['txmB_max/s'] = digits_arr[2:4]
+ m['rxmB/s'], m['txmB/s'] = digits_arr[4:6]
+ m['rxmB_min/s'], m['txmB_min/s'] = digits_arr[6:8]
+ m['rxpck_max/s'], m['txpck_max/s'] = digits_arr[8:10]
+ m['rxpck/s'], m['txpck/s'] = digits_arr[10:12]
+ m['rxpck_min/s'], m['txpck_min/s'] = digits_arr[12:14]
+ return m
+
+ def force_clean(self):
+ LOG.info("%s %s start", self.__class__, self.force_clean.__name__)
+ kill_by_name("vnstat")
+ self.child_process = {}
+ return True
diff --git a/vstf/vstf/agent/perf/vstfperf.py b/vstf/vstf/agent/perf/vstfperf.py
new file mode 100755
index 00000000..224380fe
--- /dev/null
+++ b/vstf/vstf/agent/perf/vstfperf.py
@@ -0,0 +1,105 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+# author: wly
+# date: 2015-09-08
+# see license for license details
+
+
+__doc__ = """
+operation: [start, stop, restart]
+action: [send, receive]
+tool: [pktgen, netperf, qperf, iperf, netmap]
+params:
+ protocol: [tcp_lat, udp_lat, tcp_bw, udp_bw]
+ namespace: None
+ src:[
+ { "iface":"eth0", "ip":"xxx.xxx.xxx.xxx", "mac":"FF:FF:FF:FF:FF:FF"}
+ ]
+ dst:[
+ { "iface":"eth0", "ip":"xxx.xxx.xxx.xxx", "mac":"FF:FF:FF:FF:FF:FF"}
+ ]
+ size: 64
+ threads: 1
+ ratep: 100000 (pps)
+ time: 100 (s)
+"""
+
+import sys
+import logging
+import vstf.common.constants as cst
+import vstf.common.decorator as deco
+import vstf.agent.perf.pktgen as vstf_pktgen
+import vstf.agent.perf.netmap as vstf_netmap
+import vstf.agent.perf.qperf as vstf_qperf
+import vstf.agent.perf.iperf as vstf_iperf
+import vstf.agent.perf.netperf as vstf_netperf
+
+LOG = logging.getLogger(__name__)
+
+
+class Vstfperf(object):
+ def __init__(self):
+ for tool in cst.TOOLS:
+ obj_name = 'vstf_' + tool
+ obj = getattr(sys.modules[__name__], obj_name)
+ cls_name = tool.title()
+ cls = getattr(obj, tool.title())
+ self.__dict__.update({tool: cls()})
+
+ @deco.check("operation", choices=cst.OPERATIONS)
+ @deco.check("action", choices=cst.ACTIONS)
+ @deco.check("tool", choices=cst.TOOLS)
+ @deco.check("params", defaults={})
+ def run(self, **kwargs):
+ print "_run in"
+ operation = kwargs.pop("operation")
+ tool = kwargs.pop("tool")
+ instance = getattr(self, tool)
+ action = kwargs.pop("action")
+ func_name = "%s_%s" % (action, operation)
+ func = getattr(instance, func_name)
+ LOG.info(kwargs['params'])
+ LOG.info(func)
+ ret = func(**kwargs['params'])
+ return ret
+
+ def force_clean(self):
+ LOG.info("%s %s start", self.__class__, self.force_clean.__name__)
+ for tool in cst.TOOLS:
+ instance = getattr(self, tool)
+ instance.force_clean()
+ return True
+
+
+def unit_test():
+ from vstf.common.log import setup_logging
+ setup_logging(level=logging.DEBUG, log_file="/var/log/vstf/vstf-vstfperf.log", clevel=logging.INFO)
+
+ perf = Vstfperf()
+ start = {
+ "operation": "start",
+ "action": "send",
+ "tool": "netperf",
+ "params": {
+ "namespace": "vnet_name1",
+ "protocol": "udp_lat",
+ "dst": [
+ {"ip": "192.168.1.102"}
+ ],
+ "size": 64,
+ "threads": 1,
+ "time": 100,
+ },
+ }
+ perf.run(**start)
+
+ stop = {
+ "operation": "stop",
+ "action": "send",
+ "tool": "netperf",
+ }
+ perf.run(**stop)
+
+
+if __name__ == '__main__':
+ unit_test()