DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Stephen Hemminger <stephen@networkplumber.org>
To: dev@dpdk.org
Cc: Stephen Hemminger <stephen@networkplumber.org>,
	Aman Singh <aman.deep.singh@intel.com>
Subject: [RFC 2/2] app/testpmd: add option to limit run time
Date: Sat, 17 Oct 2026 12:48:55 -0700	[thread overview]
Message-ID: <20261017194856.2950241-2-stephen@networkplumber.org> (raw)
In-Reply-To: <20261017194856.2950241-1-stephen@networkplumber.org>

When benchmarking it is useful to be able to run testpmd for
a fixed amount of time.  In non-interactive mode testpmd runs
until a signal arrives or something is read from stdin.

Add --run-time=N to stop forwarding and exit after N seconds,
printing the final statistics as on a normal exit.
The stats period loop is folded into the same wait.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 app/test-pmd/parameters.c             | 18 ++++++++
 app/test-pmd/testpmd.c                | 61 ++++++++++++++++++---------
 app/test-pmd/testpmd.h                |  1 +
 doc/guides/testpmd_app_ug/run_app.rst |  6 +++
 4 files changed, 66 insertions(+), 20 deletions(-)

diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
index f031dd7445..c852075dfb 100644
--- a/app/test-pmd/parameters.c
+++ b/app/test-pmd/parameters.c
@@ -61,6 +61,8 @@ enum {
 	TESTPMD_OPT_TX_FIRST_NUM,
 #define TESTPMD_OPT_STATS_PERIOD "stats-period"
 	TESTPMD_OPT_STATS_PERIOD_NUM,
+#define TESTPMD_OPT_RUN_TIME "run-time"
+	TESTPMD_OPT_RUN_TIME_NUM,
 #define TESTPMD_OPT_DISPLAY_XSTATS "display-xstats"
 	TESTPMD_OPT_DISPLAY_XSTATS_NUM,
 #define TESTPMD_OPT_NB_CORES "nb-cores"
@@ -282,6 +284,7 @@ static const struct option long_options[] = {
 	REQUIRED_ARG(TESTPMD_OPT_ETH_PEER),
 	NO_ARG(TESTPMD_OPT_TX_FIRST),
 	REQUIRED_ARG(TESTPMD_OPT_STATS_PERIOD),
+	REQUIRED_ARG(TESTPMD_OPT_RUN_TIME),
 	REQUIRED_ARG(TESTPMD_OPT_DISPLAY_XSTATS),
 	REQUIRED_ARG(TESTPMD_OPT_NB_CORES),
 	REQUIRED_ARG(TESTPMD_OPT_NB_PORTS),
@@ -408,6 +411,8 @@ usage(char* progname)
 	       "(only if interactive is disabled).\n");
 	printf("  --stats-period=PERIOD: statistics will be shown "
 	       "every PERIOD seconds (only if interactive is disabled).\n");
+	printf("  --run-time=N: stop forwarding and exit after N seconds "
+	       "(only if interactive is disabled).\n");
 	printf("  --display-xstats xstat_name1[,...]: comma-separated list of "
 	       "extended statistics to show. Used with --stats-period "
 	       "specified or interactive commands that show Rx/Tx statistics "
@@ -997,6 +1002,19 @@ launch_args_parse(int argc, char** argv)
 				"packets first\n");
 			tx_first = 1;
 			break;
+		case TESTPMD_OPT_RUN_TIME_NUM: {
+			char *end = NULL;
+			unsigned long secs;
+
+			errno = 0;
+			secs = strtoul(optarg, &end, 10);
+			if (optarg[0] == '\0' || *end != '\0' || errno != 0 ||
+					secs == 0 || secs > INT32_MAX)
+				rte_exit(EXIT_FAILURE, "Invalid run-time value\n");
+
+			run_time = secs;
+			break;
+		}
 		case TESTPMD_OPT_STATS_PERIOD_NUM: {
 			char *end = NULL;
 
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index e1766eec72..aaab1a83a6 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -242,6 +242,7 @@ uint16_t mbuf_data_size[MAX_SEGS_BUFFER_SPLIT] = {
 uint32_t param_total_num_mbufs = 0;  /**< number of mbufs in all pools - if
                                       * specified on command-line. */
 uint16_t stats_period; /**< Period to show statistics (disabled by default) */
+uint32_t run_time; /**< Seconds to forward before exit (0 = no limit) */
 
 /** Extended statistics to show. */
 struct rte_eth_xstat_name *xstats_display;
@@ -4556,6 +4557,41 @@ disable_primary_monitor(void)
 }
 #endif
 
+/*
+ * Non-interactive wait: print stats every stats_period seconds
+ * and stop after run_time seconds, or on signal.
+ */
+static void
+forward_wait(void)
+{
+	uint64_t hz = rte_get_timer_hz();
+	uint64_t now = rte_get_timer_cycles();
+	uint64_t end = now + (uint64_t)run_time * hz;
+	uint64_t next_stats = now;
+
+	while (f_quit == 0) {
+		uint64_t wake;
+
+		now = rte_get_timer_cycles();
+		if (run_time != 0 && now >= end)
+			break;
+
+		if (stats_period != 0 && now >= next_stats) {
+			print_stats();
+			next_stats = now + (uint64_t)stats_period * hz;
+		}
+
+		/* wake at least once a second to check for signal */
+		wake = now + hz;
+		if (stats_period != 0 && next_stats < wake)
+			wake = next_stats;
+		if (run_time != 0 && end < wake)
+			wake = end;
+
+		rte_delay_us_sleep((wake - now) * US_PER_S / hz);
+	}
+}
+
 int
 main(int argc, char** argv)
 {
@@ -4650,6 +4686,9 @@ main(int argc, char** argv)
 		rte_exit(EXIT_FAILURE, "--tx-first cannot be used on "
 				"interactive mode.\n");
 
+	if (run_time && interactive)
+		rte_exit(EXIT_FAILURE, "--run-time cannot be used on interactive mode.\n");
+
 	if (tx_first && lsc_interrupt) {
 		fprintf(stderr,
 			"Warning: lsc_interrupt needs to be off when using tx_first. Disabling.\n");
@@ -4755,26 +4794,8 @@ main(int argc, char** argv)
 	} else {
 		printf("No commandline core given, start packet forwarding\n");
 		start_packet_forwarding(tx_first);
-		if (stats_period != 0) {
-			uint64_t prev_time = 0, cur_time, diff_time = 0;
-			uint64_t timer_period;
-
-			/* Convert to number of cycles */
-			timer_period = stats_period * rte_get_timer_hz();
-
-			while (f_quit == 0) {
-				cur_time = rte_get_timer_cycles();
-				diff_time += cur_time - prev_time;
-
-				if (diff_time >= timer_period) {
-					print_stats();
-					/* Reset the timer */
-					diff_time = 0;
-				}
-				/* Sleep to avoid unnecessary checks */
-				prev_time = cur_time;
-				rte_delay_us_sleep(US_PER_S);
-			}
+		if (stats_period != 0 || run_time != 0) {
+			forward_wait();
 		} else {
 			char c;
 
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 6d4c3e8f84..3c9c78a59c 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -625,6 +625,7 @@ extern uint16_t mbuf_data_size[MAX_SEGS_BUFFER_SPLIT];
 extern uint32_t param_total_num_mbufs;
 
 extern uint16_t stats_period;
+extern uint32_t run_time;
 
 extern struct rte_eth_xstat_name *xstats_display;
 extern unsigned int xstats_display_num;
diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst
index e678058b97..6c6da5319c 100644
--- a/doc/guides/testpmd_app_ug/run_app.rst
+++ b/doc/guides/testpmd_app_ug/run_app.rst
@@ -64,6 +64,12 @@ The command line options are:
     Display statistics every PERIOD seconds, if interactive mode is disabled.
     The default value is 0, which means that the statistics will not be displayed.
 
+*   ``--run-time N``
+
+    Stop forwarding and exit after N seconds, if interactive mode is disabled.
+    Final statistics are displayed as on a normal exit.
+    The default value is 0, which means run until interrupted.
+
 *   ``--display-xstats xstat_name1[,...]``
 
     Display comma-separated list of extended statistics every PERIOD seconds
-- 
2.53.0


      reply	other threads:[~2026-10-17 19:49 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-17 19:48 [RFC 1/2] app/testpmd: add option to set flow control mode Stephen Hemminger
2026-10-17 19:48 ` Stephen Hemminger [this message]

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=20261017194856.2950241-2-stephen@networkplumber.org \
    --to=stephen@networkplumber.org \
    --cc=aman.deep.singh@intel.com \
    --cc=dev@dpdk.org \
    /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