Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/121778/?format=api
https://patches.dpdk.org/api/patches/121778/?format=api", "web_url": "https://patches.dpdk.org/project/dts/patch/20230110164431.19390-7-hongbox.li@intel.com/", "project": { "id": 3, "url": "https://patches.dpdk.org/api/projects/3/?format=api", "name": "DTS", "link_name": "dts", "list_id": "dts.dpdk.org", "list_email": "dts@dpdk.org", "web_url": "", "scm_url": "git://dpdk.org/tools/dts", "webscm_url": "http://git.dpdk.org/tools/dts/", "list_archive_url": "https://inbox.dpdk.org/dts", "list_archive_url_format": "https://inbox.dpdk.org/dts/{}", "commit_url_format": "" }, "msgid": "<20230110164431.19390-7-hongbox.li@intel.com>", "list_archive_url": "https://inbox.dpdk.org/dts/20230110164431.19390-7-hongbox.li@intel.com", "date": "2023-01-10T16:44:29", "name": "[V3,6/8] tests/multiprocess: split performance plan and suite", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "a86c4cb0137a2e3afbcb11fcf955a8f1195b6130", "submitter": { "id": 2804, "url": "https://patches.dpdk.org/api/people/2804/?format=api", "name": "Li, HongboX", "email": "hongbox.li@intel.com" }, "delegate": null, "mbox": "https://patches.dpdk.org/project/dts/patch/20230110164431.19390-7-hongbox.li@intel.com/mbox/", "series": [ { "id": 26458, "url": "https://patches.dpdk.org/api/series/26458/?format=api", "web_url": "https://patches.dpdk.org/project/dts/list/?series=26458", "date": "2023-01-10T16:44:23", "name": "split performance plan and suite", "version": 3, "mbox": "https://patches.dpdk.org/series/26458/mbox/" } ], "comments": "https://patches.dpdk.org/api/patches/121778/comments/", "check": "pending", "checks": "https://patches.dpdk.org/api/patches/121778/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<dts-bounces@dpdk.org>", "X-Original-To": "patchwork@inbox.dpdk.org", "Delivered-To": "patchwork@inbox.dpdk.org", "Received": [ "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id C900B423A1;\n\tTue, 10 Jan 2023 09:25:06 +0100 (CET)", "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id C6E5142D25;\n\tTue, 10 Jan 2023 09:25:06 +0100 (CET)", "from mga07.intel.com (mga07.intel.com [134.134.136.100])\n by mails.dpdk.org (Postfix) with ESMTP id CEF8E42D25\n for <dts@dpdk.org>; Tue, 10 Jan 2023 09:25:04 +0100 (CET)", "from fmsmga001.fm.intel.com ([10.253.24.23])\n by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 10 Jan 2023 00:25:03 -0800", "from unknown (HELO cvl_100g_103.icx.intel.com) ([10.239.252.93])\n by fmsmga001-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 10 Jan 2023 00:25:01 -0800" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple;\n d=intel.com; i=@intel.com; q=dns/txt; s=Intel;\n t=1673339105; x=1704875105;\n h=from:to:cc:subject:date:message-id:in-reply-to:\n references:mime-version:content-transfer-encoding;\n bh=LPynZ5Rs8e6Pe4eWCeLxcI2eCit4DYw5GPYbLo7Jsk4=;\n b=aqAUWUSvN32beEHA9+44pXuv95mtAWlA9037J+VchPU4qggF/rQRBzIS\n wxYSBA4HaOE5++9LXm/3QTet0YhxpI1SK7XjsToelfSMITAFOaOOFWZl3\n zwD6ZTSeRFqDXDZpp6XOry2CgrdLFx62D/ysCPizuEDglJpFnq1LoQ7Cj\n uT5+0v0cPSsc6bFsVIZui3P0tsbMtxDoY+GtZ/+qRmkMOsPUzjgIyhZuB\n Qu2VCgomF4lCWIZY3FatMHAnk+JkF0M4d2hPORT+Qt40Gv3BuGIr61tnk\n xZsenWxgKCvtV6rkboL/AcqfXEW371dIljsv/mhD0fLZMjuSufbFmQp4a w==;", "X-IronPort-AV": [ "E=McAfee;i=\"6500,9779,10585\"; a=\"387543515\"", "E=Sophos;i=\"5.96,314,1665471600\"; d=\"scan'208\";a=\"387543515\"", "E=McAfee;i=\"6500,9779,10585\"; a=\"799339289\"", "E=Sophos;i=\"5.96,314,1665471600\"; d=\"scan'208\";a=\"799339289\"" ], "From": "Hongbo Li <hongbox.li@intel.com>", "To": "dts@dpdk.org", "Cc": "Hongbo Li <hongbox.li@intel.com>", "Subject": "[dts][PATCH V3 6/8] tests/multiprocess: split performance plan and\n suite", "Date": "Wed, 11 Jan 2023 00:44:29 +0800", "Message-Id": "<20230110164431.19390-7-hongbox.li@intel.com>", "X-Mailer": "git-send-email 2.17.1", "In-Reply-To": "<20230110164431.19390-1-hongbox.li@intel.com>", "References": "<20230110164431.19390-1-hongbox.li@intel.com>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=UTF-8", "Content-Transfer-Encoding": "8bit", "X-BeenThere": "dts@dpdk.org", "X-Mailman-Version": "2.1.29", "Precedence": "list", "List-Id": "test suite reviews and discussions <dts.dpdk.org>", "List-Unsubscribe": "<https://mails.dpdk.org/options/dts>,\n <mailto:dts-request@dpdk.org?subject=unsubscribe>", "List-Archive": "<http://mails.dpdk.org/archives/dts/>", "List-Post": "<mailto:dts@dpdk.org>", "List-Help": "<mailto:dts-request@dpdk.org?subject=help>", "List-Subscribe": "<https://mails.dpdk.org/listinfo/dts>,\n <mailto:dts-request@dpdk.org?subject=subscribe>", "Errors-To": "dts-bounces@dpdk.org" }, "content": "split performance plan and suite\n\nSigned-off-by: Hongbo Li <hongbox.li@intel.com>\n---\n test_plans/multiprocess_test_plan.rst | 48 -\n test_plans/perf_multiprocess_test_plan.rst | 141 +++\n tests/TestSuite_multiprocess.py | 210 -----\n tests/TestSuite_perf_multiprocess.py | 994 +++++++++++++++++++++\n 4 files changed, 1135 insertions(+), 258 deletions(-)\n create mode 100644 test_plans/perf_multiprocess_test_plan.rst\n create mode 100644 tests/TestSuite_perf_multiprocess.py", "diff": "diff --git a/test_plans/multiprocess_test_plan.rst b/test_plans/multiprocess_test_plan.rst\nindex c7aae44b..9f5ef8fa 100644\n--- a/test_plans/multiprocess_test_plan.rst\n+++ b/test_plans/multiprocess_test_plan.rst\n@@ -196,27 +196,6 @@ run should remain the same, except for the ``num-procs`` value, which should be\n adjusted appropriately.\n \n \n-Test Case: Performance Tests\n-----------------------------\n-\n-Run the multiprocess application using standard IP traffic - varying source\n-and destination address information to allow RSS to evenly distribute packets\n-among RX queues. Record traffic throughput results as below.\n-\n-+-------------------+-----+-----+-----+-----+-----+-----+\n-| Num-procs | 1 | 2 | 2 | 4 | 4 | 8 |\n-+-------------------+-----+-----+-----+-----+-----+-----+\n-| Cores/Threads | 1/1 | 1/2 | 2/1 | 2/2 | 4/1 | 4/2 |\n-+-------------------+-----+-----+-----+-----+-----+-----+\n-| Num Ports | 2 | 2 | 2 | 2 | 2 | 2 |\n-+-------------------+-----+-----+-----+-----+-----+-----+\n-| Packet Size | 64 | 64 | 64 | 64 | 64 | 64 |\n-+-------------------+-----+-----+-----+-----+-----+-----+\n-| %-age Line Rate | X | X | X | X | X | X |\n-+-------------------+-----+-----+-----+-----+-----+-----+\n-| Packet Rate(mpps) | X | X | X | X | X | X |\n-+-------------------+-----+-----+-----+-----+-----+-----+\n-\n Test Case: Function Tests\n -------------------------\n start 2 symmetric_mp process, send some packets, the number of packets is a random value between 20 and 256.\n@@ -294,33 +273,6 @@ An example commands to run 8 client processes is as follows::\n root@host:mp_client# ./x86_64-native-linuxapp-gcc/examples/dpdk-mp_client -c 40000 --proc-type=secondary -- -n 6 &\n root@host:mp_client# ./x86_64-native-linuxapp-gcc/examples/dpdk-mp_client -c 100000 --proc-type=secondary -- -n 7 &\n \n-Test Case: Performance Measurement\n-----------------------------------\n-\n-- On the traffic generator set up a traffic flow in both directions specifying\n- IP traffic.\n-- Run the server and client applications as above.\n-- Start the traffic and record the throughput for transmitted and received packets.\n-\n-An example set of results is shown below.\n-\n-+----------------------+-----+-----+-----+-----+-----+-----+\n-| Server threads | 1 | 1 | 1 | 1 | 1 | 1 |\n-+----------------------+-----+-----+-----+-----+-----+-----+\n-| Server Cores/Threads | 1/1 | 1/1 | 1/1 | 1/1 | 1/1 | 1/1 |\n-+----------------------+-----+-----+-----+-----+-----+-----+\n-| Num-clients | 1 | 2 | 2 | 4 | 4 | 8 |\n-+----------------------+-----+-----+-----+-----+-----+-----+\n-| Client Cores/Threads | 1/1 | 1/2 | 2/1 | 2/2 | 4/1 | 4/2 |\n-+----------------------+-----+-----+-----+-----+-----+-----+\n-| Num Ports | 2 | 2 | 2 | 2 | 2 | 2 |\n-+----------------------+-----+-----+-----+-----+-----+-----+\n-| Packet Size | 64 | 64 | 64 | 64 | 64 | 64 |\n-+----------------------+-----+-----+-----+-----+-----+-----+\n-| %-age Line Rate | X | X | X | X | X | X |\n-+----------------------+-----+-----+-----+-----+-----+-----+\n-| Packet Rate(mpps) | X | X | X | X | X | X |\n-+----------------------+-----+-----+-----+-----+-----+-----+\n \n Test Case: Function Tests\n -------------------------\ndiff --git a/test_plans/perf_multiprocess_test_plan.rst b/test_plans/perf_multiprocess_test_plan.rst\nnew file mode 100644\nindex 00000000..c1e7ff87\n--- /dev/null\n+++ b/test_plans/perf_multiprocess_test_plan.rst\n@@ -0,0 +1,141 @@\n+.. SPDX-License-Identifier: BSD-3-Clause\n+ Copyright(c) 2010-2017 Intel Corporation\n+\n+=======================================\n+Sample Application Tests: Multi-Process\n+=======================================\n+\n+Simple MP Application Test\n+==========================\n+\n+Description\n+-----------\n+\n+This test is a basic multi-process test which demonstrates the basics of sharing\n+information between DPDK processes. The same application binary is run\n+twice - once as a primary instance, and once as a secondary instance. Messages\n+are sent from primary to secondary and vice versa, demonstrating the processes\n+are sharing memory and can communicate using rte_ring structures.\n+\n+Prerequisites\n+-------------\n+\n+If using vfio the kernel must be >= 3.6+ and VT-d must be enabled in bios.When\n+using vfio, use the following commands to load the vfio driver and bind it\n+to the device under test::\n+\n+ modprobe vfio\n+ modprobe vfio-pci\n+ usertools/dpdk-devbind.py --bind=vfio-pci device_bus_id\n+\n+Assuming that a DPDK build has been set up and the multi-process sample\n+applications have been built.\n+\n+\n+Test Case: Performance Tests\n+----------------------------\n+\n+Run the multiprocess application using standard IP traffic - varying source\n+and destination address information to allow RSS to evenly distribute packets\n+among RX queues. Record traffic throughput results as below.\n+\n++-------------------+-----+-----+-----+-----+-----+-----+\n+| Num-procs | 1 | 2 | 2 | 4 | 4 | 8 |\n++-------------------+-----+-----+-----+-----+-----+-----+\n+| Cores/Threads | 1/1 | 1/2 | 2/1 | 2/2 | 4/1 | 4/2 |\n++-------------------+-----+-----+-----+-----+-----+-----+\n+| Num Ports | 2 | 2 | 2 | 2 | 2 | 2 |\n++-------------------+-----+-----+-----+-----+-----+-----+\n+| Packet Size | 64 | 64 | 64 | 64 | 64 | 64 |\n++-------------------+-----+-----+-----+-----+-----+-----+\n+| %-age Line Rate | X | X | X | X | X | X |\n++-------------------+-----+-----+-----+-----+-----+-----+\n+| Packet Rate(mpps) | X | X | X | X | X | X |\n++-------------------+-----+-----+-----+-----+-----+-----+\n+\n+\n+Client Server Multiprocess Tests\n+================================\n+\n+Description\n+-----------\n+\n+The client-server sample application demonstrates the ability of Intel� DPDK\n+to use multiple processes in which a server process performs packet I/O and one\n+or multiple client processes perform packet processing. The server process\n+controls load balancing on the traffic received from a number of input ports to\n+a user-specified number of clients. The client processes forward the received\n+traffic, outputting the packets directly by writing them to the TX rings of the\n+outgoing ports.\n+\n+Prerequisites\n+-------------\n+\n+Assuming that an Intel� DPDK build has been set up and the multi-process\n+sample application has been built.\n+Also assuming a traffic generator is connected to the ports \"0\" and \"1\".\n+\n+It is important to run the server application before the client application,\n+as the server application manages both the NIC ports with packet transmission\n+and reception, as well as shared memory areas and client queues.\n+\n+Run the Server Application:\n+\n+- Provide the core mask on which the server process is to run using -c, e.g. -c 3 (bitmask number).\n+- Set the number of ports to be engaged using -p, e.g. -p 3 refers to ports 0 & 1.\n+- Define the maximum number of clients using -n, e.g. -n 8.\n+\n+The command line below is an example on how to start the server process on\n+logical core 2 to handle a maximum of 8 client processes configured to\n+run on socket 0 to handle traffic from NIC ports 0 and 1::\n+\n+ root@host:mp_server# ./x86_64-native-linuxapp-gcc/examples/dpdk-mp_server -c 2 -- -p 3 -n 8\n+\n+NOTE: If an additional second core is given in the coremask to the server process\n+that second core will be used to print statistics. When benchmarking, only a\n+single lcore is needed for the server process\n+\n+Run the Client application:\n+\n+- In another terminal run the client application.\n+- Give each client a distinct core mask with -c.\n+- Give each client a unique client-id with -n.\n+\n+An example commands to run 8 client processes is as follows::\n+\n+ root@host:mp_client# ./x86_64-native-linuxapp-gcc/examples/dpdk-mp_client -c 40 --proc-type=secondary -- -n 0 &\n+ root@host:mp_client# ./x86_64-native-linuxapp-gcc/examples/dpdk-mp_client -c 100 --proc-type=secondary -- -n 1 &\n+ root@host:mp_client# ./x86_64-native-linuxapp-gcc/examples/dpdk-mp_client -c 400 --proc-type=secondary -- -n 2 &\n+ root@host:mp_client# ./x86_64-native-linuxapp-gcc/examples/dpdk-mp_client -c 1000 --proc-type=secondary -- -n 3 &\n+ root@host:mp_client# ./x86_64-native-linuxapp-gcc/examples/dpdk-mp_client -c 4000 --proc-type=secondary -- -n 4 &\n+ root@host:mp_client# ./x86_64-native-linuxapp-gcc/examples/dpdk-mp_client -c 10000 --proc-type=secondary -- -n 5 &\n+ root@host:mp_client# ./x86_64-native-linuxapp-gcc/examples/dpdk-mp_client -c 40000 --proc-type=secondary -- -n 6 &\n+ root@host:mp_client# ./x86_64-native-linuxapp-gcc/examples/dpdk-mp_client -c 100000 --proc-type=secondary -- -n 7 &\n+\n+Test Case: Performance Measurement\n+----------------------------------\n+\n+- On the traffic generator set up a traffic flow in both directions specifying\n+ IP traffic.\n+- Run the server and client applications as above.\n+- Start the traffic and record the throughput for transmitted and received packets.\n+\n+An example set of results is shown below.\n+\n++----------------------+-----+-----+-----+-----+-----+-----+\n+| Server threads | 1 | 1 | 1 | 1 | 1 | 1 |\n++----------------------+-----+-----+-----+-----+-----+-----+\n+| Server Cores/Threads | 1/1 | 1/1 | 1/1 | 1/1 | 1/1 | 1/1 |\n++----------------------+-----+-----+-----+-----+-----+-----+\n+| Num-clients | 1 | 2 | 2 | 4 | 4 | 8 |\n++----------------------+-----+-----+-----+-----+-----+-----+\n+| Client Cores/Threads | 1/1 | 1/2 | 2/1 | 2/2 | 4/1 | 4/2 |\n++----------------------+-----+-----+-----+-----+-----+-----+\n+| Num Ports | 2 | 2 | 2 | 2 | 2 | 2 |\n++----------------------+-----+-----+-----+-----+-----+-----+\n+| Packet Size | 64 | 64 | 64 | 64 | 64 | 64 |\n++----------------------+-----+-----+-----+-----+-----+-----+\n+| %-age Line Rate | X | X | X | X | X | X |\n++----------------------+-----+-----+-----+-----+-----+-----+\n+| Packet Rate(mpps) | X | X | X | X | X | X |\n++----------------------+-----+-----+-----+-----+-----+-----+\n\\ No newline at end of file\ndiff --git a/tests/TestSuite_multiprocess.py b/tests/TestSuite_multiprocess.py\nindex 099ce6e7..a52622c9 100644\n--- a/tests/TestSuite_multiprocess.py\n+++ b/tests/TestSuite_multiprocess.py\n@@ -1714,216 +1714,6 @@ class TestMultiprocess(TestCase):\n \"core dump\" not in out, \"Core dump occurred in the secondary process!!!\"\n )\n \n- def test_perf_multiprocess_performance(self):\n- \"\"\"\n- Benchmark Multiprocess performance.\n- #\"\"\"\n- packet_count = 16\n- self.dut.send_expect(\"fg\", \"# \")\n- txPort = self.tester.get_local_port(self.dut_ports[0])\n- rxPort = self.tester.get_local_port(self.dut_ports[1])\n- mac = self.tester.get_mac(txPort)\n- dmac = self.dut.get_mac_address(self.dut_ports[0])\n- tgenInput = []\n-\n- # create mutative src_ip+dst_ip package\n- for i in range(packet_count):\n- package = (\n- r'flows = [Ether(src=\"%s\", dst=\"%s\")/IP(src=\"192.168.1.%d\", dst=\"192.168.1.%d\")/(\"X\"*26)]'\n- % (mac, dmac, i + 1, i + 2)\n- )\n- self.tester.scapy_append(package)\n- pcap = os.sep.join([self.output_path, \"test_%d.pcap\" % i])\n- self.tester.scapy_append('wrpcap(\"%s\", flows)' % pcap)\n- tgenInput.append([txPort, rxPort, pcap])\n- self.tester.scapy_execute()\n-\n- # run multiple symmetric_mp process\n- validExecutions = []\n- for execution in executions:\n- if len(self.dut.get_core_list(execution[\"cores\"])) == execution[\"nprocs\"]:\n- validExecutions.append(execution)\n-\n- portMask = utils.create_mask(self.dut_ports)\n-\n- for n in range(len(validExecutions)):\n- execution = validExecutions[n]\n- # get coreList form execution['cores']\n- coreList = self.dut.get_core_list(execution[\"cores\"], socket=self.socket)\n- # to run a set of symmetric_mp instances, like test plan\n- dutSessionList = []\n- for index in range(len(coreList)):\n- dut_new_session = self.dut.new_session()\n- dutSessionList.append(dut_new_session)\n- # add -a option when tester and dut in same server\n- dut_new_session.send_expect(\n- self.app_symmetric_mp\n- + \" -c %s --proc-type=auto %s -- -p %s --num-procs=%d --proc-id=%d\"\n- % (\n- utils.create_mask([coreList[index]]),\n- self.eal_param,\n- portMask,\n- execution[\"nprocs\"],\n- index,\n- ),\n- \"Finished Process Init\",\n- )\n-\n- # clear streams before add new streams\n- self.tester.pktgen.clear_streams()\n- # run packet generator\n- streams = self.pktgen_helper.prepare_stream_from_tginput(\n- tgenInput, 100, None, self.tester.pktgen\n- )\n- _, pps = self.tester.pktgen.measure_throughput(stream_ids=streams)\n-\n- execution[\"pps\"] = pps\n-\n- # close all symmetric_mp process\n- self.dut.send_expect(\"killall symmetric_mp\", \"# \")\n- # close all dut sessions\n- for dut_session in dutSessionList:\n- self.dut.close_session(dut_session)\n-\n- # get rate and mpps data\n- for n in range(len(executions)):\n- self.verify(executions[n][\"pps\"] is not 0, \"No traffic detected\")\n- self.result_table_create(\n- [\n- \"Num-procs\",\n- \"Sockets/Cores/Threads\",\n- \"Num Ports\",\n- \"Frame Size\",\n- \"%-age Line Rate\",\n- \"Packet Rate(mpps)\",\n- ]\n- )\n-\n- for execution in validExecutions:\n- self.result_table_add(\n- [\n- execution[\"nprocs\"],\n- execution[\"cores\"],\n- 2,\n- 64,\n- execution[\"pps\"] / float(100000000 / (8 * 84)),\n- execution[\"pps\"] / float(1000000),\n- ]\n- )\n-\n- self.result_table_print()\n-\n- def test_perf_multiprocess_client_serverperformance(self):\n- \"\"\"\n- Benchmark Multiprocess client-server performance.\n- \"\"\"\n- self.dut.kill_all()\n- self.dut.send_expect(\"fg\", \"# \")\n- txPort = self.tester.get_local_port(self.dut_ports[0])\n- rxPort = self.tester.get_local_port(self.dut_ports[1])\n- mac = self.tester.get_mac(txPort)\n-\n- self.tester.scapy_append(\n- 'dmac=\"%s\"' % self.dut.get_mac_address(self.dut_ports[0])\n- )\n- self.tester.scapy_append('smac=\"%s\"' % mac)\n- self.tester.scapy_append(\n- 'flows = [Ether(src=smac, dst=dmac)/IP(src=\"192.168.1.1\", dst=\"192.168.1.1\")/(\"X\"*26)]'\n- )\n-\n- pcap = os.sep.join([self.output_path, \"test.pcap\"])\n- self.tester.scapy_append('wrpcap(\"%s\", flows)' % pcap)\n- self.tester.scapy_execute()\n-\n- validExecutions = []\n- for execution in executions:\n- if len(self.dut.get_core_list(execution[\"cores\"])) == execution[\"nprocs\"]:\n- validExecutions.append(execution)\n-\n- for execution in validExecutions:\n- coreList = self.dut.get_core_list(execution[\"cores\"], socket=self.socket)\n- # get core with socket parameter to specified which core dut used when tester and dut in same server\n- coreMask = utils.create_mask(\n- self.dut.get_core_list(\"1S/1C/1T\", socket=self.socket)\n- )\n- portMask = utils.create_mask(self.dut_ports)\n- # specified mp_server core and add -a option when tester and dut in same server\n- self.dut.send_expect(\n- self.app_mp_server\n- + \" -n %d -c %s %s -- -p %s -n %d\"\n- % (\n- self.dut.get_memory_channels(),\n- coreMask,\n- self.eal_param,\n- portMask,\n- execution[\"nprocs\"],\n- ),\n- \"Finished Process Init\",\n- 20,\n- )\n- self.dut.send_expect(\"^Z\", \"\\r\\n\")\n- self.dut.send_expect(\"bg\", \"# \")\n-\n- for n in range(execution[\"nprocs\"]):\n- time.sleep(5)\n- # use next core as mp_client core, different from mp_server\n- coreMask = utils.create_mask([str(int(coreList[n]) + 1)])\n- self.dut.send_expect(\n- self.app_mp_client\n- + \" -n %d -c %s --proc-type=secondary %s -- -n %d\"\n- % (self.dut.get_memory_channels(), coreMask, self.eal_param, n),\n- \"Finished Process Init\",\n- )\n- self.dut.send_expect(\"^Z\", \"\\r\\n\")\n- self.dut.send_expect(\"bg\", \"# \")\n-\n- tgenInput = []\n- tgenInput.append([txPort, rxPort, pcap])\n-\n- # clear streams before add new streams\n- self.tester.pktgen.clear_streams()\n- # run packet generator\n- streams = self.pktgen_helper.prepare_stream_from_tginput(\n- tgenInput, 100, None, self.tester.pktgen\n- )\n- _, pps = self.tester.pktgen.measure_throughput(stream_ids=streams)\n-\n- execution[\"pps\"] = pps\n- self.dut.kill_all()\n- time.sleep(5)\n-\n- for n in range(len(executions)):\n- self.verify(executions[n][\"pps\"] is not 0, \"No traffic detected\")\n-\n- self.result_table_create(\n- [\n- \"Server threads\",\n- \"Server Cores/Threads\",\n- \"Num-procs\",\n- \"Sockets/Cores/Threads\",\n- \"Num Ports\",\n- \"Frame Size\",\n- \"%-age Line Rate\",\n- \"Packet Rate(mpps)\",\n- ]\n- )\n-\n- for execution in validExecutions:\n- self.result_table_add(\n- [\n- 1,\n- \"1S/1C/1T\",\n- execution[\"nprocs\"],\n- execution[\"cores\"],\n- 2,\n- 64,\n- execution[\"pps\"] / float(100000000 / (8 * 84)),\n- execution[\"pps\"] / float(1000000),\n- ]\n- )\n-\n- self.result_table_print()\n-\n def set_fields(self):\n \"\"\"set ip protocol field behavior\"\"\"\n fields_config = {\ndiff --git a/tests/TestSuite_perf_multiprocess.py b/tests/TestSuite_perf_multiprocess.py\nnew file mode 100644\nindex 00000000..179574a5\n--- /dev/null\n+++ b/tests/TestSuite_perf_multiprocess.py\n@@ -0,0 +1,994 @@\n+# SPDX-License-Identifier: BSD-3-Clause\n+# Copyright(c) 2010-2014 Intel Corporation\n+#\n+\n+\"\"\"\n+DPDK Test suite.\n+Multi-process Test.\n+\"\"\"\n+\n+import copy\n+import os\n+import random\n+import re\n+import time\n+import traceback\n+from collections import OrderedDict\n+\n+import framework.utils as utils\n+from framework.exception import VerifyFailure\n+from framework.packet import Packet\n+from framework.pktgen import PacketGeneratorHelper\n+from framework.pmd_output import PmdOutput\n+from framework.test_case import TestCase, check_supported_nic\n+from framework.utils import GREEN, RED\n+\n+from .rte_flow_common import FdirProcessing as fdirprocess\n+from .rte_flow_common import RssProcessing as rssprocess\n+\n+executions = []\n+\n+\n+class TestMultiprocess(TestCase):\n+\n+ support_nic = [\"ICE_100G-E810C_QSFP\", \"ICE_25G-E810C_SFP\", \"ICE_25G-E810_XXV_SFP\"]\n+\n+ def set_up_all(self):\n+ \"\"\"\n+ Run at the start of each test suite.\n+\n+ Multiprocess prerequisites.\n+ Requirements:\n+ OS is not freeBSD\n+ DUT core number >= 4\n+ multi_process build pass\n+ \"\"\"\n+ # self.verify('bsdapp' not in self.target, \"Multiprocess not support freebsd\")\n+\n+ self.verify(len(self.dut.get_all_cores()) >= 4, \"Not enough Cores\")\n+ self.pkt = Packet()\n+ self.dut_ports = self.dut.get_ports()\n+ self.socket = self.dut.get_numa_id(self.dut_ports[0])\n+ extra_option = \"-Dexamples='multi_process/client_server_mp/mp_server,multi_process/client_server_mp/mp_client,multi_process/simple_mp,multi_process/symmetric_mp'\"\n+ self.dut.build_install_dpdk(target=self.target, extra_options=extra_option)\n+ self.app_mp_client = self.dut.apps_name[\"mp_client\"]\n+ self.app_mp_server = self.dut.apps_name[\"mp_server\"]\n+ self.app_simple_mp = self.dut.apps_name[\"simple_mp\"]\n+ self.app_symmetric_mp = self.dut.apps_name[\"symmetric_mp\"]\n+\n+ executions.append({\"nprocs\": 1, \"cores\": \"1S/1C/1T\", \"pps\": 0})\n+ executions.append({\"nprocs\": 2, \"cores\": \"1S/1C/2T\", \"pps\": 0})\n+ executions.append({\"nprocs\": 2, \"cores\": \"1S/2C/1T\", \"pps\": 0})\n+ executions.append({\"nprocs\": 4, \"cores\": \"1S/2C/2T\", \"pps\": 0})\n+ executions.append({\"nprocs\": 4, \"cores\": \"1S/4C/1T\", \"pps\": 0})\n+ executions.append({\"nprocs\": 8, \"cores\": \"1S/4C/2T\", \"pps\": 0})\n+\n+ self.eal_param = \"\"\n+ for i in self.dut_ports:\n+ self.eal_param += \" -a %s\" % self.dut.ports_info[i][\"pci\"]\n+\n+ self.eal_para = self.dut.create_eal_parameters(cores=\"1S/2C/1T\")\n+ # start new session to run secondary\n+ self.session_secondary = self.dut.new_session()\n+\n+ # get dts output path\n+ if self.logger.log_path.startswith(os.sep):\n+ self.output_path = self.logger.log_path\n+ else:\n+ cur_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))\n+ self.output_path = os.sep.join([cur_path, self.logger.log_path])\n+ # create an instance to set stream field setting\n+ self.pktgen_helper = PacketGeneratorHelper()\n+ self.dport_info0 = self.dut.ports_info[self.dut_ports[0]]\n+ self.pci0 = self.dport_info0[\"pci\"]\n+ self.tester_ifaces = [\n+ self.tester.get_interface(self.dut.ports_map[port])\n+ for port in self.dut_ports\n+ ]\n+ rxq = 1\n+ self.session_list = []\n+ self.logfmt = \"*\" * 20\n+\n+ def set_up(self):\n+ \"\"\"\n+ Run before each test case.\n+ \"\"\"\n+ pass\n+\n+ def launch_multi_testpmd(self, proc_type, queue_num, process_num, **kwargs):\n+ self.session_list = [\n+ self.dut.new_session(\"process_{}\".format(i)) for i in range(process_num)\n+ ]\n+ self.pmd_output_list = [\n+ PmdOutput(self.dut, self.session_list[i]) for i in range(process_num)\n+ ]\n+ self.dut.init_reserved_core()\n+ proc_type_list = []\n+ self.out_list = []\n+ if isinstance(proc_type, list):\n+ proc_type_list = copy.deepcopy(proc_type)\n+ proc_type = proc_type_list[0]\n+ for i in range(process_num):\n+ cores = self.dut.get_reserved_core(\"2C\", socket=0)\n+ if i != 0 and proc_type_list:\n+ proc_type = proc_type_list[1]\n+ eal_param = \"--proc-type={} -a {} --log-level=ice,7\".format(\n+ proc_type, self.pci0\n+ )\n+ param = \"--rxq={0} --txq={0} --num-procs={1} --proc-id={2}\".format(\n+ queue_num, process_num, i\n+ )\n+ if kwargs.get(\"options\") is not None:\n+ param = \"\".join([param, kwargs.get(\"options\")])\n+ out = self.pmd_output_list[i].start_testpmd(\n+ cores=cores,\n+ eal_param=eal_param,\n+ param=param,\n+ timeout=kwargs.get(\"timeout\", 20),\n+ )\n+ self.out_list.append(out)\n+ self.pmd_output_list[i].execute_cmd(\"set fwd rxonly\")\n+ self.pmd_output_list[i].execute_cmd(\"set verbose 1\")\n+ self.pmd_output_list[i].execute_cmd(\"start\")\n+ self.pmd_output_list[i].execute_cmd(\"clear port stats all\")\n+\n+ def get_pkt_statistic_process(self, out, **kwargs):\n+ \"\"\"\n+ :param out: information received by testpmd process after sending packets and port statistics\n+ :return: forward statistic dict, eg: {'rx-packets':1, 'tx-packets:0, 'tx-dropped':1}\n+ \"\"\"\n+ p = re.compile(\n+ r\"Forward\\s+Stats\\s+for\\s+RX\\s+Port=\\s+{}/Queue=([\\s\\d+]\\d+)\\s+.*\\n.*RX-packets:\\s+(\\d+)\\s+TX-packets:\\s+(\\d+)\\s+TX-dropped:\\s+(\\d+)\\s\".format(\n+ kwargs.get(\"port_id\")\n+ )\n+ )\n+ item_name = [\"rx-packets\", \"tx-packets\", \"tx-dropped\"]\n+ statistic = p.findall(out)\n+ if statistic:\n+ rx_pkt_total, tx_pkt_total, tx_drop_total = 0, 0, 0\n+ queue_set = set()\n+ for item in statistic:\n+ queue, rx_pkt, tx_pkt, tx_drop = map(int, item)\n+ queue_set.add(queue)\n+ rx_pkt_total += rx_pkt\n+ tx_pkt_total += tx_pkt\n+ tx_drop_total += tx_drop\n+ static_dict = {\n+ k: v\n+ for k, v in zip(item_name, [rx_pkt_total, tx_pkt_total, tx_drop_total])\n+ }\n+ static_dict[\"queue\"] = queue_set\n+ return static_dict\n+ else:\n+ raise Exception(\"got wrong output, not match pattern {}\".format(p.pattern))\n+\n+ def random_packet(self, pkt_num):\n+ pkt = Packet()\n+ if self.kdriver == \"i40e\":\n+ pkt.generate_random_pkts(\n+ pktnum=pkt_num,\n+ dstmac=\"00:11:22:33:44:55\",\n+ random_type=[\"IP_RAW\", \"IPv6_RAW\"],\n+ )\n+ else:\n+ pkt.generate_random_pkts(\n+ pktnum=pkt_num,\n+ dstmac=\"00:11:22:33:44:55\",\n+ )\n+ pkt.send_pkt(crb=self.tester, tx_port=self.tester_ifaces[0], count=1)\n+\n+ def specify_packet(self, que_num):\n+ # create rule to set queue as one of each process queues\n+ rule_str = \"flow create 0 ingress pattern eth / ipv4 src is 192.168.{0}.3 / end actions queue index {0} / end\"\n+ rules = [rule_str.format(i) for i in range(que_num)]\n+ fdirprocess(\n+ self, self.pmd_output_list[0], self.tester_ifaces, rxq=que_num\n+ ).create_rule(rules)\n+ # send 1 packet for each queue,the number of packets should be received by each process is (queue_num/proc_num)\n+ pkt = Packet()\n+ pkt_num = que_num\n+ self.logger.info(\"packet num:{}\".format(pkt_num))\n+ packets = [\n+ 'Ether(dst=\"00:11:22:33:44:55\") / IP(src=\"192.168.{0}.3\", dst=\"192.168.0.21\") / Raw(\"x\" * 80)'.format(\n+ i\n+ )\n+ for i in range(pkt_num)\n+ ]\n+ pkt.update_pkt(packets)\n+ pkt.send_pkt(crb=self.tester, tx_port=self.tester_ifaces[0], count=1)\n+\n+ def _multiprocess_data_pass(self, case):\n+ que_num, proc_num = case.get(\"queue_num\"), case.get(\"proc_num\")\n+ pkt_num = case.setdefault(\"pkt_num\", que_num)\n+ step = int(que_num / proc_num)\n+ proc_queue = [set(range(i, i + step)) for i in range(0, que_num, step)]\n+ queue_dict = {\n+ k: v\n+ for k, v in zip(\n+ [\"process_{}\".format(i) for i in range(que_num)], proc_queue\n+ )\n+ }\n+ # start testpmd multi-process\n+ self.launch_multi_testpmd(\n+ proc_type=case.get(\"proc_type\"), queue_num=que_num, process_num=proc_num\n+ )\n+ # send random or specify packets\n+ packet_func = getattr(self, case.get(\"packet_type\") + \"_packet\")\n+ packet_func(pkt_num)\n+ # get output for each process\n+ process_static = {}\n+ for i in range(len(self.pmd_output_list)):\n+ out = self.pmd_output_list[i].execute_cmd(\"stop\")\n+ static = self.get_pkt_statistic_process(out, port_id=0)\n+ process_static[\"process_{}\".format(i)] = static\n+ self.logger.info(\"process output static:{}\".format(process_static))\n+ # check whether each process receives packet, and ecah process receives packets with the corresponding queue\n+ for k, v in process_static.items():\n+ self.verify(\n+ v.get(\"rx-packets\") > 0,\n+ \"fail:process:{} does not receive packet\".format(k),\n+ )\n+ self.verify(\n+ v.get(\"queue\").issubset(queue_dict.get(k)),\n+ \"fail: {} is not a subset of {}, \"\n+ \"process should use its own queues\".format(\n+ v.get(\"queue\"), queue_dict.get(k)\n+ ),\n+ )\n+ self.logger.info(\"pass:each process receives packets and uses its own queue\")\n+ # check whether the sum of packets received by all processes is equal to the number of packets sent\n+ received_pkts = sum(\n+ int(v.get(\"rx-packets\", 0)) for v in process_static.values()\n+ )\n+ self.verify(\n+ received_pkts == pkt_num,\n+ \"the number of packets received is not equal to packets sent,\"\n+ \"send packet:{}, received packet:{}\".format(pkt_num, received_pkts),\n+ )\n+ self.logger.info(\n+ \"pass:the number of packets received is {}, equal to packets sent\".format(\n+ received_pkts\n+ )\n+ )\n+\n+ def check_rss(self, out, **kwargs):\n+ \"\"\"\n+ check whether the packet directed by rss or not according to the specified parameters\n+ :param out: information received by testpmd after sending packets and port statistics\n+ :param kwargs: some specified parameters, such as: rxq, stats\n+ :return: queue value list\n+ usage:\n+ check_rss(out, rxq=rxq, stats=stats)\n+ \"\"\"\n+ self.logger.info(\"{0} check rss {0}\".format(self.logfmt))\n+ rxq = kwargs.get(\"rxq\")\n+ p = re.compile(\"RSS\\shash=(\\w+)\\s-\\sRSS\\squeue=(\\w+)\")\n+ pkt_info = p.findall(out)\n+ self.verify(\n+ pkt_info,\n+ \"no information matching the pattern was found,pattern:{}\".format(\n+ p.pattern\n+ ),\n+ )\n+ pkt_queue = set([int(i[1], 16) for i in pkt_info])\n+ if kwargs.get(\"stats\"):\n+ self.verify(\n+ all([int(i[0], 16) % rxq == int(i[1], 16) for i in pkt_info]),\n+ \"some pkt not directed by rss.\",\n+ )\n+ self.logger.info((GREEN(\"pass: all pkts directed by rss\")))\n+ else:\n+ self.verify(\n+ not any([int(i[0], 16) % rxq == int(i[1], 16) for i in pkt_info]),\n+ \"some pkt directed by rss, expect not directed by rss\",\n+ )\n+ self.logger.info((GREEN(\"pass: no pkt directed by rss\")))\n+ return pkt_queue\n+\n+ def check_queue(self, out, check_param, **kwargs):\n+ \"\"\"\n+ verify that queue value matches the expected value\n+ :param out: information received by testpmd after sending packets and port statistics\n+ :param check_param: check item name and value, eg\n+ \"check_param\": {\"port_id\": 0, \"queue\": 2}\n+ :param kwargs: some specified parameters, such as: pkt_num, port_id, stats\n+ :return:\n+ \"\"\"\n+ self.logger.info(\"{0} check queue {0}\".format(self.logfmt))\n+ queue = check_param[\"queue\"]\n+ if isinstance(check_param[\"queue\"], int):\n+ queue = [queue]\n+ patt = re.compile(\n+ r\"port\\s+{}/queue(.+?):\\s+received\\s+(\\d+)\\s+packets\".format(\n+ kwargs.get(\"port_id\")\n+ )\n+ )\n+ res = patt.findall(out)\n+ if res:\n+ pkt_queue = set([int(i[0]) for i in res])\n+ if kwargs.get(\"stats\"):\n+ self.verify(\n+ all(q in queue for q in pkt_queue),\n+ \"fail: queue id not matched, expect queue {}, got {}\".format(\n+ queue, pkt_queue\n+ ),\n+ )\n+ self.logger.info((GREEN(\"pass: queue id {} matched\".format(pkt_queue))))\n+ else:\n+ try:\n+ self.verify(\n+ not any(q in queue for q in pkt_queue),\n+ \"fail: queue id should not matched, {} should not in {}\".format(\n+ pkt_queue, queue\n+ ),\n+ )\n+ self.logger.info(\n+ (GREEN(\"pass: queue id {} not matched\".format(pkt_queue)))\n+ )\n+ except VerifyFailure:\n+ self.logger.info(\n+ \"queue id {} contains the queue {} specified in rule, so need to check\"\n+ \" whether the packet directed by rss or not\".format(\n+ pkt_queue, queue\n+ )\n+ )\n+ # for mismatch packet the 'stats' parameter is False, need to change to True\n+ kwargs[\"stats\"] = True\n+ self.check_rss(out, **kwargs)\n+\n+ else:\n+ raise Exception(\"got wrong output, not match pattern\")\n+\n+ def check_mark_id(self, out, check_param, **kwargs):\n+ \"\"\"\n+ verify that the mark ID matches the expected value\n+ :param out: information received by testpmd after sending packets\n+ :param check_param: check item name and value, eg\n+ \"check_param\": {\"port_id\": 0, \"mark_id\": 1}\n+ :param kwargs: some specified parameters,eg: stats\n+ :return: None\n+ usage:\n+ check_mark_id(out, check_param, stats=stats)\n+ \"\"\"\n+ self.logger.info(\"{0} check mark id {0}\".format(self.logfmt))\n+ fdir_scanner = re.compile(\"FDIR matched ID=(0x\\w+)\")\n+ all_mark = fdir_scanner.findall(out)\n+ stats = kwargs.get(\"stats\")\n+ if stats:\n+ mark_list = set(int(i, 16) for i in all_mark)\n+ self.verify(\n+ all([i == check_param[\"mark_id\"] for i in mark_list]) and mark_list,\n+ \"failed: some packet mark id of {} not match expect {}\".format(\n+ mark_list, check_param[\"mark_id\"]\n+ ),\n+ )\n+ self.logger.info((GREEN(\"pass: all packets mark id are matched \")))\n+ else:\n+ # for mismatch packet,verify no mark id in output of received packet\n+ self.verify(\n+ not all_mark, \"mark id {} in output, expect no mark id\".format(all_mark)\n+ )\n+ self.logger.info((GREEN(\"pass: no mark id in output\")))\n+\n+ def check_drop(self, out, **kwargs):\n+ \"\"\"\n+ check the drop number of packets according to the specified parameters\n+ :param out: information received by testpmd after sending packets and port statistics\n+ :param kwargs: some specified parameters, such as: pkt_num, port_id, stats\n+ :return: None\n+ usage:\n+ chek_drop(out, pkt_num=pkt_num, port_id=portid, stats=stats)\n+ \"\"\"\n+ self.logger.info(\"{0} check drop {0}\".format(self.logfmt))\n+ pkt_num = kwargs.get(\"pkt_num\")\n+ stats = kwargs.get(\"stats\")\n+ res = self.get_pkt_statistic(out, **kwargs)\n+ self.verify(\n+ pkt_num == res[\"rx-total\"],\n+ \"failed: get wrong amount of packet {}, expected {}\".format(\n+ res[\"rx-total\"], pkt_num\n+ ),\n+ )\n+ drop_packet_num = res[\"rx-dropped\"]\n+ if stats:\n+ self.verify(\n+ drop_packet_num == pkt_num,\n+ \"failed: {} packet dropped,expect {} dropped\".format(\n+ drop_packet_num, pkt_num\n+ ),\n+ )\n+ self.logger.info(\n+ (\n+ GREEN(\n+ \"pass: drop packet number {} is matched\".format(drop_packet_num)\n+ )\n+ )\n+ )\n+ else:\n+ self.verify(\n+ drop_packet_num == 0 and res[\"rx-packets\"] == pkt_num,\n+ \"failed: {} packet dropped, expect 0 packet dropped\".format(\n+ drop_packet_num\n+ ),\n+ )\n+ self.logger.info(\n+ (\n+ GREEN(\n+ \"pass: drop packet number {} is matched\".format(drop_packet_num)\n+ )\n+ )\n+ )\n+\n+ @staticmethod\n+ def get_pkt_statistic(out, **kwargs):\n+ \"\"\"\n+ :param out: information received by testpmd after sending packets and port statistics\n+ :return: rx statistic dict, eg: {'rx-packets':1, 'rx-dropped':0, 'rx-total':1}\n+ \"\"\"\n+ p = re.compile(\n+ r\"Forward\\sstatistics\\s+for\\s+port\\s+{}\\s+.*\\n.*RX-packets:\\s(\\d+)\\s+RX-dropped:\\s(\\d+)\\s+RX-total:\\s(\\d+)\\s\".format(\n+ kwargs.get(\"port_id\")\n+ )\n+ )\n+ item_name = [\"rx-packets\", \"rx-dropped\", \"rx-total\"]\n+ statistic = p.findall(out)\n+ if statistic:\n+ static_dict = {\n+ k: v for k, v in zip(item_name, list(map(int, list(statistic[0]))))\n+ }\n+ return static_dict\n+ else:\n+ raise Exception(\n+ \"got wrong output, not match pattern {}\".format(p.pattern).replace(\n+ \"\\\\\\\\\", \"\\\\\"\n+ )\n+ )\n+\n+ def send_pkt_get_output(\n+ self, instance_obj, pkts, port_id=0, count=1, interval=0, get_stats=False\n+ ):\n+ instance_obj.pmd_output.execute_cmd(\"clear port stats all\")\n+ tx_port = self.tester_ifaces[port_id]\n+ self.logger.info(\"----------send packet-------------\")\n+ self.logger.info(\"{}\".format(pkts))\n+ if not isinstance(pkts, list):\n+ pkts = [pkts]\n+ self.pkt.update_pkt(pkts)\n+ self.pkt.send_pkt(\n+ crb=self.tester,\n+ tx_port=tx_port,\n+ count=count,\n+ interval=interval,\n+ )\n+ out1 = instance_obj.pmd_output.get_output(timeout=1)\n+ if get_stats:\n+ out2 = instance_obj.pmd_output.execute_cmd(\"show port stats all\")\n+ instance_obj.pmd_output.execute_cmd(\"stop\")\n+ else:\n+ out2 = instance_obj.pmd_output.execute_cmd(\"stop\")\n+ instance_obj.pmd_output.execute_cmd(\"start\")\n+ return \"\".join([out1, out2])\n+\n+ def check_pkt_num(self, out, **kwargs):\n+ \"\"\"\n+ check number of received packets matches the expected value\n+ :param out: information received by testpmd after sending packets and port statistics\n+ :param kwargs: some specified parameters, such as: pkt_num, port_id\n+ :return: rx statistic dict\n+ \"\"\"\n+ self.logger.info(\n+ \"{0} check pkt num for port:{1} {0}\".format(\n+ self.logfmt, kwargs.get(\"port_id\")\n+ )\n+ )\n+ pkt_num = kwargs.get(\"pkt_num\")\n+ res = self.get_pkt_statistic(out, **kwargs)\n+ res_num = res[\"rx-total\"]\n+ self.verify(\n+ res_num == pkt_num,\n+ \"fail: got wrong number of packets, expect pakcet number {}, got {}\".format(\n+ pkt_num, res_num\n+ ),\n+ )\n+ self.logger.info(\n+ (GREEN(\"pass: pkt num is {} same as expected\".format(pkt_num)))\n+ )\n+ return res\n+\n+ def check_with_param(self, out, pkt_num, check_param, stats=True):\n+ \"\"\"\n+ according to the key and value of the check parameter,\n+ perform the corresponding verification in the out information\n+ :param out: information received by testpmd after sending packets and port statistics\n+ :param pkt_num: number of packets sent\n+ :param check_param: check item name and value, eg:\n+ \"check_param\": {\"port_id\": 0, \"mark_id\": 1, \"queue\": 1}\n+ \"check_param\": {\"port_id\": 0, \"drop\": 1}\n+ :param stats: effective status of rule, True or False, default is True\n+ :return:\n+ usage:\n+ check_with_param(out, pkt_num, check_param, stats)\n+ check_with_param(out, pkt_num, check_param=check_param)\n+ \"\"\"\n+ rxq = check_param.get(\"rxq\")\n+ port_id = (\n+ check_param[\"port_id\"] if check_param.get(\"port_id\") is not None else 0\n+ )\n+ match_flag = True\n+ \"\"\"\n+ check_dict shows the supported check items,the key is item name and value represent the check priority,\n+ the smaller the value, the higher the priority, priority default value is 999. if need to add new check item,\n+ please add it to the dict and implement the corresponding method and named as 'check_itemname',eg: check_queue\n+ \"\"\"\n+ self.matched_queue = []\n+ default_pri = 999\n+ check_dict = {\n+ \"queue\": default_pri,\n+ \"drop\": default_pri,\n+ \"mark_id\": 1,\n+ \"rss\": default_pri,\n+ }\n+ params = {\"port_id\": port_id, \"rxq\": rxq, \"pkt_num\": pkt_num, \"stats\": stats}\n+ # sort check_param order by priority, from high to low, set priority as 999 if key not in check_dict\n+ check_param = OrderedDict(\n+ sorted(\n+ check_param.items(),\n+ key=lambda item: check_dict.get(item[0], default_pri),\n+ )\n+ )\n+ if not check_param.get(\"drop\"):\n+ self.check_pkt_num(out, **params)\n+ for k in check_param:\n+ parameter = copy.deepcopy(params)\n+ if k not in check_dict:\n+ continue\n+ func_name = \"check_{}\".format(k)\n+ try:\n+ func = getattr(self, func_name)\n+ except AttributeError:\n+ emsg = \"{},this func is not implemented, please check!\".format(\n+ traceback.format_exc()\n+ )\n+ raise Exception(emsg)\n+ else:\n+ # for mismatch packet, if the check item is 'rss',should also verify the packets are distributed by rss\n+ if k == \"rss\" and not stats:\n+ parameter[\"stats\"] = True\n+ match_flag = False\n+ res = func(out=out, check_param=check_param, **parameter)\n+ if k == \"rss\" and match_flag:\n+ self.matched_queue.append(res)\n+\n+ def destroy_rule(self, instance_obj, port_id=0, rule_id=None):\n+ rule_id = 0 if rule_id is None else rule_id\n+ if not isinstance(rule_id, list):\n+ rule_id = [rule_id]\n+ for i in rule_id:\n+ out = instance_obj.pmd_output.execute_cmd(\n+ \"flow destroy {} rule {}\".format(port_id, i)\n+ )\n+ p = re.compile(r\"Flow rule #(\\d+) destroyed\")\n+ m = p.search(out)\n+ self.verify(m, \"flow rule {} delete failed\".format(rule_id))\n+\n+ def multiprocess_flow_data(self, case, **pmd_param):\n+ que_num, proc_num = pmd_param.get(\"queue_num\"), pmd_param.get(\"proc_num\")\n+ # start testpmd multi-process\n+ self.launch_multi_testpmd(\n+ proc_type=pmd_param.get(\"proc_type\"),\n+ queue_num=que_num,\n+ process_num=proc_num,\n+ )\n+ self.pmd_output_list[0].execute_cmd(\"flow flush 0\")\n+ check_param = case[\"check_param\"]\n+ check_param[\"rxq\"] = pmd_param.get(\"queue_num\")\n+ if check_param.get(\"rss\"):\n+ [pmd.execute_cmd(\"port config all rss all\") for pmd in self.pmd_output_list]\n+ fdir_pro = fdirprocess(\n+ self,\n+ self.pmd_output_list[0],\n+ self.tester_ifaces,\n+ rxq=pmd_param.get(\"queue_num\"),\n+ )\n+ fdir_pro.create_rule(case.get(\"rule\"))\n+ # send match and mismatch packet\n+ packets = [case.get(\"packet\")[\"match\"], case.get(\"packet\")[\"mismatch\"]]\n+ for i in range(2):\n+ out1 = self.send_pkt_get_output(fdir_pro, packets[i])\n+ patt = re.compile(\n+ r\"port\\s+{}/queue(.+?):\\s+received\\s+(\\d+)\\s+packets\".format(\n+ check_param.get(\"port_id\")\n+ )\n+ )\n+ if patt.findall(out1) and check_param.get(\"rss\"):\n+ self.logger.info(\n+ \"check whether the packets received by the primary process are distributed by RSS\"\n+ )\n+ self.check_rss(out1, stats=True, **check_param)\n+ for proc_pmd in self.pmd_output_list[1:]:\n+ out2 = proc_pmd.get_output(timeout=1)\n+ out3 = proc_pmd.execute_cmd(\"stop\")\n+ out1 = \"\".join([out1, out2, out3])\n+ proc_pmd.execute_cmd(\"start\")\n+ if patt.findall(out2) and check_param.get(\"rss\"):\n+ self.logger.info(\n+ \"check whether the packets received by the secondary process are distributed by RSS\"\n+ )\n+ self.check_rss(out2, stats=True, **check_param)\n+ pkt_num = len(packets[i])\n+ self.check_with_param(\n+ out1,\n+ pkt_num=pkt_num,\n+ check_param=check_param,\n+ stats=True if i == 0 else False,\n+ )\n+\n+ def _handle_test(self, tests, instance_obj, port_id=0):\n+ instance_obj.pmd_output.wait_link_status_up(port_id)\n+ for test in tests:\n+ if \"send_packet\" in test:\n+ out = self.send_pkt_get_output(\n+ instance_obj, test[\"send_packet\"], port_id\n+ )\n+ for proc_pmd in self.pmd_output_list[1:]:\n+ out1 = proc_pmd.get_output(timeout=1)\n+ out = \"\".join([out, out1])\n+ if \"action\" in test:\n+ instance_obj.handle_actions(out, test[\"action\"])\n+\n+ def multiprocess_rss_data(self, case, **pmd_param):\n+ que_num, proc_num = pmd_param.get(\"queue_num\"), pmd_param.get(\"proc_num\")\n+ # start testpmd multi-process\n+ self.launch_multi_testpmd(\n+ proc_type=pmd_param.get(\"proc_type\"),\n+ queue_num=que_num,\n+ process_num=proc_num,\n+ options=pmd_param.get(\"options\", None),\n+ )\n+ self.pmd_output_list[0].execute_cmd(\"flow flush 0\")\n+ rss_pro = rssprocess(\n+ self,\n+ self.pmd_output_list[0],\n+ self.tester_ifaces,\n+ rxq=pmd_param.get(\"queue_num\"),\n+ )\n+ rss_pro.error_msgs = []\n+ # handle tests\n+ tests = case[\"test\"]\n+ port_id = case[\"port_id\"]\n+ self.logger.info(\"------------handle test--------------\")\n+ # validate rule\n+ rule = case.get(\"rule\", None)\n+ if rule:\n+ rss_pro.validate_rule(rule=rule)\n+ rule_ids = rss_pro.create_rule(rule=rule)\n+ rss_pro.check_rule(rule_list=rule_ids)\n+ self._handle_test(tests, rss_pro, port_id)\n+ # handle post-test\n+ if \"post-test\" in case:\n+ self.logger.info(\"------------handle post-test--------------\")\n+ self.destroy_rule(rss_pro, port_id=port_id, rule_id=rule_ids)\n+ rss_pro.check_rule(port_id=port_id, stats=False)\n+ self._handle_test(case[\"post-test\"], rss_pro, port_id)\n+ if rss_pro.error_msgs:\n+ self.verify(\n+ False,\n+ \" \".join([errs.replace(\"'\", \" \") for errs in rss_pro.error_msgs[:500]]),\n+ )\n+\n+ def rte_flow(self, case_list, func_name, **kwargs):\n+ \"\"\"\n+ main flow of case:\n+ 1. iterate the case list and do the below steps:\n+ a. get the subcase name and init dict to save result\n+ b. call method by func name to execute case step\n+ c. record case result and err msg if case failed\n+ d. clear flow rule\n+ 2. calculate the case passing rate according to the result dict\n+ 3. record case result and pass rate in the case log file\n+ 4. verify whether the case pass rate is equal to 100, if not, mark the case as failed and raise the err msg\n+ :param case_list: case list, each item is a subcase of case\n+ :param func_name: hadle case method name, eg:\n+ 'flow_rule_operate': a method of 'FlowRuleProcessing' class,\n+ used to handle flow rule related suites,such as fdir and switch_filter\n+ 'handle_rss_distribute_cases': a method of 'RssProcessing' class,\n+ used to handle rss related suites\n+ :return:\n+ usage:\n+ for flow rule related:\n+ rte_flow(caselist, flow_rule_operate)\n+ for rss related:\n+ rte_flow(caselist, handle_rss_distribute_cases)\n+ \"\"\"\n+ if not isinstance(case_list, list):\n+ case_list = [case_list]\n+ test_results = dict()\n+ for case in case_list:\n+ case_name = case.get(\"sub_casename\")\n+ test_results[case_name] = {}\n+ try:\n+ self.logger.info(\"{0} case_name:{1} {0}\".format(\"*\" * 20, case_name))\n+ func_name(case, **kwargs)\n+ except Exception:\n+ test_results[case_name][\"result\"] = \"failed\"\n+ test_results[case_name][\"err\"] = re.sub(\n+ r\"['\\r\\n]\", \"\", str(traceback.format_exc(limit=1))\n+ ).replace(\"\\\\\\\\\", \"\\\\\")\n+ self.logger.info(\n+ (\n+ RED(\n+ \"case failed:{}, err:{}\".format(\n+ case_name, traceback.format_exc()\n+ )\n+ )\n+ )\n+ )\n+ else:\n+ test_results[case_name][\"result\"] = \"passed\"\n+ self.logger.info((GREEN(\"case passed: {}\".format(case_name))))\n+ finally:\n+ self.session_list[0].send_command(\"flow flush 0\", timeout=1)\n+ for sess in self.session_list:\n+ self.dut.close_session(sess)\n+ pass_rate = (\n+ round(\n+ sum(1 for k in test_results if \"passed\" in test_results[k][\"result\"])\n+ / len(test_results),\n+ 4,\n+ )\n+ * 100\n+ )\n+ self.logger.info(\n+ [\n+ \"{}:{}\".format(sub_name, test_results[sub_name][\"result\"])\n+ for sub_name in test_results\n+ ]\n+ )\n+ self.logger.info(\"pass rate is: {}\".format(pass_rate))\n+ msg = [\n+ \"subcase_name:{}:{},err:{}\".format(\n+ name, test_results[name].get(\"result\"), test_results[name].get(\"err\")\n+ )\n+ for name in test_results.keys()\n+ if \"failed\" in test_results[name][\"result\"]\n+ ]\n+ self.verify(\n+ int(pass_rate) == 100,\n+ \"some subcases failed, detail as below:{}\".format(msg),\n+ )\n+\n+ def test_perf_multiprocess_performance(self):\n+ \"\"\"\n+ Benchmark Multiprocess performance.\n+ #\"\"\"\n+ packet_count = 16\n+ self.dut.send_expect(\"fg\", \"# \")\n+ txPort = self.tester.get_local_port(self.dut_ports[0])\n+ rxPort = self.tester.get_local_port(self.dut_ports[1])\n+ mac = self.tester.get_mac(txPort)\n+ dmac = self.dut.get_mac_address(self.dut_ports[0])\n+ tgenInput = []\n+\n+ # create mutative src_ip+dst_ip package\n+ for i in range(packet_count):\n+ package = (\n+ r'flows = [Ether(src=\"%s\", dst=\"%s\")/IP(src=\"192.168.1.%d\", dst=\"192.168.1.%d\")/(\"X\"*26)]'\n+ % (mac, dmac, i + 1, i + 2)\n+ )\n+ self.tester.scapy_append(package)\n+ pcap = os.sep.join([self.output_path, \"test_%d.pcap\" % i])\n+ self.tester.scapy_append('wrpcap(\"%s\", flows)' % pcap)\n+ tgenInput.append([txPort, rxPort, pcap])\n+ self.tester.scapy_execute()\n+\n+ # run multiple symmetric_mp process\n+ validExecutions = []\n+ for execution in executions:\n+ if len(self.dut.get_core_list(execution[\"cores\"])) == execution[\"nprocs\"]:\n+ validExecutions.append(execution)\n+\n+ portMask = utils.create_mask(self.dut_ports)\n+\n+ for n in range(len(validExecutions)):\n+ execution = validExecutions[n]\n+ # get coreList form execution['cores']\n+ coreList = self.dut.get_core_list(execution[\"cores\"], socket=self.socket)\n+ # to run a set of symmetric_mp instances, like test plan\n+ dutSessionList = []\n+ for index in range(len(coreList)):\n+ dut_new_session = self.dut.new_session()\n+ dutSessionList.append(dut_new_session)\n+ # add -a option when tester and dut in same server\n+ dut_new_session.send_expect(\n+ self.app_symmetric_mp\n+ + \" -c %s --proc-type=auto %s -- -p %s --num-procs=%d --proc-id=%d\"\n+ % (\n+ utils.create_mask([coreList[index]]),\n+ self.eal_param,\n+ portMask,\n+ execution[\"nprocs\"],\n+ index,\n+ ),\n+ \"Finished Process Init\",\n+ )\n+\n+ # clear streams before add new streams\n+ self.tester.pktgen.clear_streams()\n+ # run packet generator\n+ streams = self.pktgen_helper.prepare_stream_from_tginput(\n+ tgenInput, 100, None, self.tester.pktgen\n+ )\n+ _, pps = self.tester.pktgen.measure_throughput(stream_ids=streams)\n+\n+ execution[\"pps\"] = pps\n+\n+ # close all symmetric_mp process\n+ self.dut.send_expect(\"killall symmetric_mp\", \"# \")\n+ # close all dut sessions\n+ for dut_session in dutSessionList:\n+ self.dut.close_session(dut_session)\n+\n+ # get rate and mpps data\n+ for n in range(len(executions)):\n+ self.verify(executions[n][\"pps\"] is not 0, \"No traffic detected\")\n+ self.result_table_create(\n+ [\n+ \"Num-procs\",\n+ \"Sockets/Cores/Threads\",\n+ \"Num Ports\",\n+ \"Frame Size\",\n+ \"%-age Line Rate\",\n+ \"Packet Rate(mpps)\",\n+ ]\n+ )\n+\n+ for execution in validExecutions:\n+ self.result_table_add(\n+ [\n+ execution[\"nprocs\"],\n+ execution[\"cores\"],\n+ 2,\n+ 64,\n+ execution[\"pps\"] / float(100000000 / (8 * 84)),\n+ execution[\"pps\"] / float(1000000),\n+ ]\n+ )\n+\n+ self.result_table_print()\n+\n+ def test_perf_multiprocess_client_serverperformance(self):\n+ \"\"\"\n+ Benchmark Multiprocess client-server performance.\n+ \"\"\"\n+ self.dut.kill_all()\n+ self.dut.send_expect(\"fg\", \"# \")\n+ txPort = self.tester.get_local_port(self.dut_ports[0])\n+ rxPort = self.tester.get_local_port(self.dut_ports[1])\n+ mac = self.tester.get_mac(txPort)\n+\n+ self.tester.scapy_append(\n+ 'dmac=\"%s\"' % self.dut.get_mac_address(self.dut_ports[0])\n+ )\n+ self.tester.scapy_append('smac=\"%s\"' % mac)\n+ self.tester.scapy_append(\n+ 'flows = [Ether(src=smac, dst=dmac)/IP(src=\"192.168.1.1\", dst=\"192.168.1.1\")/(\"X\"*26)]'\n+ )\n+\n+ pcap = os.sep.join([self.output_path, \"test.pcap\"])\n+ self.tester.scapy_append('wrpcap(\"%s\", flows)' % pcap)\n+ self.tester.scapy_execute()\n+\n+ validExecutions = []\n+ for execution in executions:\n+ if len(self.dut.get_core_list(execution[\"cores\"])) == execution[\"nprocs\"]:\n+ validExecutions.append(execution)\n+\n+ for execution in validExecutions:\n+ coreList = self.dut.get_core_list(execution[\"cores\"], socket=self.socket)\n+ # get core with socket parameter to specified which core dut used when tester and dut in same server\n+ coreMask = utils.create_mask(\n+ self.dut.get_core_list(\"1S/1C/1T\", socket=self.socket)\n+ )\n+ portMask = utils.create_mask(self.dut_ports)\n+ # specified mp_server core and add -a option when tester and dut in same server\n+ self.dut.send_expect(\n+ self.app_mp_server\n+ + \" -n %d -c %s %s -- -p %s -n %d\"\n+ % (\n+ self.dut.get_memory_channels(),\n+ coreMask,\n+ self.eal_param,\n+ portMask,\n+ execution[\"nprocs\"],\n+ ),\n+ \"Finished Process Init\",\n+ 20,\n+ )\n+ self.dut.send_expect(\"^Z\", \"\\r\\n\")\n+ self.dut.send_expect(\"bg\", \"# \")\n+\n+ for n in range(execution[\"nprocs\"]):\n+ time.sleep(5)\n+ # use next core as mp_client core, different from mp_server\n+ coreMask = utils.create_mask([str(int(coreList[n]) + 1)])\n+ self.dut.send_expect(\n+ self.app_mp_client\n+ + \" -n %d -c %s --proc-type=secondary %s -- -n %d\"\n+ % (self.dut.get_memory_channels(), coreMask, self.eal_param, n),\n+ \"Finished Process Init\",\n+ )\n+ self.dut.send_expect(\"^Z\", \"\\r\\n\")\n+ self.dut.send_expect(\"bg\", \"# \")\n+\n+ tgenInput = []\n+ tgenInput.append([txPort, rxPort, pcap])\n+\n+ # clear streams before add new streams\n+ self.tester.pktgen.clear_streams()\n+ # run packet generator\n+ streams = self.pktgen_helper.prepare_stream_from_tginput(\n+ tgenInput, 100, None, self.tester.pktgen\n+ )\n+ _, pps = self.tester.pktgen.measure_throughput(stream_ids=streams)\n+\n+ execution[\"pps\"] = pps\n+ self.dut.kill_all()\n+ time.sleep(5)\n+\n+ for n in range(len(executions)):\n+ self.verify(executions[n][\"pps\"] is not 0, \"No traffic detected\")\n+\n+ self.result_table_create(\n+ [\n+ \"Server threads\",\n+ \"Server Cores/Threads\",\n+ \"Num-procs\",\n+ \"Sockets/Cores/Threads\",\n+ \"Num Ports\",\n+ \"Frame Size\",\n+ \"%-age Line Rate\",\n+ \"Packet Rate(mpps)\",\n+ ]\n+ )\n+\n+ for execution in validExecutions:\n+ self.result_table_add(\n+ [\n+ 1,\n+ \"1S/1C/1T\",\n+ execution[\"nprocs\"],\n+ execution[\"cores\"],\n+ 2,\n+ 64,\n+ execution[\"pps\"] / float(100000000 / (8 * 84)),\n+ execution[\"pps\"] / float(1000000),\n+ ]\n+ )\n+\n+ self.result_table_print()\n+\n+ def set_fields(self):\n+ \"\"\"set ip protocol field behavior\"\"\"\n+ fields_config = {\n+ \"ip\": {\n+ \"src\": {\"range\": 64, \"action\": \"inc\"},\n+ \"dst\": {\"range\": 64, \"action\": \"inc\"},\n+ },\n+ }\n+\n+ return fields_config\n+\n+ def tear_down(self):\n+ \"\"\"\n+ Run after each test case.\n+ \"\"\"\n+ if self.session_list:\n+ for sess in self.session_list:\n+ self.dut.close_session(sess)\n+ self.dut.kill_all()\n+\n+ def tear_down_all(self):\n+ \"\"\"\n+ Run after each test suite.\n+ \"\"\"\n+ self.dut.kill_all()\n", "prefixes": [ "V3", "6/8" ] }{ "id": 121778, "url": "