From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by dpdk.org (Postfix) with ESMTP id 75AAF2BAC for ; Mon, 21 May 2018 03:50:15 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 20 May 2018 18:50:13 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,425,1520924400"; d="scan'208";a="230162981" Received: from dpdk-test47.sh.intel.com ([10.67.118.152]) by fmsmga005.fm.intel.com with ESMTP; 20 May 2018 18:50:12 -0700 From: wang fei To: dts@dpdk.org Cc: wang fei Date: Mon, 21 May 2018 12:16:57 +0800 Message-Id: <1526876217-60447-1-git-send-email-feix.y.wang@intel.com> X-Mailer: git-send-email 2.7.4 Subject: [dts] [DTS][Patch V3 0/2] VF_performace_test_suite 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: Mon, 21 May 2018 01:50:16 -0000 Add performance test for kernel PF + DPDK VF and DPDK PF + DPDK VF. Signed-off-by: wang fei --- tests/TestSuite_vf_perf.py | 340 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 340 insertions(+) create mode 100644 tests/TestSuite_vf_perf.py diff --git a/tests/TestSuite_vf_perf.py b/tests/TestSuite_vf_perf.py new file mode 100644 index 0000000..6b36c8a --- /dev/null +++ b/tests/TestSuite_vf_perf.py @@ -0,0 +1,340 @@ +# 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. + +import re +import time +import string + +import utils +from test_case import TestCase +from pmd_output import PmdOutput +from etgen import IxiaPacketGenerator +from settings import HEADER_SIZE + +class TestVfPerf(TestCase, IxiaPacketGenerator): + + def set_up_all(self): + + self.tester.extend_external_packet_generator(TestVfPerf, self) + + self.dut_ports = self.dut.get_ports(self.nic) + self.verify(len(self.dut_ports) >= 2, "Insufficient ports") + + self.pf0 = self.dut_ports[0] + netdev = self.dut.ports_info[self.pf0]['port'] + self.pf0_socket = netdev.get_nic_socket() + + self.cores = self.dut.get_core_list("1S/6C/1T", socket=self.pf0_socket) + self.verify(self.cores is not None, "Insufficient cores for the testing") + + self.req_ports = eval(self.get_suite_cfg()['req_ports']) + assert self.req_ports in [2, 4], "Requested Ports Number Must Be 2 or 4" + + global valports + valports = [_ for _ in self.dut_ports if self.tester.get_local_port(_) != -1] + self.verify(len(valports) >= self.req_ports, "Insufficient active ports for testing") + + self.frame_sizes = [64, 128, 256, 512, 1024, 1518] + self.l3fwd_methods = ['lpm'] + + self.vf0_mac = "00:12:34:56:78:01" + self.vf1_mac = "00:12:34:56:78:02" + if self.req_ports == 4: + self.vf2_mac = "00:12:34:56:78:03" + self.vf3_mac = "00:12:34:56:78:04" + + self.l3fwd_test_results = {'header': [], 'data': []} + + self.dut.send_expect("sed -i -e 's/define RTE_TEST_RX_DESC_DEFAULT.*$/" + + "define RTE_TEST_RX_DESC_DEFAULT 2048/' ./examples/l3fwd/main.c", "#", 20) + self.dut.send_expect("sed -i -e 's/define RTE_TEST_TX_DESC_DEFAULT.*$/" + + "define RTE_TEST_TX_DESC_DEFAULT 2048/' ./examples/l3fwd/main.c", "#", 20) + out = self.dut.build_dpdk_apps("./examples/l3fwd", "USER_FLAGS=-DAPP_LOOKUP_METHOD=1") + self.verify("Error" not in out, "compilation error 1") + self.verify("No such file" not in out, "compilation error 2") + + def set_up(self): + + self.setup_vf_env_flag = 0 + + def setup_vf_env(self, host_driver='default'): + """ + require two PF ports, using kernel or dpdk driver, create 1 VF from each PF. + """ + + self.used_dut_port_0 = self.dut_ports[0] + self.dut.generate_sriov_vfs_by_port(self.used_dut_port_0, 1, host_driver) + self.sriov_vfs_port_0 = self.dut.ports_info[self.used_dut_port_0]['vfs_port'] + + self.used_dut_port_1 = self.dut_ports[1] + self.dut.generate_sriov_vfs_by_port(self.used_dut_port_1, 1, host_driver) + self.sriov_vfs_port_1 = self.dut.ports_info[self.used_dut_port_1]['vfs_port'] + + if self.req_ports == 4: + self.used_dut_port_2 = self.dut_ports[2] + self.dut.generate_sriov_vfs_by_port(self.used_dut_port_2, 1, host_driver) + self.sriov_vfs_port_2 = self.dut.ports_info[self.used_dut_port_2]['vfs_port'] + + self.used_dut_port_3 = self.dut_ports[3] + self.dut.generate_sriov_vfs_by_port(self.used_dut_port_3, 1, host_driver) + self.sriov_vfs_port_3 = self.dut.ports_info[self.used_dut_port_3]['vfs_port'] + + if host_driver != 'igb_uio': + + pf_intf0 = self.dut.ports_info[0]['port'].get_interface_name() + self.dut.send_expect("ip link set %s vf 0 mac %s" % (pf_intf0, self.vf0_mac), "#") + pf_intf1 = self.dut.ports_info[1]['port'].get_interface_name() + self.dut.send_expect("ip link set %s vf 0 mac %s" % (pf_intf1, self.vf1_mac), "#") + if self.req_ports == 4: + pf_intf2 = self.dut.ports_info[2]['port'].get_interface_name() + self.dut.send_expect("ip link set %s vf 0 mac %s" % (pf_intf2, self.vf2_mac), "#") + pf_intf3 = self.dut.ports_info[3]['port'].get_interface_name() + self.dut.send_expect("ip link set %s vf 0 mac %s" % (pf_intf3, self.vf3_mac), "#") + + #bind vf to igb_uio driver + try: + for port in self.sriov_vfs_port_0: + port.bind_driver('igb_uio') + for port in self.sriov_vfs_port_1: + port.bind_driver('igb_uio') + if self.req_ports == 4: + for port in self.sriov_vfs_port_2: + port.bind_driver('igb_uio') + for port in self.sriov_vfs_port_3: + port.bind_driver('igb_uio') + + time.sleep(1) + + if host_driver == 'igb_uio' and self.req_ports ==2: + # start testpmd without the two VFs on the host + self.host_testpmd = PmdOutput(self.dut) + eal_param = '--socket-mem=1024,1024 --file-prefix=pf -b %(vf0)s -b %(vf1)s' % {'vf0': self.sriov_vfs_port_0[0].pci, + 'vf1': self.sriov_vfs_port_1[0].pci} + testpmd_cl = self.cores[0:2] + self.host_testpmd.start_testpmd(testpmd_cl, "", eal_param=eal_param) + self.host_testpmd.execute_cmd('set vf mac addr 0 0 %s' % self.vf0_mac) + self.host_testpmd.execute_cmd('set vf mac addr 1 0 %s' % self.vf1_mac) + elif host_driver == 'igb_uio' and self.req_ports ==4: + self.host_testpmd = PmdOutput(self.dut) + eal_param = '--socket-mem=1024,1024 --file-prefix=pf -b %(vf0)s -b %(vf1)s -b %(vf2)s -b %(vf3)s' % {'vf0': self.sriov_vfs_port_0[0].pci, + 'vf1': self.sriov_vfs_port_1[0].pci, 'vf2': self.sriov_vfs_port_2[0].pci, 'vf3': self.sriov_vfs_port_3[0].pci} + testpmd_cl = self.cores[0:4] + self.host_testpmd.start_testpmd(testpmd_cl, "", eal_param=eal_param) + self.host_testpmd.execute_cmd('set vf mac addr 0 0 %s' % self.vf0_mac) + self.host_testpmd.execute_cmd('set vf mac addr 1 0 %s' % self.vf1_mac) + self.host_testpmd.execute_cmd('set vf mac addr 2 0 %s' % self.vf2_mac) + self.host_testpmd.execute_cmd('set vf mac addr 3 0 %s' % self.vf3_mac) + time.sleep(1) + + self.setup_vf_env_flag = 1 + + except Exception as e: + self.destroy_vf_env() + raise Exception(e) + + def destroy_vf_env(self): + """destroy the setup VFs""" + + if getattr(self, 'host_testpmd', None): + self.host_testpmd.execute_cmd('quit', '# ') + self.host_testpmd = None + + if getattr(self, 'used_dut_port_0', None) != None: + self.dut.destroy_sriov_vfs_by_port(self.used_dut_port_0) + port = self.dut.ports_info[self.used_dut_port_0]['port'] + port.bind_driver() + self.used_dut_port_0 = None + + if getattr(self, 'used_dut_port_1', None) != None: + self.dut.destroy_sriov_vfs_by_port(self.used_dut_port_1) + port = self.dut.ports_info[self.used_dut_port_1]['port'] + port.bind_driver() + self.used_dut_port_1 = None + + if getattr(self, 'used_dut_port_2', None) != None: + self.dut.destroy_sriov_vfs_by_port(self.used_dut_port_2) + port = self.dut.ports_info[self.used_dut_port_2]['port'] + port.bind_driver() + self.used_dut_port_2 = None + + if getattr(self, 'used_dut_port_3', None) != None: + self.dut.destroy_sriov_vfs_by_port(self.used_dut_port_3) + port = self.dut.ports_info[self.used_dut_port_3]['port'] + port.bind_driver() + self.used_dut_port_3 = None + + for port_id in self.dut_ports: + port = self.dut.ports_info[port_id]['port'] + port.bind_driver() + + self.setup_vf_env_flag = 0 + + def flows(self): + """ + Return a list of packets that implements the flows described in l3fwd. + """ + return [ + 'IP(src="1.2.3.4",dst="2.1.1.1")', + 'IP(src="1.2.3.4",dst="2.1.1.2")', + 'IP(src="1.2.3.4",dst="1.1.1.1")', + 'IP(src="1.2.3.4",dst="1.1.1.2")', + 'IP(src="1.2.3.4",dst="4.1.1.1")', + 'IP(src="1.2.3.4",dst="4.1.1.2")', + 'IP(src="1.2.3.4",dst="3.1.1.1")', + 'IP(src="1.2.3.4",dst="3.1.1.2")'] + + def perf_test(self, cmdline): + + l3fwd_session = self.dut.new_session() + + header_row = ["Frame", "mode", "Mpps", "%linerate"] + self.l3fwd_test_results['header'] = header_row + self.result_table_create(header_row) + self.l3fwd_test_results['data'] = [] + + dmac = [self.vf0_mac, self.vf1_mac] + smac = ["02:00:00:00:00:00", "02:00:00:00:00:01"] + if self.req_ports == 4: + dmac.extend([self.vf2_mac, self.vf3_mac]) + smac.extend(["02:00:00:00:00:02", "02:00:00:00:00:03"]) + + for frame_size in self.frame_sizes: + + # Prepare traffic flow + payload_size = frame_size - HEADER_SIZE['ip'] - HEADER_SIZE['eth'] + + for _port in range(self.req_ports): + flows = ['Ether(dst="%s", src="%s")/%s/("X"*%d)' % (dmac[_port], smac[_port], flow, payload_size) for flow in self.flows()[_port *2:(_port +1)*2]] + self.tester.scapy_append('wrpcap("dst%d.pcap", [%s])' %(valports[_port], string.join(flows,','))) + self.tester.scapy_execute() + + for mode in self.l3fwd_methods: + + info = "Executing l3fwd using %s mode, %d ports, %d frame size.\n" % (mode, self.req_ports, frame_size) + self.logger.info(info) + + if frame_size > 1518: + cmdline = cmdline + " --max-pkt-len %d" % frame_size + + out = l3fwd_session.send_expect(cmdline, "L3FWD:", 120) + + # Measure test + tgenInput = [] + + for rxPort in range(self.req_ports): + if rxPort % self.req_ports == 0 or rxPort % self.req_ports == 2 : + txIntf = self.tester.get_local_port(valports[rxPort + 1]) + rxIntf = self.tester.get_local_port(valports[rxPort]) + tgenInput.append((txIntf, rxIntf, "dst%d.pcap" % valports[rxPort+1])) + elif rxPort % self.req_ports == 1 or rxPort % self.req_ports == 3: + txIntf = self.tester.get_local_port(valports[rxPort - 1]) + rxIntf = self.tester.get_local_port(valports[rxPort]) + tgenInput.append((txIntf, rxIntf, "dst%d.pcap" % valports[rxPort-1])) + + + _, pps = self.tester.traffic_generator_throughput(tgenInput, rate_percent=100, delay=60) + self.verify(pps > 0, "No traffic detected") + pps /= 1000000.0 + linerate = self.wirespeed(self.nic, frame_size, self.req_ports) + pct = pps * 100 / linerate + + # Stop l3fwd + l3fwd_session.send_expect("^C", "#") + time.sleep(5) + + data_row = [frame_size, mode, str(pps), str(pct)] + self.result_table_add(data_row) + self.l3fwd_test_results['data'].append(data_row) + + self.dut.close_session(l3fwd_session) + self.result_table_print() + + + def measure_vf_performance(self, host_driver='default'): + """start l3fwd and run the perf test""" + + time.sleep(10) + if host_driver == 'igb_uio': + self.setup_vf_env(host_driver='igb_uio') + else: + self.setup_vf_env(host_driver='') + + vf0_pci = self.sriov_vfs_port_0[0].pci + vf1_pci = self.sriov_vfs_port_1[0].pci + if self.req_ports == 4: + vf2_pci = self.sriov_vfs_port_2[0].pci + vf3_pci = self.sriov_vfs_port_3[0].pci + + #for fvl10g, fvl40g, fvl25g, use 2c/2q per VF port for performance test + if self.nic in ["fortville_25g", "fortville_spirit", "fortville_eagle"]: + + l3fwd_cl = self.cores[2:6] + core_mask = utils.create_mask(l3fwd_cl) + port_mask = utils.create_mask(self.dut_ports) + + cmdline = "./examples/l3fwd/build/l3fwd -c {0} -n 4 -w {1} -w {2} -- -p {3} \ + --config '(0,0,{4}),(0,1,{5}),(1,0,{6}),(1,1,{7})' ". \ + format(core_mask, vf0_pci, vf1_pci, port_mask, l3fwd_cl[0], l3fwd_cl[1], l3fwd_cl[2], l3fwd_cl[3]) + if self.req_ports == 4: + cmdline = "./examples/l3fwd/build/l3fwd -c {0} -n 4 -w {1} -w {2} -w {3} -w {4} -- -p {5} \ + --config '(0,0,{6}),(1,0,{7}),(2,0,{8}),(3,0,{9})' ". \ + format(core_mask, vf0_pci, vf1_pci, vf2_pci, vf3_pci, port_mask, l3fwd_cl[0], l3fwd_cl[1], l3fwd_cl[2], l3fwd_cl[3]) + else: + #for nnt, use 1c/1q per VF port for performance test + l3fwd_cl = self.cores[4:6] + core_mask = utils.create_mask(l3fwd_cl) + cmdline = "./examples/l3fwd/build/l3fwd -c {0} -n 4 -w {1} -w {2} -- -p 0x3 \ + --config '(0,0,{3}),(1,0,{4})' ". \ + format(core_mask, vf0_pci, vf1_pci, l3fwd_cl[0], l3fwd_cl[1]) + + self.perf_test(cmdline) + + def test_perf_a_kernel_pf_dpdk_vf_performance(self): + + self.measure_vf_performance(host_driver='') + + def test_perf_b_dpdk_pf_dpdk_vf_performance(self): + + self.measure_vf_performance(host_driver='igb_uio') + + def tear_down(self): + + if self.setup_vf_env_flag == 1: + self.destroy_vf_env() + + for port_id in self.dut_ports: + self.dut.destroy_sriov_vfs_by_port(port_id) + # DPDK-1754 + intf = self.dut.ports_info[port_id]['intf'] + self.dut.send_expect("ethtool -s %s autoneg on" % intf, "# ") + + def tear_down_all(self): + pass -- 2.7.4