From: Stanislav Fomichev <sdf.kernel@gmail.com>
To: netdev@vger.kernel.org
Cc: davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com
Subject: [RFC net-next 4/6] selftests: drv-net: add an iperf performance test
Date: Wed, 16 Sep 2026 12:04:07 -0700 [thread overview]
Message-ID: <20260916190409.1222272-5-sdf@fomichev.me> (raw)
In-Reply-To: <20260916190409.1222272-1-sdf@fomichev.me>
Report Iperf3Runner throughput and retransmits when metric collection is
active.
Tested on two mlx5 hosts. Benchmark metric output:
# # ktap-metric-policy-json: {"name":"throughput","regression":{"better":"higher","compare":"p50","relative_tolerance":0.05},"summarize":"distribution"}
# # ktap-metric-policy-json: {"name":"tcp.retransmits","summarize":"max"}
# # ktap-metric-json: {"host":"local","name":"throughput","shape":"scalar","time":11.42686,"value":32.62285180182741}
# # ktap-metric-json: {"host":"remote","name":"tcp.retransmits","shape":"scalar","time":11.426883,"value":75895.0}
# ok 1 iperf.test_iperf
# # Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
---
.../testing/selftests/drivers/net/hw/Makefile | 1 +
.../testing/selftests/drivers/net/hw/iperf.py | 21 ++++++++++++++++
.../drivers/net/hw/lib/py/__init__.py | 8 +++---
.../selftests/drivers/net/lib/py/__init__.py | 8 +++---
.../selftests/drivers/net/lib/py/load.py | 25 +++++++++++++++++--
.../testing/selftests/net/lib/py/__init__.py | 6 ++---
tools/testing/selftests/net/lib/py/ksft.py | 6 +++++
7 files changed, 62 insertions(+), 13 deletions(-)
create mode 100755 tools/testing/selftests/drivers/net/hw/iperf.py
diff --git a/tools/testing/selftests/drivers/net/hw/Makefile b/tools/testing/selftests/drivers/net/hw/Makefile
index 8aebdc6feb17..03ecc81e18e0 100644
--- a/tools/testing/selftests/drivers/net/hw/Makefile
+++ b/tools/testing/selftests/drivers/net/hw/Makefile
@@ -32,6 +32,7 @@ TEST_PROGS = \
hw_stats_l3.sh \
hw_stats_l3_gre.sh \
iou-zcrx.py \
+ iperf.py \
ipsec_vxlan.py \
irq.py \
loopback.sh \
diff --git a/tools/testing/selftests/drivers/net/hw/iperf.py b/tools/testing/selftests/drivers/net/hw/iperf.py
new file mode 100755
index 000000000000..77e315c9547e
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/hw/iperf.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+
+from lib.py import (Iperf3Runner, NetDrvEpEnv, SystemMonitor, ksft_exit,
+ ksft_run)
+
+
+def test_iperf(cfg):
+ """Measure TCP throughput while sampling system utilization."""
+ with SystemMonitor(cfg):
+ Iperf3Runner(cfg).measure_bandwidth()
+
+
+def main():
+ with NetDrvEpEnv(__file__, nsim_test=False) as cfg:
+ ksft_run([test_iperf], args=(cfg,))
+ ksft_exit()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py b/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py
index 1077930d1677..857bd016e5e0 100644
--- a/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py
+++ b/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py
@@ -28,8 +28,8 @@ KSFT_DIR = (Path(__file__).parent / "../../../../..").resolve()
from net.lib.py import bpf_map_set, bpf_map_dump, bpf_prog_map_ids
from net.lib.py import KsftSkipEx, KsftFailEx, KsftXfailEx
from net.lib.py import ksft_disruptive, ksft_exit, ksft_metric, \
- ksft_metric_aggregate, ksft_metric_reporting, ksft_pr, ksft_run, \
- ksft_setup, \
+ ksft_metric_aggregate, ksft_metric_reporting, \
+ ksft_metric_reporting_enabled, ksft_pr, ksft_run, ksft_setup, \
ksft_variants, KsftNamedVariant
from net.lib.py import ksft_eq, ksft_ge, ksft_in, ksft_is, ksft_lt, \
ksft_ne, ksft_not_in, ksft_raises, ksft_true, ksft_gt, ksft_not_none
@@ -47,8 +47,8 @@ KSFT_DIR = (Path(__file__).parent / "../../../../..").resolve()
"bpf_map_set", "bpf_map_dump", "bpf_prog_map_ids",
"KsftSkipEx", "KsftFailEx", "KsftXfailEx",
"ksft_disruptive", "ksft_exit", "ksft_metric",
- "ksft_metric_aggregate", "ksft_metric_reporting", "ksft_pr",
- "ksft_run",
+ "ksft_metric_aggregate", "ksft_metric_reporting",
+ "ksft_metric_reporting_enabled", "ksft_pr", "ksft_run",
"ksft_setup", "ksft_variants",
"KsftNamedVariant",
"ksft_eq", "ksft_ge", "ksft_in", "ksft_is", "ksft_lt",
diff --git a/tools/testing/selftests/drivers/net/lib/py/__init__.py b/tools/testing/selftests/drivers/net/lib/py/__init__.py
index d779f48ea6c5..e418837f0b00 100644
--- a/tools/testing/selftests/drivers/net/lib/py/__init__.py
+++ b/tools/testing/selftests/drivers/net/lib/py/__init__.py
@@ -28,8 +28,8 @@ KSFT_DIR = (Path(__file__).parent / "../../../..").resolve()
from net.lib.py import bpf_map_set, bpf_map_dump, bpf_prog_map_ids
from net.lib.py import KsftSkipEx, KsftFailEx, KsftXfailEx
from net.lib.py import ksft_disruptive, ksft_exit, ksft_metric, \
- ksft_metric_aggregate, ksft_metric_reporting, ksft_pr, ksft_run, \
- ksft_setup, \
+ ksft_metric_aggregate, ksft_metric_reporting, \
+ ksft_metric_reporting_enabled, ksft_pr, ksft_run, ksft_setup, \
ksft_variants, KsftNamedVariant
from net.lib.py import ksft_eq, ksft_ge, ksft_in, ksft_is, ksft_lt, \
ksft_ne, ksft_not_in, ksft_raises, ksft_true, ksft_gt, ksft_not_none
@@ -44,8 +44,8 @@ KSFT_DIR = (Path(__file__).parent / "../../../..").resolve()
"bpf_map_set", "bpf_map_dump", "bpf_prog_map_ids",
"KsftSkipEx", "KsftFailEx", "KsftXfailEx",
"ksft_disruptive", "ksft_exit", "ksft_metric",
- "ksft_metric_aggregate", "ksft_metric_reporting", "ksft_pr",
- "ksft_run",
+ "ksft_metric_aggregate", "ksft_metric_reporting",
+ "ksft_metric_reporting_enabled", "ksft_pr", "ksft_run",
"ksft_setup", "ksft_variants",
"KsftNamedVariant",
"ksft_eq", "ksft_ge", "ksft_in", "ksft_is", "ksft_lt",
diff --git a/tools/testing/selftests/drivers/net/lib/py/load.py b/tools/testing/selftests/drivers/net/lib/py/load.py
index e24660e5c27f..f5f5cf780fbe 100644
--- a/tools/testing/selftests/drivers/net/lib/py/load.py
+++ b/tools/testing/selftests/drivers/net/lib/py/load.py
@@ -4,7 +4,8 @@ import re
import time
import json
-from lib.py import ksft_pr, cmd, ip, rand_port, wait_port_listen
+from lib.py import cmd, ip, ksft_metric, ksft_metric_aggregate, \
+ ksft_metric_reporting_enabled, ksft_pr, rand_port, wait_port_listen
class Iperf3Runner:
@@ -57,8 +58,17 @@ from lib.py import ksft_pr, cmd, ip, rand_port, wait_port_listen
"""
Runs an iperf3 measurement and returns the average bandwidth (Gbps).
Discards the first and last few reporting intervals and uses only the
- middle part of the run where throughput is typically stable.
+ middle part of the run where throughput is typically stable. When a
+ SystemMonitor is active, also emit throughput and retransmit metrics.
"""
+ report_metrics = ksft_metric_reporting_enabled()
+ if report_metrics:
+ ksft_metric_aggregate(
+ "throughput", summarize="distribution",
+ regression={"compare": "p50", "better": "higher",
+ "relative_tolerance": 0.05})
+ ksft_metric_aggregate("tcp.retransmits", summarize="max")
+
self.start_server()
result = self.start_client(duration=10, reverse=reverse)
@@ -77,6 +87,17 @@ from lib.py import ksft_pr, cmd, ip, rand_port, wait_port_listen
stable = samples[3:-3]
avg = sum(stable) / len(stable)
+ retransmits = out.get("end", {}).get("sum_sent", {}).get(
+ "retransmits")
+ if report_metrics:
+ if not isinstance(retransmits, int) or \
+ isinstance(retransmits, bool):
+ raise ValueError("iperf3 did not report TCP retransmits")
+ receiver = "remote" if reverse else "local"
+ sender = "local" if reverse else "remote"
+ ksft_metric("throughput", avg, shape="scalar", host=receiver)
+ ksft_metric("tcp.retransmits", retransmits, shape="scalar",
+ host=sender)
return avg
diff --git a/tools/testing/selftests/net/lib/py/__init__.py b/tools/testing/selftests/net/lib/py/__init__.py
index 9795a83d662a..5b91de1650c5 100644
--- a/tools/testing/selftests/net/lib/py/__init__.py
+++ b/tools/testing/selftests/net/lib/py/__init__.py
@@ -9,7 +9,7 @@ from .ksft import KsftFailEx, KsftSkipEx, KsftXfailEx, ksft_pr, ksft_eq, \
ksft_ne, ksft_true, ksft_not_none, ksft_in, ksft_not_in, ksft_is, \
ksft_ge, ksft_gt, ksft_lt, ksft_raises, ksft_busy_wait, \
ktap_result, ksft_disruptive, ksft_metric, ksft_metric_aggregate, \
- ksft_metric_reporting, ksft_setup, ksft_run, \
+ ksft_metric_reporting, ksft_metric_reporting_enabled, ksft_setup, ksft_run, \
ksft_exit, ksft_variants, KsftNamedVariant
from .netns import NetNS, NetNSEnter, UserNetNS
from .nsim import NetdevSim, NetdevSimDev
@@ -26,8 +26,8 @@ __all__ = ["KSRC",
"ksft_ne", "ksft_true", "ksft_not_none", "ksft_in", "ksft_not_in",
"ksft_is", "ksft_ge", "ksft_gt", "ksft_lt", "ksft_raises",
"ksft_busy_wait", "ktap_result", "ksft_disruptive", "ksft_metric",
- "ksft_metric_aggregate", "ksft_metric_reporting", "ksft_setup",
- "ksft_run",
+ "ksft_metric_aggregate", "ksft_metric_reporting",
+ "ksft_metric_reporting_enabled", "ksft_setup", "ksft_run",
"ksft_exit", "ksft_variants",
"KsftNamedVariant",
"NetNS", "NetNSEnter", "UserNetNS",
diff --git a/tools/testing/selftests/net/lib/py/ksft.py b/tools/testing/selftests/net/lib/py/ksft.py
index e44029213e4f..566ec52cd9c9 100644
--- a/tools/testing/selftests/net/lib/py/ksft.py
+++ b/tools/testing/selftests/net/lib/py/ksft.py
@@ -108,6 +108,12 @@ KSFT_METRICS_LOCK = threading.Lock()
KSFT_METRIC_REPORTING += 1 if enable else -1
+def ksft_metric_reporting_enabled():
+ """Return whether benchmark metric producers should emit metrics."""
+ with KSFT_METRICS_LOCK:
+ return KSFT_METRIC_REPORTING > 0
+
+
def ksft_metric_aggregate(name, summarize="total", *, aggregation=None,
transform=None, regression=None,
display_range=None, display_scale=None,
--
2.53.0-Meta
next prev parent reply other threads:[~2026-09-16 19:04 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-16 19:04 [RFC net-next 0/6] selftests: net: add performance metric reporting Stanislav Fomichev
2026-09-16 19:04 ` [RFC net-next 1/6] selftests: net: py: add timestamped metric output Stanislav Fomichev
2026-09-22 16:10 ` Paolo Abeni
2026-09-16 19:04 ` [RFC net-next 2/6] selftests: net: py: add metric policy output Stanislav Fomichev
2026-09-22 16:16 ` Paolo Abeni
2026-09-16 19:04 ` [RFC net-next 3/6] selftests: drv-net: add a system performance monitor Stanislav Fomichev
2026-09-16 19:04 ` Stanislav Fomichev [this message]
2026-09-16 19:04 ` [RFC net-next 5/6] selftests: drv-net: add a kperf runner Stanislav Fomichev
2026-09-16 19:04 ` [RFC net-next 6/6] selftests: drv-net: measure devmem performance with kperf Stanislav Fomichev
2026-09-17 20:01 ` [RFC net-next 0/6] selftests: net: add performance metric reporting Jakub Kicinski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260916190409.1222272-5-sdf@fomichev.me \
--to=sdf.kernel@gmail.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox