<div dir="ltr"><span class="gmail-il">Recheck</span>-<span class="gmail-il">request</span>: <span style="color:rgb(51,51,51);font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px">iol-unit-arm64-testing</span></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Tue, Sep 1, 2026 at 2:59 PM Koushik Bhargav Nimoji <<a href="mailto:knimoji@iol.unh.edu">knimoji@iol.unh.edu</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">This patch adds the pvp multi paths vhost single core forward<br>
performance testsuite, which launches testpmd using the vhost<br>
and virtio virtual devices with one and two cores respectively,<br>
and tests the vhost single core throughput performance.<br>
<br>
Signed-off-by: Koushik Bhargav Nimoji <<a href="mailto:knimoji@iol.unh.edu" target="_blank">knimoji@iol.unh.edu</a>><br>
---<br>
 ...lti_paths_vhost_single_core_performance.py | 445 ++++++++++++++++++<br>
 1 file changed, 445 insertions(+)<br>
 create mode 100644 dts/tests/TestSuite_pvp_multi_paths_vhost_single_core_performance.py<br>
<br>
diff --git a/dts/tests/TestSuite_pvp_multi_paths_vhost_single_core_performance.py b/dts/tests/TestSuite_pvp_multi_paths_vhost_single_core_performance.py<br>
new file mode 100644<br>
index 0000000000..111cb4df12<br>
--- /dev/null<br>
+++ b/dts/tests/TestSuite_pvp_multi_paths_vhost_single_core_performance.py<br>
@@ -0,0 +1,445 @@<br>
+# SPDX-License-Identifier: BSD-3-Clause<br>
+# Copyright(c) 2025 University of New Hampshire<br>
+<br>
+"""Vhost-user single-core forwarding performance test suite.<br>
+<br>
+This suite measures the packet forwarding performance of DPDK's vhost-user PMD running on a<br>
+single CPU core in a Physical-Virtual-Physical (PVP) topology. Performance is evaluated across<br>
+multiple virtio-user backend options, including packed versus split ring formats, in-order packet<br>
+processing, mergeable buffers, and SIMD vectorization. Test cases are parameterized using<br>
+combinations of frame sizes, descriptor ring sizes, and target MPPS baselines specified in the<br>
+test configuration. High-speed traffic is injected from an external generator through SUT physical<br>
+interfaces, routed through Vhost and Virtio loops, and returned to the generator to measure<br>
+aggregate MPPS.<br>
+"""<br>
+<br>
+from scapy.layers.inet import IP<br>
+from scapy.layers.l2 import Ether<br>
+from scapy.packet import Raw<br>
+<br>
+from api.capabilities import (<br>
+    LinkTopology,<br>
+    requires_link_topology,<br>
+)<br>
+from api.packet import assess_performance_by_packet<br>
+from api.test import verify, write_performance_json<br>
+from api.testpmd import TestPmd<br>
+from api.testpmd.config import PortTopology, RXRingParams, SimpleForwardingModes, TXRingParams<br>
+from framework.params.eal import VirtualDevice<br>
+from framework.params.types import LogicalCoreList, RSSSetting, TestPmdParamsDict<br>
+from framework.test_suite import BaseConfig, TestSuite, perf_test<br>
+<br>
+<br>
+class Config(BaseConfig):<br>
+    """Performance test metrics."""<br>
+<br>
+    test_parameters: list[dict[str, int | float]] = [<br>
+        {"frame_size": 64, "num_descriptors": 1024, "expected_mpps": 1.00},<br>
+        {"frame_size": 128, "num_descriptors": 1024, "expected_mpps": 1.00},<br>
+        {"frame_size": 256, "num_descriptors": 1024, "expected_mpps": 1.00},<br>
+        {"frame_size": 512, "num_descriptors": 1024, "expected_mpps": 1.00},<br>
+        {"frame_size": 1024, "num_descriptors": 1024, "expected_mpps": 1.00},<br>
+        {"frame_size": 1518, "num_descriptors": 1024, "expected_mpps": 1.00},<br>
+    ]<br>
+    delta_tolerance: float = 0.05<br>
+<br>
+<br>
+@requires_link_topology(LinkTopology.TWO_LINKS)<br>
+class TestPvpMultiPathsVhostSingleCorePerformance(TestSuite):<br>
+    """pvp multi paths vhost single core performance test suite."""<br>
+<br>
+    config: Config<br>
+<br>
+    def set_up_suite(self):<br>
+        """Assign test parameters."""<br>
+        self.test_parameters = self.config.test_parameters<br>
+        self.delta_tolerance = self.config.delta_tolerance<br>
+<br>
+    def set_up_test_case(self):<br>
+        """Delete stale vhost-user Unix domain socket files."""<br>
+        self._ctx.sut_node.main_session.send_command("rm -rf /tmp/vhost-net*", privileged=True)<br>
+<br>
+    def _transmit(<br>
+        self, vhost: TestPmd, virtio: TestPmd, frame_size: int, repetitions: int = 1<br>
+    ) -> float:<br>
+        """Create a testpmd session with every rule in the given list, verify jump behavior.<br>
+<br>
+        Args:<br>
+            vhost: the running vhost testpmd shell.<br>
+            virtio: the running virtio testpmd shell.<br>
+            testpmd: The testpmd shell to use for forwarding packets.<br>
+            frame_size: The size of the frame to transmit.<br>
+            repetitions: The number of times to rerun the transmission.<br>
+<br>
+        Returns:<br>
+            The MPPS (millions of packets per second) forwarded by the SUT.<br>
+        """<br>
+        assert repetitions > 0, "Invalid number of repetitions given."<br>
+        # Build packet with dummy values, and account for the 14B and 20B Ether and IP headers<br>
+        packet = (<br>
+            Ether(src="52:00:00:00:00:00")<br>
+            / IP(src="1.2.3.4", dst="192.18.1.0")<br>
+            / Raw(load="x" * (frame_size - 14 - 20))<br>
+        )<br>
+<br>
+        vhost.start()<br>
+        virtio.start()<br>
+        rx_avg = 0.0<br>
+<br>
+        for _ in range(repetitions):<br>
+            # Transmit for 5 seconds.<br>
+            stats = assess_performance_by_packet(packet=packet, duration=5)<br>
+            rx_avg += stats.rx_pps<br>
+        return rx_avg / (repetitions * 1_000_000)<br>
+<br>
+    def _create_and_transmit(<br>
+        self,<br>
+        ring_format: int,<br>
+        in_order: int,<br>
+        buffers: int,<br>
+        vectorized: int,<br>
+        extra_args: TestPmdParamsDict,<br>
+    ):<br>
+        """Create testpmd instance with specified params and send traffic."""<br>
+        sut_dpdk_driver = self._ctx.sut_node.config.ports[0].os_driver_for_dpdk<br>
+        vhost_user_vdev = VirtualDevice("net_vhost0,iface=/tmp/vhost-net,queues=1")<br>
+        virtio_user_vdev = VirtualDevice(<br>
+            "net_virtio_user0,"<br>
+            "mac=00:11:22:33:44:10,"<br>
+            "path=/tmp/vhost-net,"<br>
+            "queues=1,"<br>
+            f"packed_vq={ring_format},"<br>
+            f"mrg_rxbuf={buffers},"<br>
+            f"in_order={in_order},"<br>
+            f"vectorized={vectorized}"<br>
+        )<br>
+<br>
+        for params in self.test_parameters:<br>
+            frame_size = params["frame_size"]<br>
+            num_descriptors = params["num_descriptors"]<br>
+<br>
+            default_args = {<br>
+                "tx_ring": TXRingParams(descriptors=num_descriptors),<br>
+                "rx_ring": RXRingParams(descriptors=num_descriptors),<br>
+            }<br>
+<br>
+            # extra_args["tx_ring"] = TXRingParams(descriptors=num_descriptors)<br>
+            # extra_args["rx_ring"] = RXRingParams(descriptors=num_descriptors)<br>
+<br>
+            if sut_dpdk_driver == "mlx5_core":<br>
+                default_args["burst"] = 64<br>
+                default_args["mbcache"] = 512<br>
+            elif sut_dpdk_driver == "i40e":<br>
+                default_args["rx_queues"] = 1<br>
+                default_args["tx_queues"] = 1<br>
+<br>
+            with (<br>
+                TestPmd(<br>
+                    prefix="vhost",<br>
+                    allowed_ports=[],<br>
+                    memory_channels=4,<br>
+                    port_topology=PortTopology.chained,<br>
+                    vdevs=[vhost_user_vdev],<br>
+                    lcore_list=LogicalCoreList([1, 2]),<br>
+                    nb_cores=1,<br>
+                    **default_args,<br>
+                ) as vhost,<br>
+                TestPmd(<br>
+                    prefix="virtio",<br>
+                    no_pci=True,<br>
+                    memory_channels=4,<br>
+                    allowed_ports=[],<br>
+                    vdevs=[virtio_user_vdev],<br>
+                    lcore_list=LogicalCoreList([3, 4, 5]),<br>
+                    nb_cores=2,<br>
+                    **extra_args,<br>
+                    **default_args,<br>
+                ) as virtio,<br>
+            ):<br>
+                vhost.set_forward_mode(SimpleForwardingModes.mac)<br>
+                virtio.set_forward_mode(SimpleForwardingModes.io)<br>
+                vhost.set_portlist([0, 2, 1])<br>
+<br>
+                params["measured_mpps"] = round(<br>
+                    self._transmit(vhost, virtio, frame_size, repetitions=5), 3<br>
+                )<br>
+                params["performance_delta"] = round(<br>
+                    (float(params["measured_mpps"]) - float(params["expected_mpps"]))<br>
+                    / float(params["expected_mpps"]),<br>
+                    3,<br>
+                )<br>
+                params["pass"] = float(params["performance_delta"]) >= -self.delta_tolerance<br>
+<br>
+        self._produce_stats_table(self.test_parameters)<br>
+        for params in self.test_parameters:<br>
+            verify(<br>
+                params["pass"] is True,<br>
+                f"""Packets forwarded is less than {(1 - self.delta_tolerance) * 100}%<br>
+                of the expected baseline.<br>
+                Measured MPPS = {params["measured_mpps"]}<br>
+                Expected MPPS = {params["expected_mpps"]}""",<br>
+            )<br>
+<br>
+    def _produce_stats_table(self, test_parameters: list[dict[str, int | float]]) -> None:<br>
+        """Display performance results in table format and write to structured JSON file.<br>
+<br>
+        Args:<br>
+            test_parameters: The expected and real stats per set of test parameters.<br>
+        """<br>
+        header = f"{'Frame Size':>12} | {'TXD/RXD':>12} | {'Real MPPS':>12} | {'Expected MPPS':>14}"<br>
+        print("-" * len(header))<br>
+        print(header)<br>
+        print("-" * len(header))<br>
+        for params in test_parameters:<br>
+            print(f"{params['frame_size']:>12} | {params['num_descriptors']:>12} | ", end="")<br>
+            print(f"{params['measured_mpps']:>12} | {params['expected_mpps']:>14}")<br>
+            print("-" * len(header))<br>
+<br>
+        write_performance_json({"results": test_parameters})<br>
+<br>
+    @perf_test<br>
+    def test_perf_vhost_single_core_virtio11_mergeable(self):<br>
+        """Validate expected single core forwarding performance.<br>
+<br>
+        Steps:<br>
+            * Set TestPMD virtio parameters: ring_format=1, buffers=1.<br>
+            * Create a packet according to the frame size specified in the test config.<br>
+            * Transmit from the traffic generator's ports 0 and 1 at above the expect.<br>
+            * Forward on TestPMD's interfaces 0 and 1 with 1 core.<br>
+<br>
+        Verify:<br>
+            * The resulting MPPS forwarded is greater than expected_mpps*(1-delta_tolerance).<br>
+        """<br>
+        extra_args: TestPmdParamsDict = {<br>
+            "tx_offloads": 0,<br>
+            "enable_hw_vlan_strip": True,<br>
+            "rss": RSSSetting.SetIPOnly(),<br>
+        }<br>
+        self._create_and_transmit(<br>
+            ring_format=1,<br>
+            buffers=1,<br>
+            in_order=0,<br>
+            vectorized=0,<br>
+            extra_args=extra_args,<br>
+        )<br>
+<br>
+    @perf_test<br>
+    def test_perf_vhost_single_core_virtio11_non_mergeable(self):<br>
+        """Validate expected single core forwarding performance.<br>
+<br>
+        Steps:<br>
+            * Set TestPMD virtio parameters: ring_format=1.<br>
+            * Create a packet according to the frame size specified in the test config.<br>
+            * Transmit from the traffic generator's ports 0 and 1 at above the expect.<br>
+            * Forward on TestPMD's interfaces 0 and 1 with 1 core.<br>
+<br>
+        Verify:<br>
+            * The resulting MPPS forwarded is greater than expected_mpps*(1-delta_tolerance).<br>
+        """<br>
+        extra_args: TestPmdParamsDict = {<br>
+            "tx_offloads": 0,<br>
+            "enable_hw_vlan_strip": True,<br>
+            "rss": RSSSetting.SetIPOnly(),<br>
+        }<br>
+        self._create_and_transmit(<br>
+            ring_format=1,<br>
+            buffers=0,<br>
+            in_order=0,<br>
+            vectorized=0,<br>
+            extra_args=extra_args,<br>
+        )<br>
+<br>
+    @perf_test<br>
+    def test_perf_vhost_single_core_virtio_inorder_mergeable(self):<br>
+        """Validate expected single core forwarding performance.<br>
+<br>
+        Steps:<br>
+            * Set TestPMD virtio parameters: buffers=1, in_order=1.<br>
+            * Create a packet according to the frame size specified in the test config.<br>
+            * Transmit from the traffic generator's ports 0 and 1 at above the expect.<br>
+            * Forward on TestPMD's interfaces 0 and 1 with 1 core.<br>
+<br>
+        Verify:<br>
+            * The resulting MPPS forwarded is greater than expected_mpps*(1-delta_tolerance).<br>
+        """<br>
+        extra_args: TestPmdParamsDict = {<br>
+            "tx_offloads": 0,<br>
+            "enable_hw_vlan_strip": True,<br>
+            "rss": RSSSetting.SetIPOnly(),<br>
+        }<br>
+        self._create_and_transmit(<br>
+            ring_format=0,<br>
+            buffers=1,<br>
+            in_order=1,<br>
+            vectorized=0,<br>
+            extra_args=extra_args,<br>
+        )<br>
+<br>
+    @perf_test<br>
+    def test_perf_vhost_single_core_virtio_inorder_nonmergeable(self):<br>
+        """Validate expected single core forwarding performance.<br>
+<br>
+        Steps:<br>
+            * Set TestPMD virtio parameters: in_order=1.<br>
+            * Create a packet according to the frame size specified in the test config.<br>
+            * Transmit from the traffic generator's ports 0 and 1 at above the expect.<br>
+            * Forward on TestPMD's interfaces 0 and 1 with 1 core.<br>
+<br>
+        Verify:<br>
+            * The resulting MPPS forwarded is greater than expected_mpps*(1-delta_tolerance).<br>
+        """<br>
+        extra_args: TestPmdParamsDict = {<br>
+            "tx_offloads": 0,<br>
+            "enable_hw_vlan_strip": True,<br>
+            "rss": RSSSetting.SetIPOnly(),<br>
+        }<br>
+        self._create_and_transmit(<br>
+            ring_format=0,<br>
+            buffers=0,<br>
+            in_order=1,<br>
+            vectorized=0,<br>
+            extra_args=extra_args,<br>
+        )<br>
+<br>
+    @perf_test<br>
+    def test_perf_vhost_single_core_virtio_mergeable(self):<br>
+        """Validate expected single core forwarding performance.<br>
+<br>
+        Steps:<br>
+            * Set TestPMD virtio parameters: buffers=1.<br>
+            * Create a packet according to the frame size specified in the test config.<br>
+            * Transmit from the traffic generator's ports 0 and 1 at above the expect.<br>
+            * Forward on TestPMD's interfaces 0 and 1 with 1 core.<br>
+<br>
+        Verify:<br>
+            * The resulting MPPS forwarded is greater than expected_mpps*(1-delta_tolerance).<br>
+        """<br>
+        extra_args: TestPmdParamsDict = {<br>
+            "tx_offloads": 0,<br>
+            "enable_hw_vlan_strip": True,<br>
+            "rss": RSSSetting.SetIPOnly(),<br>
+        }<br>
+        self._create_and_transmit(<br>
+            ring_format=0,<br>
+            buffers=1,<br>
+            in_order=0,<br>
+            vectorized=0,<br>
+            extra_args=extra_args,<br>
+        )<br>
+<br>
+    @perf_test<br>
+    def test_perf_vhost_single_core_virtio_nonmergeable(self):<br>
+        """Validate expected single core forwarding performance.<br>
+<br>
+        Steps:<br>
+            * Set TestPMD virtio parameters: vectorized=1.<br>
+            * Create a packet according to the frame size specified in the test config.<br>
+            * Transmit from the traffic generator's ports 0 and 1 at above the expect.<br>
+            * Forward on TestPMD's interfaces 0 and 1 with 1 core.<br>
+<br>
+        Verify:<br>
+            * The resulting MPPS forwarded is greater than expected_mpps*(1-delta_tolerance).<br>
+        """<br>
+        extra_args: TestPmdParamsDict = {<br>
+            "tx_offloads": 0,<br>
+            "enable_hw_vlan_strip": True,<br>
+            "rss": RSSSetting.SetIPOnly(),<br>
+        }<br>
+        self._create_and_transmit(<br>
+            ring_format=0,<br>
+            buffers=0,<br>
+            in_order=0,<br>
+            vectorized=1,<br>
+            extra_args=extra_args,<br>
+        )<br>
+<br>
+    @perf_test<br>
+    def test_perf_vhost_single_core_virtio_vectorized(self):<br>
+        """Validate expected single core forwarding performance.<br>
+<br>
+        Steps:<br>
+            * Set TestPMD virtio parameters: buffers=1.<br>
+            * Create a packet according to the frame size specified in the test config.<br>
+            * Transmit from the traffic generator's ports 0 and 1 at above the expect.<br>
+            * Forward on TestPMD's interfaces 0 and 1 with 1 core.<br>
+<br>
+        Verify:<br>
+            * The resulting MPPS forwarded is greater than expected_mpps*(1-delta_tolerance).<br>
+        """<br>
+        self._create_and_transmit(<br>
+            ring_format=0,<br>
+            buffers=1,<br>
+            in_order=0,<br>
+            vectorized=0,<br>
+            extra_args={},<br>
+        )<br>
+<br>
+    @perf_test<br>
+    def test_perf_vhost_single_core_virtio11_inorder_mergeable(self):<br>
+        """Validate expected single core forwarding performance.<br>
+<br>
+        Steps:<br>
+            * Set TestPMD virtio parameters: ring_format=1, buffers=1, in_order=1.<br>
+            * Create a packet according to the frame size specified in the test config.<br>
+            * Transmit from the traffic generator's ports 0 and 1 at above the expect.<br>
+            * Forward on TestPMD's interfaces 0 and 1 with 1 core.<br>
+<br>
+        Verify:<br>
+            * The resulting MPPS forwarded is greater than expected_mpps*(1-delta_tolerance).<br>
+        """<br>
+        extra_args: TestPmdParamsDict = {<br>
+            "tx_offloads": 0,<br>
+            "enable_hw_vlan_strip": True,<br>
+            "rss": RSSSetting.SetIPOnly(),<br>
+        }<br>
+        self._create_and_transmit(<br>
+            ring_format=1,<br>
+            buffers=1,<br>
+            in_order=1,<br>
+            vectorized=0,<br>
+            extra_args=extra_args,<br>
+        )<br>
+<br>
+    @perf_test<br>
+    def test_perf_vhost_single_core_virtio11_inorder_nonmergeable(self):<br>
+        """Validate expected single core forwarding performance.<br>
+<br>
+        Steps:<br>
+            * Set TestPMD virtio parameters: ring_format=1, in_order=1.<br>
+            * Create a packet according to the frame size specified in the test config.<br>
+            * Transmit from the traffic generator's ports 0 and 1 at above the expect.<br>
+            * Forward on TestPMD's interfaces 0 and 1 with 1 core.<br>
+<br>
+        Verify:<br>
+            * The resulting MPPS forwarded is greater than expected_mpps*(1-delta_tolerance).<br>
+        """<br>
+        extra_args: TestPmdParamsDict = {"rss": RSSSetting.SetIPOnly()}<br>
+        self._create_and_transmit(<br>
+            ring_format=1,<br>
+            buffers=0,<br>
+            in_order=1,<br>
+            vectorized=0,<br>
+            extra_args=extra_args,<br>
+        )<br>
+<br>
+    @perf_test<br>
+    def test_perf_vhost_single_core_virtio11_vectorized(self):<br>
+        """Validate expected single core forwarding performance.<br>
+<br>
+        Steps:<br>
+            * Set TestPMD virtio parameters: ring_format=1, in_order=1, vectorized=1.<br>
+            * Create a packet according to the frame size specified in the test config.<br>
+            * Transmit from the traffic generator's ports 0 and 1 at above the expect.<br>
+            * Forward on TestPMD's interfaces 0 and 1 with 1 core.<br>
+<br>
+        Verify:<br>
+            * The resulting MPPS forwarded is greater than expected_mpps*(1-delta_tolerance).<br>
+        """<br>
+        extra_args: TestPmdParamsDict = {"rss": RSSSetting.SetIPOnly()}<br>
+        self._create_and_transmit(<br>
+            ring_format=1,<br>
+            buffers=0,<br>
+            in_order=1,<br>
+            vectorized=1,<br>
+            extra_args=extra_args,<br>
+        )<br>
-- <br>
2.55.0<br>
<br>
</blockquote></div>