patch 'latencystats: fix receive sample race' has been queued to stable release 23.11.5

Xueming Li xuemingl at nvidia.com
Wed Jul 30 16:56:26 CEST 2025


Hi,

FYI, your patch has been queued to stable release 23.11.5

Note it hasn't been pushed to http://dpdk.org/browse/dpdk-stable yet.
It will be pushed if I get no objections before 08/10/25. So please
shout if anyone has objections.

Also note that after the patch there's a diff of the upstream commit vs the
patch applied to the branch. This will indicate if there was any rebasing
needed to apply to the stable branch. If there were code changes for rebasing
(ie: not only metadata diffs), please double check that the rebase was
correctly done.

Queued patches are on a temporary branch at:
https://git.dpdk.org/dpdk-stable/log/?h=23.11-staging

This queued commit can be viewed at:
https://git.dpdk.org/dpdk-stable/commit/?h=23.11-staging&id=b5b33cbcaa6a0df137f259d43062d18aef367223

Thanks.

Xueming Li <xuemingl at nvidia.com>

---
>From b5b33cbcaa6a0df137f259d43062d18aef367223 Mon Sep 17 00:00:00 2001
From: Stephen Hemminger <stephen at networkplumber.org>
Date: Tue, 17 Jun 2025 08:00:16 -0700
Subject: [PATCH] latencystats: fix receive sample race
Cc: Xueming Li <xuemingl at nvidia.com>

[ upstream commit 4e12258d782e2511bf0d781faff23fada54ee7d8 ]

The receive callback was not safe with multiple queues.
If one receive queue callback decides to take a sample it
needs to add that sample and do atomic update to the previous
TSC sample value. Add a new lock for that.

Optimize the check for when to take sample so that
it only needs to lock when likely to need a sample.

Also, add code to handle TSC wraparound in comparison.
Perhaps this should move to rte_cycles.h?

Bugzilla ID: 1723
Fixes: 5cd3cac9ed22 ("latency: added new library for latency stats")
Cc: stable at dpdk.org

Signed-off-by: Stephen Hemminger <stephen at networkplumber.org>
Tested-by: Thiyagarajan P <thiyagarajan.p at amd.com>
Reviewed-by: Vipin Varghese <vipin.varghese at amd.com>
---
 .mailmap                            |  1 +
 lib/latencystats/rte_latencystats.c | 55 ++++++++++++++++++-----------
 2 files changed, 36 insertions(+), 20 deletions(-)

diff --git a/.mailmap b/.mailmap
index 86920fea08..e64da3ab08 100644
--- a/.mailmap
+++ b/.mailmap
@@ -1460,6 +1460,7 @@ Thibaut Collet <thibaut.collet at 6wind.com>
 Thierry Herbelot <thierry.herbelot at 6wind.com>
 Thierry Martin <thierry.martin.public at gmail.com>
 Thinh Tran <thinhtr at linux.vnet.ibm.com>
+Thiyagarajan P <thiyagarajan.p at amd.com>
 Thomas Faivre <thomas.faivre at 6wind.com>
 Thomas F Herbert <therbert at redhat.com>
 Thomas Graf <tgraf at redhat.com>
diff --git a/lib/latencystats/rte_latencystats.c b/lib/latencystats/rte_latencystats.c
index e47eac2cf8..a68eb3dcb6 100644
--- a/lib/latencystats/rte_latencystats.c
+++ b/lib/latencystats/rte_latencystats.c
@@ -12,6 +12,7 @@
 #include <rte_metrics.h>
 #include <rte_memzone.h>
 #include <rte_lcore.h>
+#include <rte_stdatomic.h>
 
 #include "rte_latencystats.h"
 
@@ -38,11 +39,20 @@ timestamp_dynfield(struct rte_mbuf *mbuf)
 			timestamp_dynfield_offset, rte_mbuf_timestamp_t *);
 }
 
+/* Compare two 64 bit timer counter but deal with wraparound correctly. */
+static inline bool tsc_after(uint64_t t0, uint64_t t1)
+{
+	return (int64_t)(t1 - t0) < 0;
+}
+
+#define tsc_before(a, b) tsc_after(b, a)
+
 static const char *MZ_RTE_LATENCY_STATS = "rte_latencystats";
 static int latency_stats_index;
+
+static rte_spinlock_t sample_lock = RTE_SPINLOCK_INITIALIZER;
 static uint64_t samp_intvl;
