get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/121778/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 121778,
    "url": "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"
    ]
}