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