[dts] [PATCH v1 2/2] tests: add test suite for distributor library and sample
Marvin Liu
yong.liu at intel.com
Wed Jul 26 04:56:14 CEST 2017
Signed-off-by: Marvin Liu <yong.liu at intel.com>
diff --git a/tests/TestSuite_distributor.py b/tests/TestSuite_distributor.py
new file mode 100644
index 0000000..63edd52
--- /dev/null
+++ b/tests/TestSuite_distributor.py
@@ -0,0 +1,286 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""
+DPDK Test suite.
+"""
+import re
+import utils
+from test_case import TestCase
+from etgen import IxiaPacketGenerator
+
+
+class TestDistributor(TestCase, IxiaPacketGenerator):
+ def set_up_all(self):
+ """
+ Run at the start of each test suite.
+ """
+ self.tester.extend_external_packet_generator(TestDistributor, self)
+
+ out = self.dut.send_expect("make -C test -j", "#")
+ self.verify("Error" not in out, "Compilation error")
+ self.verify("No such" not in out, "Compilation error")
+
+ # reduce tx queues for enable many workers
+ self.dut.send_expect("sed -i -e 's/.*txRings = .*/\\tconst uint16_t rxRings = 1, txRings = 1;/' ./examples/distributor/main.c", "#")
+ out = self.dut.build_dpdk_apps("./examples/distributor")
+ self.verify("Error" not in out, "Compilation error")
+ self.verify("No such" not in out, "Compilation error")
+
+ self.dut_ports = self.dut.get_ports()
+
+
+ def set_up(self):
+ """
+ Run before each test case.
+ """
+ pass
+
+ def test_distributor_unit(self):
+ """
+ Run distributor unit test
+ """
+ self.dut.send_expect("./test/test/test -n 1 -c f", "RTE>>", 60)
+ out = self.dut.send_expect("distributor_autotest", "RTE>>", 30)
+ self.dut.send_expect("quit", "# ")
+ self.verify("Test OK" in out, "Test failed")
+
+ def test_distributor_unit_perf(self):
+ """
+ Run distributor unit perf test
+ """
+ self.dut.send_expect("./test/test/test -n 1 -c f", "RTE>>", 60)
+ out = self.dut.send_expect("distributor_perf_autotest", "RTE>>", 120)
+ cycles_single = self.strip_cycles(out, "single")
+ cycles_burst = self.strip_cycles(out, "burst")
+ self.logger.info("Cycles for single mode is %d burst mode is %d"
+ % (cycles_single, cycles_burst))
+ self.dut.send_expect("quit", "# ")
+ self.verify("Test OK" in out, "Test failed")
+ self.verify(cycles_single > cycles_burst * 2,
+ "Burst performance should be much better")
+
+ def test_perf_distributor(self):
+ """
+ Run distributor perf test, recorded statistic of Rx/Enqueue/Sent/Dequeue/Tx
+ """
+ self.verify(len(self.dut_ports) >=1, "Not enough ports")
+ workers = [1, 2, 3, 4, 8, 16, 32]
+ table_header = ["Number of workers",
+ "Throughput Rate Rx received",
+ "Throughput Rate Rx core enqueued",
+ "Throughput Rate Distributor Sent",
+ "Throughput Rate Tx core dequeued",
+ "Throughput Rate Tx transmitted",
+ "Throughput Rate Pkts out",
+ "Throughput Rate Pkts out line rate"]
+
+ app = "./examples/distributor/build/distributor_app"
+ # output port is calculated from overall ports number
+ cmd_fmt = "%s -c %s -n %d -w %s -- -p 0x1"
+ socket = self.dut.get_numa_id(self.dut_ports[0])
+
+ self.tester.scapy_append('wrpcap("distributor.pcap", [Ether()/IP()/("X"*26)])')
+ self.tester.scapy_execute()
+ tgen_input = []
+ rx_port = self.tester.get_local_port(self.dut_ports[0])
+ tx_port = self.tester.get_local_port(self.dut_ports[0])
+ tgen_input.append((tx_port, rx_port, "distributor.pcap"))
+
+ self.result_table_create(table_header)
+ for worker_num in workers:
+ # Rx core/distributor core/Tx core/stats core
+ cores = self.dut.get_core_list("1S/%dC/1T" % (worker_num + 4), socket)
+ # If can't get enough core from one socket, just use all lcores
+ if len(cores) < (worker_num + 4):
+ cores = self._get_thread_lcore(worker_num + 4)
+
+ cmd = cmd_fmt % (app, utils.create_mask(cores),
+ self.dut.get_memory_channels(),
+ self.dut.get_port_pci(self.dut_ports[0]))
+
+ self.dut.send_expect(cmd, "doing packet RX", timeout=30)
+
+ self.tester.ixia_packet_gen.hook_transmission_func = self.hook_transmission_func
+ _, pps = self.tester.traffic_generator_throughput(tgen_input, delay=2)
+
+ self.dut.send_expect("^C", "#")
+
+ pps/= 1000000.0
+ rx, enq, sent, deq, trans = self.strip_performance_data(self.app_output)
+ rate = pps * 100 / float(self.wirespeed(self.nic, 64, 1))
+ self.result_table_add([worker_num, rx, enq, sent, deq, trans, pps, float('%.3f' % rate)])
+
+ self.result_table_print()
+
+ def test_maximum_workers(self):
+ """
+ Check distributor app work fine with maximum workers
+ """
+ self.verify(len(self.dut_ports) >=1, "Not enough ports")
+ app = "./examples/distributor/build/distributor_app"
+ cmd_fmt = "%s -c %s -n %d -w %s -- -p 0x1"
+
+ out = self.dut.send_expect("sed -n '/#define RTE_DISTRIB_MAX_WORKERS/p' lib/librte_distributor/rte_distributor_private.h", "# ")
+ reg_match = r"#define RTE_DISTRIB_MAX_WORKERS (.*)"
+ m = re.match(reg_match, out)
+ self.verify(m, "Can't find maximum worker number")
+
+ max_workers = int(m.group(1))
+ cores = self._get_thread_lcore(max_workers - 1 + 4)
+
+ cmd = cmd_fmt % (app, utils.create_mask(cores),
+ self.dut.get_memory_channels(),
+ self.dut.get_port_pci(self.dut_ports[0]))
+
+ self.dut.send_expect(cmd, "doing packet RX", timeout=30)
+
+ tx_port = self.tester.get_local_port(self.dut_ports[0])
+ tgen_input = [(tx_port, tx_port)]
+ self.tester.check_random_pkts(tgen_input, pktnum=256, seq_check=True)
+
+ self.dut.send_expect("^C", "#")
+
+ def test_multiple_ports(self):
+ """
+ Check distributor app work fine with multiple ports
+ """
+ app = "./examples/distributor/build/distributor_app"
+ self.verify(len(self.dut_ports) >=2, "Not enough ports")
+ cmd_fmt = "%s -c %s -n %d -w %s -w %s -- -p 0x3"
+ socket = self.dut.get_numa_id(self.dut_ports[0])
+ cores = self.dut.get_core_list("1S/%dC/1T" % (2 + 4), socket)
+
+ cmd = cmd_fmt % (app, utils.create_mask(cores),
+ self.dut.get_memory_channels(),
+ self.dut.get_port_pci(self.dut_ports[0]),
+ self.dut.get_port_pci(self.dut_ports[1]))
+
+ self.dut.send_expect(cmd, "doing packet RX", timeout=30)
+
+ tx_port = self.tester.get_local_port(self.dut_ports[0])
+ rx_port = self.tester.get_local_port(self.dut_ports[1])
+ tgen_input = [(tx_port, rx_port)]
+ self.tester.check_random_pkts(tgen_input, pktnum=256, seq_check=True)
+
+ tgen_input = [(rx_port, tx_port)]
+ self.tester.check_random_pkts(tgen_input, pktnum=256, seq_check=True)
+
+ self.dut.send_expect("^C", "#")
+
+ def _get_thread_lcore(self, core_num):
+ def strip_core(x):
+ return(int(x['thread']))
+ cores = map(strip_core, self.dut.cores[0:core_num])
+ return cores
+
+ def hook_transmission_func(self):
+ self.app_output = self.dut.session.get_session_before(timeout=2)
+
+ def strip_performance_data(self, output=""):
+ """
+ Strip throughput of each stage in threads
+ RX Thread:
+ Port 0 Pktsin :
+ - Received:
+ - Returned:
+ - Enqueued:
+ - Dropped:
+ Distributor thread:
+ - In:
+ - Returned:
+ - Sent:
+ - Dropped:
+ TX thread:
+ - Dequeued:
+ Port 0 Pktsout:
+ - Transmitted:
+ - Dropped:
+ """
+ # skip the last one, we use the next one
+ output = output[:output.rfind("RX Thread")]
+ output = output[output.rfind("RX Thread"):]
+ rec_rate = 0.0
+ enq_rate = 0.0
+ sent_rate = 0.0
+ deq_rate = 0.0
+ trans_rate = 0.0
+ for line in output.splitlines():
+ if "Received" in line:
+ rec_rate = float(line.split()[2])
+ elif "Enqueued" in line:
+ enq_rate = float(line.split()[2])
+ elif "Sent" in line:
+ sent_rate = float(line.split()[2])
+ elif "Dequeued" in line:
+ deq_rate = float(line.split()[2])
+ elif "Transmitted" in line:
+ trans_rate = float(line.split()[2])
+
+ return (rec_rate, enq_rate, sent_rate, deq_rate, trans_rate)
+
+ def strip_cycles(self, out="", mode="single"):
+ """
+ Strip per packet cycles from output like:
+ Time per burst: 12542
+ Time per packet: 195
+ """
+ out = out[out.index("%s mode" % mode):]
+ lines = out.splitlines()
+ cycles = lines[2].split()[3]
+ return int(cycles)
+
+ def ip(self, port, frag, src, proto, tos, dst, chksum, len, options, version, flags, ihl, ttl, id):
+ self.add_tcl_cmd("protocol config -name ip")
+ self.add_tcl_cmd('ip config -sourceIpAddr "%s"' % src)
+ self.add_tcl_cmd("ip config -sourceIpAddrMode ipIdle")
+ self.add_tcl_cmd('ip config -destIpAddr "%s"' % dst)
+ self.add_tcl_cmd("ip config -destIpAddrMode ipRandom")
+ self.add_tcl_cmd("ip config -ttl %d" % ttl)
+ self.add_tcl_cmd("ip config -totalLength %d" % len)
+ self.add_tcl_cmd("ip config -fragment %d" % frag)
+ self.add_tcl_cmd("ip config -ipProtocol ipV4ProtocolReserved255")
+ self.add_tcl_cmd("ip config -identifier %d" % id)
+ self.add_tcl_cmd("stream config -framesize %d" % (len + 18))
+ self.add_tcl_cmd("ip set %d %d %d" % (self.chasId, port['card'], port['port']))
+
+ def tear_down(self):
+ """
+ Run after each test case.
+ """
+ pass
+
+ def tear_down_all(self):
+ """
+ Run after each test suite.
+ """
+ self.dut.send_expect("sed -i -e 's/.*txRings = .*/\\tconst uint16_t rxRings = 1, txRings = rte_lcore_count() - 1;/' ./examples/distributor/main.c", "#")
+ pass
--
1.9.3
More information about the dts
mailing list