From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by dpdk.org (Postfix) with ESMTP id 401812661 for ; Wed, 26 Jul 2017 05:44:11 +0200 (CEST) Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 25 Jul 2017 20:44:10 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.40,413,1496127600"; d="scan'208";a="882875448" Received: from dpdk-test38.sh.intel.com ([10.67.111.97]) by FMSMGA003.fm.intel.com with ESMTP; 25 Jul 2017 20:44:09 -0700 From: Marvin Liu To: dts@dpdk.org Cc: Marvin Liu Date: Tue, 25 Jul 2017 23:42:01 -0400 Message-Id: <1501040521-43009-3-git-send-email-yong.liu@intel.com> X-Mailer: git-send-email 1.9.3 In-Reply-To: <1501040521-43009-1-git-send-email-yong.liu@intel.com> References: <1501037774-40417-1-git-send-email-yong.liu@intel.com> <1501040521-43009-1-git-send-email-yong.liu@intel.com> Subject: [dts] [PATCH v2 2/2] tests: add test suite for distributor library and sample X-BeenThere: dts@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: test suite reviews and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 26 Jul 2017 03:44:12 -0000 Signed-off-by: Marvin Liu diff --git a/tests/TestSuite_distributor.py b/tests/TestSuite_distributor.py new file mode 100644 index 0000000..a900f5e --- /dev/null +++ b/tests/TestSuite_distributor.py @@ -0,0 +1,283 @@ +# 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() + self.app = "./examples/distributor/build/distributor_app" + + 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"] + + # 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 % (self.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") + 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 % (self.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 + """ + 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 % (self.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