-static uint64_t timer_tsc;
-static uint64_t prev_tsc;
+static RTE_ATOMIC(uint64_t) next_tsc;
 
 struct rte_latency_stats {
 	float min_latency; /**< Minimum latency in nano seconds */
@@ -124,25 +134,29 @@ add_time_stamps(uint16_t pid __rte_unused,
 		void *user_cb __rte_unused)
 {
 	unsigned int i;
-	uint64_t diff_tsc, now;
-
-	/*
-	 * For every sample interval,
-	 * time stamp is marked on one received packet.
-	 */
-	now = rte_rdtsc();
-	for (i = 0; i < nb_pkts; i++) {
-		diff_tsc = now - prev_tsc;
-		timer_tsc += diff_tsc;
-
-		if ((pkts[i]->ol_flags & timestamp_dynflag) == 0
-				&& (timer_tsc >= samp_intvl)) {
-			*timestamp_dynfield(pkts[i]) = now;
-			pkts[i]->ol_flags |= timestamp_dynflag;
-			timer_tsc = 0;
+	uint64_t now = rte_rdtsc();
+
+	/* Check without locking */
+	if (likely(tsc_before(now, rte_atomic_load_explicit(&next_tsc,
+							    rte_memory_order_relaxed))))
+		return nb_pkts;
+
+	/* Try and get sample, skip if sample is being done by other core. */
+	if (likely(rte_spinlock_trylock(&sample_lock))) {
+		for (i = 0; i < nb_pkts; i++) {
+			struct rte_mbuf *m = pkts[i];
+
+			/* skip if already timestamped */
+			if (unlikely(m->ol_flags & timestamp_dynflag))
+				continue;
+
+			m->ol_flags |= timestamp_dynflag;
+			*timestamp_dynfield(m) = now;
+			rte_atomic_store_explicit(&next_tsc, now + samp_intvl,
+						  rte_memory_order_relaxed);
+			break;
 		}
-		prev_tsc = now;
-		now = rte_rdtsc();
+		rte_spinlock_unlock(&sample_lock);
 	}
 
 	return nb_pkts;
@@ -235,6 +249,7 @@ rte_latencystats_init(uint64_t app_samp_intvl,
 	glob_stats = mz->addr;
 	rte_spinlock_init(&glob_stats->lock);
 	samp_intvl = app_samp_intvl * latencystat_cycles_per_ns();
+	next_tsc = rte_rdtsc();
 
 	/** Register latency stats with stats library */
 	for (i = 0; i < NUM_LATENCY_STATS; i++)
-- 
2.34.1

---
  Diff of the applied patch vs upstream commit (please double-check if non-empty:
---
--- -	2025-07-30 22:50:04.173146104 +0800
+++ 0017-latencystats-fix-receive-sample-race.patch	2025-07-30 22:50:03.036757880 +0800
@@ -1 +1 @@
-From 4e12258d782e2511bf0d781faff23fada54ee7d8 Mon Sep 17 00:00:00 2001
+From b5b33cbcaa6a0df137f259d43062d18aef367223 Mon Sep 17 00:00:00 2001
@@ -4,0 +5,3 @@
+Cc: Xueming Li <xuemingl at nvidia.com>
+
+[ upstream commit 4e12258d782e2511bf0d781faff23fada54ee7d8 ]
@@ -30 +33 @@
-index 8e898e303e..1ea4f9446d 100644
+index 86920fea08..e64da3ab08 100644
@@ -33 +36 @@
-@@ -1553,6 +1553,7 @@ Thibaut Collet <thibaut.collet at 6wind.com>
+@@ -1460,6 +1460,7 @@ Thibaut Collet <thibaut.collet at 6wind.com>
@@ -42 +45 @@
-index 6873a44a92..72a58d78d1 100644
+index e47eac2cf8..a68eb3dcb6 100644
@@ -45 +48 @@
-@@ -22,6 +22,7 @@
+@@ -12,6 +12,7 @@
@@ -47,2 +50,2 @@
- #include <rte_spinlock.h>
- #include <rte_string_fns.h>
+ #include <rte_memzone.h>
+ #include <rte_lcore.h>
@@ -53 +56 @@
-@@ -45,11 +46,20 @@ timestamp_dynfield(struct rte_mbuf *mbuf)
+@@ -38,11 +39,20 @@ timestamp_dynfield(struct rte_mbuf *mbuf)
@@ -74,3 +77,3 @@
- #define LATENCY_AVG_SCALE     4
- #define LATENCY_JITTER_SCALE 16
-@@ -147,25 +157,29 @@ add_time_stamps(uint16_t pid __rte_unused,
+ struct rte_latency_stats {
+ 	float min_latency; /**< Minimum latency in nano seconds */
+@@ -124,25 +134,29 @@ add_time_stamps(uint16_t pid __rte_unused,
@@ -124 +127 @@
-@@ -270,6 +284,7 @@ rte_latencystats_init(uint64_t app_samp_intvl,
+@@ -235,6 +249,7 @@ rte_latencystats_init(uint64_t app_samp_intvl,
@@ -127 +130 @@
- 	samp_intvl = (uint64_t)(app_samp_intvl * cycles_per_ns);
+ 	samp_intvl = app_samp_intvl * latencystat_cycles_per_ns();


More information about the stable mailing list