* [PATCH net-next v2 0/5] page_pool: Convert stats to u64_stats_t.
@ 2025-03-07 11:57 Sebastian Andrzej Siewior
2025-03-07 11:57 ` [PATCH net-next v2 1/5] page_pool: Provide an empty page_pool_stats for disabled stats Sebastian Andrzej Siewior
` (4 more replies)
0 siblings, 5 replies; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2025-03-07 11:57 UTC (permalink / raw)
To: linux-rdma, netdev
Cc: David S. Miller, Andrew Lunn, Eric Dumazet, Ilias Apalodimas,
Jakub Kicinski, Jesper Dangaard Brouer, Joe Damato,
Leon Romanovsky, Paolo Abeni, Saeed Mahameed, Simon Horman,
Tariq Toukan, Thomas Gleixner, Yunsheng Lin,
Sebastian Andrzej Siewior
This is a follow-up on
https://lore.kernel.org/all/20250213093925.x_ggH1aj@linutronix.de/
to convert the page_pool statistics to u64_stats_t to avoid u64 related
problems on 32bit architectures.
While looking over it, the comment for recycle_stat_inc() says that it
is safe to use in preemptible context. The 32bit update is split into
two 32bit writes. This is "okay" if the value observed from the current
CPU but cross CPU reads may observe inconsistencies if the lower part
overflows and the upper part is not yet written.
I explained this and added x86-32 assembly in
https://lore.kernel.org/all/20250226102703.3F7Aa2oK@linutronix.de/
I don't know if it is ensured that only *one* update can happen because
the stats are per-CPU and per NAPI device. But there will be now a
warning on 32bit if this is really attempted in preemptible context.
The placement of the counters is not affected by this change except on
32bit where an additional sync member is added. For 64bit pahole output
changes from
| struct page_pool_recycle_stats {
| u64 cached; /* 0 8 */
| u64 cache_full; /* 8 8 */
| u64 ring; /* 16 8 */
| u64 ring_full; /* 24 8 */
| u64 released_refcnt; /* 32 8 */
|
| /* size: 40, cachelines: 1, members: 5 */
| /* last cacheline: 40 bytes */
| };
to
| struct page_pool_recycle_stats {
| struct u64_stats_sync syncp; /* 0 0 */
| u64_stats_t cached; /* 0 8 */
| u64_stats_t cache_full; /* 8 8 */
| u64_stats_t ring; /* 16 8 */
| u64_stats_t ring_full; /* 24 8 */
| u64_stats_t released_refcnt; /* 32 8 */
|
| /* size: 40, cachelines: 1, members: 6 */
| /* last cacheline: 40 bytes */
| };
On 32bit struct u64_stats_sync grows by 4 bytes (plus addiional 20 with
lockdep).
For bench_page_pool_simple.ko loops=600000000 I neded up with, before:
| time_bench: Type:for_loop Per elem: 1 cycles(tsc) 0.501 ns (step:0)
| time_bench: Type:atomic_inc Per elem: 6 cycles(tsc) 3.303 ns (step:0)
| time_bench: Type:lock Per elem: 28 cycles(tsc) 14.038 ns (step:0)
| time_bench: Type:u64_stats_inc Per elem: 1 cycles(tsc) 0.565 ns (step:0)
| time_bench: Type:this_cpu_inc Per elem: 1 cycles(tsc) 0.503 ns (step:0)
|
| bench_page_pool_simple: time_bench_page_pool01_fast_path(): Cannot use page_pool fast-path
| time_bench: Type:no-softirq-page_pool01 Per elem: 19 cycles(tsc) 9.526 ns (step:0)
| bench_page_pool_simple: time_bench_page_pool02_ptr_ring(): Cannot use page_pool fast-path
| time_bench: Type:no-softirq-page_pool02 Per elem: 46 cycles(tsc) 23.501 ns (step:0)
| bench_page_pool_simple: time_bench_page_pool03_slow(): Cannot use page_pool fast-path
| time_bench: Type:no-softirq-page_pool03 Per elem: 121 cycles(tsc) 60.697 ns (step:0)
| bench_page_pool_simple: pp_tasklet_handler(): in_serving_softirq fast-path
| bench_page_pool_simple: time_bench_page_pool01_fast_path(): in_serving_softirq fast-path
| time_bench: Type:tasklet_page_pool01_fast_path Per elem: 19 cycles(tsc) 9.531 ns (step:0)
| bench_page_pool_simple: time_bench_page_pool02_ptr_ring(): in_serving_softirq fast-path
| time_bench: Type:tasklet_page_pool02_ptr_ring Per elem: 45 cycles(tsc) 22.594 ns (step:0)
| bench_page_pool_simple: time_bench_page_pool03_slow(): in_serving_softirq fast-path
| time_bench: Type:tasklet_page_pool03_slow Per elem: 123 cycles(tsc) 61.969 ns (step:0)
after:
| time_bench: Type:for_loop Per elem: 1 cycles(tsc) 0.501 ns (step:0)
| time_bench: Type:atomic_inc Per elem: 6 cycles(tsc) 3.324 ns (step:0)
| time_bench: Type:lock Per elem: 28 cycles(tsc) 14.038 ns (step:0)
| time_bench: Type:u64_stats_inc Per elem: 1 cycles(tsc) 0.565 ns (step:0)
| time_bench: Type:this_cpu_inc Per elem: 1 cycles(tsc) 0.506 ns (step:0)
|
| bench_page_pool_simple: time_bench_page_pool01_fast_path(): Cannot use page_pool fast-path
| time_bench: Type:no-softirq-page_pool01 Per elem: 18 cycles(tsc) 9.028 ns (step:0)
| bench_page_pool_simple: time_bench_page_pool02_ptr_ring(): Cannot use page_pool fast-path
| time_bench: Type:no-softirq-page_pool02 Per elem: 45 cycles(tsc) 22.714 ns (step:0)
| bench_page_pool_simple: time_bench_page_pool03_slow(): Cannot use page_pool fast-path
| time_bench: Type:no-softirq-page_pool03 Per elem: 120 cycles(tsc) 60.428 ns (step:0)
| bench_page_pool_simple: pp_tasklet_handler(): in_serving_softirq fast-path
| bench_page_pool_simple: time_bench_page_pool01_fast_path(): in_serving_softirq fast-path
| time_bench: Type:tasklet_page_pool01_fast_path Per elem: 18 cycles(tsc) 9.024 ns (step:0)
| bench_page_pool_simple: time_bench_page_pool02_ptr_ring(): in_serving_softirq fast-path
| time_bench: Type:tasklet_page_pool02_ptr_ring Per elem: 43 cycles(tsc) 22.028 ns (step:0)
| bench_page_pool_simple: time_bench_page_pool03_slow(): in_serving_softirq fast-path
| time_bench: Type:tasklet_page_pool03_slow Per elem: 121 cycles(tsc) 60.736 ns (step:0)
v1…v2: https://lore.kernel.org/all/20250221115221.291006-1-bigeasy@linutronix.de
- Clarified the cover mail, added stat for pahole and from bench_page_pool_simple.ko
- Corrected page_pool_alloc_stats vs page_pool_recycle_stats type in
the last patch.
- Copy the counter values outside of the do {} while loop and add them
later.
- Redid the mlnx5 patch to make it use generic infrastructure which is
now extended as part of this series.
Sebastian Andrzej Siewior (5):
page_pool: Provide an empty page_pool_stats for disabled stats.
page_pool: Add per-queue statistics.
mlx5: Use generic code for page_pool statistics.
page_pool: Convert page_pool_recycle_stats to u64_stats_t.
page_pool: Convert page_pool_alloc_stats to u64_stats_t.
Documentation/networking/page_pool.rst | 6 +-
.../ethernet/mellanox/mlx5/core/en_stats.c | 87 +++----------
.../ethernet/mellanox/mlx5/core/en_stats.h | 30 +----
include/linux/u64_stats_sync.h | 5 +
include/net/page_pool/helpers.h | 11 ++
include/net/page_pool/types.h | 31 +++--
net/core/page_pool.c | 122 ++++++++++++++----
net/core/page_pool_user.c | 22 ++--
8 files changed, 163 insertions(+), 151 deletions(-)
--
2.47.2
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH net-next v2 1/5] page_pool: Provide an empty page_pool_stats for disabled stats.
2025-03-07 11:57 [PATCH net-next v2 0/5] page_pool: Convert stats to u64_stats_t Sebastian Andrzej Siewior
@ 2025-03-07 11:57 ` Sebastian Andrzej Siewior
2025-03-13 14:40 ` Ilias Apalodimas
2025-03-07 11:57 ` [PATCH net-next v2 2/5] page_pool: Add per-queue statistics Sebastian Andrzej Siewior
` (3 subsequent siblings)
4 siblings, 1 reply; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2025-03-07 11:57 UTC (permalink / raw)
To: linux-rdma, netdev
Cc: David S. Miller, Andrew Lunn, Eric Dumazet, Ilias Apalodimas,
Jakub Kicinski, Jesper Dangaard Brouer, Joe Damato,
Leon Romanovsky, Paolo Abeni, Saeed Mahameed, Simon Horman,
Tariq Toukan, Thomas Gleixner, Yunsheng Lin,
Sebastian Andrzej Siewior
An empty struct page_pool_stats allows to always add it to structs and
pass it to functions like page_pool_ethtool_stats_get() without the need
for an ifdef.
Provide an empty struct page_pool_stats and page_pool_get_stats() for
!CONFIG_PAGE_POOL_STATS builds.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
include/net/page_pool/helpers.h | 6 ++++++
include/net/page_pool/types.h | 4 ++++
2 files changed, 10 insertions(+)
diff --git a/include/net/page_pool/helpers.h b/include/net/page_pool/helpers.h
index 582a3d00cbe23..4622db90f88f2 100644
--- a/include/net/page_pool/helpers.h
+++ b/include/net/page_pool/helpers.h
@@ -81,6 +81,12 @@ static inline u64 *page_pool_ethtool_stats_get(u64 *data, const void *stats)
{
return data;
}
+
+static inline bool page_pool_get_stats(const struct page_pool *pool,
+ struct page_pool_stats *stats)
+{
+ return false;
+}
#endif
/**
diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h
index 7f405672b089d..6d55e6cf5d0db 100644
--- a/include/net/page_pool/types.h
+++ b/include/net/page_pool/types.h
@@ -140,6 +140,10 @@ struct page_pool_stats {
struct page_pool_alloc_stats alloc_stats;
struct page_pool_recycle_stats recycle_stats;
};
+
+#else /* !CONFIG_PAGE_POOL_STATS */
+
+struct page_pool_stats { };
#endif
/* The whole frag API block must stay within one cacheline. On 32-bit systems,
--
2.47.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH net-next v2 2/5] page_pool: Add per-queue statistics.
2025-03-07 11:57 [PATCH net-next v2 0/5] page_pool: Convert stats to u64_stats_t Sebastian Andrzej Siewior
2025-03-07 11:57 ` [PATCH net-next v2 1/5] page_pool: Provide an empty page_pool_stats for disabled stats Sebastian Andrzej Siewior
@ 2025-03-07 11:57 ` Sebastian Andrzej Siewior
2025-03-07 16:11 ` Jakub Kicinski
2025-03-07 11:57 ` [PATCH net-next v2 3/5] mlx5: Use generic code for page_pool statistics Sebastian Andrzej Siewior
` (2 subsequent siblings)
4 siblings, 1 reply; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2025-03-07 11:57 UTC (permalink / raw)
To: linux-rdma, netdev
Cc: David S. Miller, Andrew Lunn, Eric Dumazet, Ilias Apalodimas,
Jakub Kicinski, Jesper Dangaard Brouer, Joe Damato,
Leon Romanovsky, Paolo Abeni, Saeed Mahameed, Simon Horman,
Tariq Toukan, Thomas Gleixner, Yunsheng Lin,
Sebastian Andrzej Siewior
The mlx5 driver supports per-channel statistics. To make support generic
it is required to have a template to fill the individual channel/ queue.
Provide page_pool_ethtool_stats_get_strings_mq() to fill the strings for
multiple queue.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
include/net/page_pool/helpers.h | 5 +++++
net/core/page_pool.c | 23 +++++++++++++++++++++++
2 files changed, 28 insertions(+)
diff --git a/include/net/page_pool/helpers.h b/include/net/page_pool/helpers.h
index 4622db90f88f2..a815b0ff97448 100644
--- a/include/net/page_pool/helpers.h
+++ b/include/net/page_pool/helpers.h
@@ -62,6 +62,7 @@
/* Deprecated driver-facing API, use netlink instead */
int page_pool_ethtool_stats_get_count(void);
u8 *page_pool_ethtool_stats_get_strings(u8 *data);
+void page_pool_ethtool_stats_get_strings_mq(u8 **data, unsigned int queue);
u64 *page_pool_ethtool_stats_get(u64 *data, const void *stats);
bool page_pool_get_stats(const struct page_pool *pool,
@@ -77,6 +78,10 @@ static inline u8 *page_pool_ethtool_stats_get_strings(u8 *data)
return data;
}
+static inline void page_pool_ethtool_stats_get_strings_mq(u8 **data, unsigned int queue)
+{
+}
+
static inline u64 *page_pool_ethtool_stats_get(u64 *data, const void *stats)
{
return data;
diff --git a/net/core/page_pool.c b/net/core/page_pool.c
index f5e908c9e7ad8..2290d80443d1e 100644
--- a/net/core/page_pool.c
+++ b/net/core/page_pool.c
@@ -68,6 +68,20 @@ static const char pp_stats[][ETH_GSTRING_LEN] = {
"rx_pp_recycle_released_ref",
};
+static const char pp_stats_mq[][ETH_GSTRING_LEN] = {
+ "rx%d_pp_alloc_fast",
+ "rx%d_pp_alloc_slow",
+ "rx%d_pp_alloc_slow_ho",
+ "rx%d_pp_alloc_empty",
+ "rx%d_pp_alloc_refill",
+ "rx%d_pp_alloc_waive",
+ "rx%d_pp_recycle_cached",
+ "rx%d_pp_recycle_cache_full",
+ "rx%d_pp_recycle_ring",
+ "rx%d_pp_recycle_ring_full",
+ "rx%d_pp_recycle_released_ref",
+};
+
/**
* page_pool_get_stats() - fetch page pool stats
* @pool: pool from which page was allocated
@@ -123,6 +137,15 @@ u8 *page_pool_ethtool_stats_get_strings(u8 *data)
}
EXPORT_SYMBOL(page_pool_ethtool_stats_get_strings);
+void page_pool_ethtool_stats_get_strings_mq(u8 **data, unsigned int queue)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pp_stats_mq); i++)
+ ethtool_sprintf(data, pp_stats_mq[i], queue);
+}
+EXPORT_SYMBOL(page_pool_ethtool_stats_get_strings_mq);
+
int page_pool_ethtool_stats_get_count(void)
{
return ARRAY_SIZE(pp_stats);
--
2.47.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH net-next v2 3/5] mlx5: Use generic code for page_pool statistics.
2025-03-07 11:57 [PATCH net-next v2 0/5] page_pool: Convert stats to u64_stats_t Sebastian Andrzej Siewior
2025-03-07 11:57 ` [PATCH net-next v2 1/5] page_pool: Provide an empty page_pool_stats for disabled stats Sebastian Andrzej Siewior
2025-03-07 11:57 ` [PATCH net-next v2 2/5] page_pool: Add per-queue statistics Sebastian Andrzej Siewior
@ 2025-03-07 11:57 ` Sebastian Andrzej Siewior
2025-03-07 11:57 ` [PATCH net-next v2 4/5] page_pool: Convert page_pool_recycle_stats to u64_stats_t Sebastian Andrzej Siewior
2025-03-07 11:57 ` [PATCH net-next v2 5/5] page_pool: Convert page_pool_alloc_stats " Sebastian Andrzej Siewior
4 siblings, 0 replies; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2025-03-07 11:57 UTC (permalink / raw)
To: linux-rdma, netdev
Cc: David S. Miller, Andrew Lunn, Eric Dumazet, Ilias Apalodimas,
Jakub Kicinski, Jesper Dangaard Brouer, Joe Damato,
Leon Romanovsky, Paolo Abeni, Saeed Mahameed, Simon Horman,
Tariq Toukan, Thomas Gleixner, Yunsheng Lin,
Sebastian Andrzej Siewior
The statistics gathering code for page_pool statistics has multiple
steps:
- gather statistics from a channel via page_pool_get_stats() to an
on-stack structure.
- copy this data to dedicated rq_stats.
- copy the data from rq_stats global mlx5e_sw_stats structure, and merge
per-queue statistics into one counter.
- Finally copy the data in specific order for the ethtool query (both
per queue and all queues summed up).
The downside here is that the individual counter types are expected to
be u64 and if something changes, the code breaks. Also if additional
counter are added to struct page_pool_stats then they are not
automtically picked up by the driver but need to be manually added in
all four spots.
Remove the page_pool_stats related description from sw_stats_desc and
rq_stats_desc.
Replace the counters in mlx5e_sw_stats and mlx5e_rq_stats with struct
page_pool_stats. This one will be empty if page_pool_stats is disabled.
Let mlx5e_stats_update_stats_rq_page_pool() fetch the stats for
page_pool twice: One for the summed up data, one for the individual
queue.
Publish the strings via page_pool_ethtool_stats_get_strings() and
page_pool_ethtool_stats_get_strings_mq().
Publish the counter via page_pool_ethtool_stats_get().
Suggested-by: Joe Damato <jdamato@fastly.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
.../ethernet/mellanox/mlx5/core/en_stats.c | 87 ++++---------------
.../ethernet/mellanox/mlx5/core/en_stats.h | 30 +------
2 files changed, 19 insertions(+), 98 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
index 611ec4b6f3709..f99c5574b79b9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
@@ -37,9 +37,7 @@
#include "en/ptp.h"
#include "en/port.h"
-#ifdef CONFIG_PAGE_POOL_STATS
#include <net/page_pool/helpers.h>
-#endif
void mlx5e_ethtool_put_stat(u64 **data, u64 val)
{
@@ -196,19 +194,6 @@ static const struct counter_desc sw_stats_desc[] = {
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_arfs_err) },
#endif
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_recover) },
-#ifdef CONFIG_PAGE_POOL_STATS
- { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_alloc_fast) },
- { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_alloc_slow) },
- { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_alloc_slow_high_order) },
- { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_alloc_empty) },
- { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_alloc_refill) },
- { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_alloc_waive) },
- { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_recycle_cached) },
- { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_recycle_cache_full) },
- { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_recycle_ring) },
- { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_recycle_ring_full) },
- { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_recycle_released_ref) },
-#endif
#ifdef CONFIG_MLX5_EN_TLS
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_tls_decrypted_packets) },
{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_tls_decrypted_bytes) },
@@ -257,7 +242,7 @@ static const struct counter_desc sw_stats_desc[] = {
static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(sw)
{
- return NUM_SW_COUNTERS;
+ return NUM_SW_COUNTERS + page_pool_ethtool_stats_get_count();
}
static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(sw)
@@ -266,6 +251,7 @@ static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(sw)
for (i = 0; i < NUM_SW_COUNTERS; i++)
ethtool_puts(data, sw_stats_desc[i].format);
+ *data = page_pool_ethtool_stats_get_strings(*data);
}
static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(sw)
@@ -276,6 +262,7 @@ static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(sw)
mlx5e_ethtool_put_stat(data,
MLX5E_READ_CTR64_CPU(&priv->stats.sw,
sw_stats_desc, i));
+ *data = page_pool_ethtool_stats_get(*data, &priv->stats.sw.page_pool_stats);
}
static void mlx5e_stats_grp_sw_update_stats_xdp_red(struct mlx5e_sw_stats *s,
@@ -377,19 +364,6 @@ static void mlx5e_stats_grp_sw_update_stats_rq_stats(struct mlx5e_sw_stats *s,
s->rx_arfs_err += rq_stats->arfs_err;
#endif
s->rx_recover += rq_stats->recover;
-#ifdef CONFIG_PAGE_POOL_STATS
- s->rx_pp_alloc_fast += rq_stats->pp_alloc_fast;
- s->rx_pp_alloc_slow += rq_stats->pp_alloc_slow;
- s->rx_pp_alloc_empty += rq_stats->pp_alloc_empty;
- s->rx_pp_alloc_refill += rq_stats->pp_alloc_refill;
- s->rx_pp_alloc_waive += rq_stats->pp_alloc_waive;
- s->rx_pp_alloc_slow_high_order += rq_stats->pp_alloc_slow_high_order;
- s->rx_pp_recycle_cached += rq_stats->pp_recycle_cached;
- s->rx_pp_recycle_cache_full += rq_stats->pp_recycle_cache_full;
- s->rx_pp_recycle_ring += rq_stats->pp_recycle_ring;
- s->rx_pp_recycle_ring_full += rq_stats->pp_recycle_ring_full;
- s->rx_pp_recycle_released_ref += rq_stats->pp_recycle_released_ref;
-#endif
#ifdef CONFIG_MLX5_EN_TLS
s->rx_tls_decrypted_packets += rq_stats->tls_decrypted_packets;
s->rx_tls_decrypted_bytes += rq_stats->tls_decrypted_bytes;
@@ -496,34 +470,14 @@ static void mlx5e_stats_grp_sw_update_stats_qos(struct mlx5e_priv *priv,
}
}
-#ifdef CONFIG_PAGE_POOL_STATS
-static void mlx5e_stats_update_stats_rq_page_pool(struct mlx5e_channel *c)
+static void mlx5e_stats_update_stats_rq_page_pool(struct mlx5e_sw_stats *s,
+ struct mlx5e_channel *c)
{
struct mlx5e_rq_stats *rq_stats = c->rq.stats;
- struct page_pool *pool = c->rq.page_pool;
- struct page_pool_stats stats = { 0 };
- if (!page_pool_get_stats(pool, &stats))
- return;
-
- rq_stats->pp_alloc_fast = stats.alloc_stats.fast;
- rq_stats->pp_alloc_slow = stats.alloc_stats.slow;
- rq_stats->pp_alloc_slow_high_order = stats.alloc_stats.slow_high_order;
- rq_stats->pp_alloc_empty = stats.alloc_stats.empty;
- rq_stats->pp_alloc_waive = stats.alloc_stats.waive;
- rq_stats->pp_alloc_refill = stats.alloc_stats.refill;
-
- rq_stats->pp_recycle_cached = stats.recycle_stats.cached;
- rq_stats->pp_recycle_cache_full = stats.recycle_stats.cache_full;
- rq_stats->pp_recycle_ring = stats.recycle_stats.ring;
- rq_stats->pp_recycle_ring_full = stats.recycle_stats.ring_full;
- rq_stats->pp_recycle_released_ref = stats.recycle_stats.released_refcnt;
+ page_pool_get_stats(c->rq.page_pool, &s->page_pool_stats);
+ page_pool_get_stats(c->rq.page_pool, &rq_stats->page_pool_stats);
}
-#else
-static void mlx5e_stats_update_stats_rq_page_pool(struct mlx5e_channel *c)
-{
-}
-#endif
static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(sw)
{
@@ -532,15 +486,13 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(sw)
memset(s, 0, sizeof(*s));
- for (i = 0; i < priv->channels.num; i++) /* for active channels only */
- mlx5e_stats_update_stats_rq_page_pool(priv->channels.c[i]);
-
for (i = 0; i < priv->stats_nch; i++) {
struct mlx5e_channel_stats *channel_stats =
priv->channel_stats[i];
int j;
+ mlx5e_stats_update_stats_rq_page_pool(s, priv->channels.c[i]);
mlx5e_stats_grp_sw_update_stats_rq_stats(s, &channel_stats->rq);
mlx5e_stats_grp_sw_update_stats_xdpsq(s, &channel_stats->rq_xdpsq);
mlx5e_stats_grp_sw_update_stats_ch_stats(s, &channel_stats->ch);
@@ -2086,19 +2038,6 @@ static const struct counter_desc rq_stats_desc[] = {
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, arfs_err) },
#endif
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, recover) },
-#ifdef CONFIG_PAGE_POOL_STATS
- { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, pp_alloc_fast) },
- { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, pp_alloc_slow) },
- { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, pp_alloc_slow_high_order) },
- { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, pp_alloc_empty) },
- { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, pp_alloc_refill) },
- { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, pp_alloc_waive) },
- { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, pp_recycle_cached) },
- { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, pp_recycle_cache_full) },
- { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, pp_recycle_ring) },
- { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, pp_recycle_ring_full) },
- { MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, pp_recycle_released_ref) },
-#endif
#ifdef CONFIG_MLX5_EN_TLS
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, tls_decrypted_packets) },
{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, tls_decrypted_bytes) },
@@ -2446,7 +2385,8 @@ static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(channels)
(NUM_RQ_XDPSQ_STATS * max_nch) +
(NUM_XDPSQ_STATS * max_nch) +
(NUM_XSKRQ_STATS * max_nch * priv->xsk.ever_used) +
- (NUM_XSKSQ_STATS * max_nch * priv->xsk.ever_used);
+ (NUM_XSKSQ_STATS * max_nch * priv->xsk.ever_used) +
+ page_pool_ethtool_stats_get_count() * max_nch;
}
static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(channels)
@@ -2462,6 +2402,7 @@ static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(channels)
for (i = 0; i < max_nch; i++) {
for (j = 0; j < NUM_RQ_STATS; j++)
ethtool_sprintf(data, rq_stats_desc[j].format, i);
+ page_pool_ethtool_stats_get_strings_mq(data, i);
for (j = 0; j < NUM_XSKRQ_STATS * is_xsk; j++)
ethtool_sprintf(data, xskrq_stats_desc[j].format, i);
for (j = 0; j < NUM_RQ_XDPSQ_STATS; j++)
@@ -2496,11 +2437,13 @@ static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(channels)
ch_stats_desc, j));
for (i = 0; i < max_nch; i++) {
+ struct mlx5e_rq_stats *rq_stats = &priv->channel_stats[i]->rq;
+
for (j = 0; j < NUM_RQ_STATS; j++)
mlx5e_ethtool_put_stat(
- data, MLX5E_READ_CTR64_CPU(
- &priv->channel_stats[i]->rq,
+ data, MLX5E_READ_CTR64_CPU(rq_stats,
rq_stats_desc, j));
+ *data = page_pool_ethtool_stats_get(*data, &rq_stats->page_pool_stats);
for (j = 0; j < NUM_XSKRQ_STATS * is_xsk; j++)
mlx5e_ethtool_put_stat(
data, MLX5E_READ_CTR64_CPU(
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
index 5961c569cfe01..aebf4838a76c9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
@@ -33,6 +33,8 @@
#ifndef __MLX5_EN_STATS_H__
#define __MLX5_EN_STATS_H__
+#include <net/page_pool/types.h>
+
#define MLX5E_READ_CTR64_CPU(ptr, dsc, i) \
(*(u64 *)((char *)ptr + dsc[i].offset))
#define MLX5E_READ_CTR64_BE(ptr, dsc, i) \
@@ -215,19 +217,7 @@ struct mlx5e_sw_stats {
u64 ch_aff_change;
u64 ch_force_irq;
u64 ch_eq_rearm;
-#ifdef CONFIG_PAGE_POOL_STATS
- u64 rx_pp_alloc_fast;
- u64 rx_pp_alloc_slow;
- u64 rx_pp_alloc_slow_high_order;
- u64 rx_pp_alloc_empty;
- u64 rx_pp_alloc_refill;
- u64 rx_pp_alloc_waive;
- u64 rx_pp_recycle_cached;
- u64 rx_pp_recycle_cache_full;
- u64 rx_pp_recycle_ring;
- u64 rx_pp_recycle_ring_full;
- u64 rx_pp_recycle_released_ref;
-#endif
+ struct page_pool_stats page_pool_stats;
#ifdef CONFIG_MLX5_EN_TLS
u64 tx_tls_encrypted_packets;
u64 tx_tls_encrypted_bytes;
@@ -381,19 +371,7 @@ struct mlx5e_rq_stats {
u64 arfs_err;
#endif
u64 recover;
-#ifdef CONFIG_PAGE_POOL_STATS
- u64 pp_alloc_fast;
- u64 pp_alloc_slow;
- u64 pp_alloc_slow_high_order;
- u64 pp_alloc_empty;
- u64 pp_alloc_refill;
- u64 pp_alloc_waive;
- u64 pp_recycle_cached;
- u64 pp_recycle_cache_full;
- u64 pp_recycle_ring;
- u64 pp_recycle_ring_full;
- u64 pp_recycle_released_ref;
-#endif
+ struct page_pool_stats page_pool_stats;
#ifdef CONFIG_MLX5_EN_TLS
u64 tls_decrypted_packets;
u64 tls_decrypted_bytes;
--
2.47.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH net-next v2 4/5] page_pool: Convert page_pool_recycle_stats to u64_stats_t.
2025-03-07 11:57 [PATCH net-next v2 0/5] page_pool: Convert stats to u64_stats_t Sebastian Andrzej Siewior
` (2 preceding siblings ...)
2025-03-07 11:57 ` [PATCH net-next v2 3/5] mlx5: Use generic code for page_pool statistics Sebastian Andrzej Siewior
@ 2025-03-07 11:57 ` Sebastian Andrzej Siewior
2025-03-07 11:57 ` [PATCH net-next v2 5/5] page_pool: Convert page_pool_alloc_stats " Sebastian Andrzej Siewior
4 siblings, 0 replies; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2025-03-07 11:57 UTC (permalink / raw)
To: linux-rdma, netdev
Cc: David S. Miller, Andrew Lunn, Eric Dumazet, Ilias Apalodimas,
Jakub Kicinski, Jesper Dangaard Brouer, Joe Damato,
Leon Romanovsky, Paolo Abeni, Saeed Mahameed, Simon Horman,
Tariq Toukan, Thomas Gleixner, Yunsheng Lin,
Sebastian Andrzej Siewior
Using u64 for statistics can lead to inconsistency on 32bit because an
update and a read requires to access two 32bit values.
This can be avoided by using u64_stats_t for the counters and
u64_stats_sync for the required synchronisation on 32bit platforms. The
synchronisation is a NOP on 64bit architectures.
Use u64_stats_t for the counters in page_pool_recycle_stats.
Add U64_STATS_ZERO, a static initializer for u64_stats_t.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
Documentation/networking/page_pool.rst | 6 +--
include/linux/u64_stats_sync.h | 5 +++
include/net/page_pool/types.h | 13 ++++---
net/core/page_pool.c | 52 ++++++++++++++++++--------
net/core/page_pool_user.c | 10 ++---
5 files changed, 58 insertions(+), 28 deletions(-)
diff --git a/Documentation/networking/page_pool.rst b/Documentation/networking/page_pool.rst
index 9d958128a57cb..5215fd51a334a 100644
--- a/Documentation/networking/page_pool.rst
+++ b/Documentation/networking/page_pool.rst
@@ -181,11 +181,11 @@ Stats
#ifdef CONFIG_PAGE_POOL_STATS
/* retrieve stats */
- struct page_pool_stats stats = { 0 };
+ struct page_pool_stats stats = { };
if (page_pool_get_stats(page_pool, &stats)) {
/* perhaps the driver reports statistics with ethool */
- ethtool_print_allocation_stats(&stats.alloc_stats);
- ethtool_print_recycle_stats(&stats.recycle_stats);
+ ethtool_print_allocation_stats(u64_stats_read(&stats.alloc_stats));
+ ethtool_print_recycle_stats(u64_stats_read(&stats.recycle_stats));
}
#endif
diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h
index 457879938fc19..086bd4a51cfe9 100644
--- a/include/linux/u64_stats_sync.h
+++ b/include/linux/u64_stats_sync.h
@@ -94,6 +94,8 @@ static inline void u64_stats_inc(u64_stats_t *p)
local64_inc(&p->v);
}
+#define U64_STATS_ZERO(_member, _name) {}
+
static inline void u64_stats_init(struct u64_stats_sync *syncp) { }
static inline void __u64_stats_update_begin(struct u64_stats_sync *syncp) { }
static inline void __u64_stats_update_end(struct u64_stats_sync *syncp) { }
@@ -141,6 +143,9 @@ static inline void u64_stats_inc(u64_stats_t *p)
seqcount_init(&__s->seq); \
} while (0)
+#define U64_STATS_ZERO(_member, _name) \
+ _member.seq = SEQCNT_ZERO(#_name#_member.seq)
+
static inline void __u64_stats_update_begin(struct u64_stats_sync *syncp)
{
preempt_disable_nested();
diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h
index 6d55e6cf5d0db..daf989d01436e 100644
--- a/include/net/page_pool/types.h
+++ b/include/net/page_pool/types.h
@@ -6,6 +6,7 @@
#include <linux/dma-direction.h>
#include <linux/ptr_ring.h>
#include <linux/types.h>
+#include <linux/u64_stats_sync.h>
#include <net/netmem.h>
#define PP_FLAG_DMA_MAP BIT(0) /* Should page_pool do the DMA
@@ -114,6 +115,7 @@ struct page_pool_alloc_stats {
/**
* struct page_pool_recycle_stats - recycling (freeing) statistics
+ * @syncp: synchronisations point for updates.
* @cached: recycling placed page in the page pool cache
* @cache_full: page pool cache was full
* @ring: page placed into the ptr ring
@@ -121,11 +123,12 @@ struct page_pool_alloc_stats {
* @released_refcnt: page released (and not recycled) because refcnt > 1
*/
struct page_pool_recycle_stats {
- u64 cached;
- u64 cache_full;
- u64 ring;
- u64 ring_full;
- u64 released_refcnt;
+ struct u64_stats_sync syncp;
+ u64_stats_t cached;
+ u64_stats_t cache_full;
+ u64_stats_t ring;
+ u64_stats_t ring_full;
+ u64_stats_t released_refcnt;
};
/**
diff --git a/net/core/page_pool.c b/net/core/page_pool.c
index 2290d80443d1e..312bdc5b5a8bf 100644
--- a/net/core/page_pool.c
+++ b/net/core/page_pool.c
@@ -37,21 +37,27 @@ DEFINE_STATIC_KEY_FALSE(page_pool_mem_providers);
#define BIAS_MAX (LONG_MAX >> 1)
#ifdef CONFIG_PAGE_POOL_STATS
-static DEFINE_PER_CPU(struct page_pool_recycle_stats, pp_system_recycle_stats);
+static DEFINE_PER_CPU(struct page_pool_recycle_stats, pp_system_recycle_stats) = {
+ U64_STATS_ZERO(.syncp, pp_system_recycle_stats),
+};
/* alloc_stat_inc is intended to be used in softirq context */
#define alloc_stat_inc(pool, __stat) (pool->alloc_stats.__stat++)
/* recycle_stat_inc is safe to use when preemption is possible. */
#define recycle_stat_inc(pool, __stat) \
do { \
- struct page_pool_recycle_stats __percpu *s = pool->recycle_stats; \
- this_cpu_inc(s->__stat); \
+ struct page_pool_recycle_stats *s = this_cpu_ptr(pool->recycle_stats); \
+ u64_stats_update_begin(&s->syncp); \
+ u64_stats_inc(&s->__stat); \
+ u64_stats_update_end(&s->syncp); \
} while (0)
#define recycle_stat_add(pool, __stat, val) \
do { \
- struct page_pool_recycle_stats __percpu *s = pool->recycle_stats; \
- this_cpu_add(s->__stat, val); \
+ struct page_pool_recycle_stats *s = this_cpu_ptr(pool->recycle_stats); \
+ u64_stats_update_begin(&s->syncp); \
+ u64_stats_add(&s->__stat, val); \
+ u64_stats_update_end(&s->syncp); \
} while (0)
static const char pp_stats[][ETH_GSTRING_LEN] = {
@@ -96,6 +102,7 @@ static const char pp_stats_mq[][ETH_GSTRING_LEN] = {
bool page_pool_get_stats(const struct page_pool *pool,
struct page_pool_stats *stats)
{
+ unsigned int start;
int cpu = 0;
if (!stats)
@@ -110,14 +117,24 @@ bool page_pool_get_stats(const struct page_pool *pool,
stats->alloc_stats.waive += pool->alloc_stats.waive;
for_each_possible_cpu(cpu) {
+ u64 cached, cache_full, ring, ring_full, released_refcnt;
const struct page_pool_recycle_stats *pcpu =
per_cpu_ptr(pool->recycle_stats, cpu);
- stats->recycle_stats.cached += pcpu->cached;
- stats->recycle_stats.cache_full += pcpu->cache_full;
- stats->recycle_stats.ring += pcpu->ring;
- stats->recycle_stats.ring_full += pcpu->ring_full;
- stats->recycle_stats.released_refcnt += pcpu->released_refcnt;
+ do {
+ start = u64_stats_fetch_begin(&pcpu->syncp);
+ cached = u64_stats_read(&pcpu->cached);
+ cache_full = u64_stats_read(&pcpu->cache_full);
+ ring = u64_stats_read(&pcpu->ring);
+ ring_full = u64_stats_read(&pcpu->ring_full);
+ released_refcnt = u64_stats_read(&pcpu->released_refcnt);
+ } while (u64_stats_fetch_retry(&pcpu->syncp, start));
+
+ u64_stats_add(&stats->recycle_stats.cached, cached);
+ u64_stats_add(&stats->recycle_stats.cache_full, cache_full);
+ u64_stats_add(&stats->recycle_stats.ring, ring);
+ u64_stats_add(&stats->recycle_stats.ring_full, ring_full);
+ u64_stats_add(&stats->recycle_stats.released_refcnt, released_refcnt);
}
return true;
@@ -162,11 +179,11 @@ u64 *page_pool_ethtool_stats_get(u64 *data, const void *stats)
*data++ = pool_stats->alloc_stats.empty;
*data++ = pool_stats->alloc_stats.refill;
*data++ = pool_stats->alloc_stats.waive;
- *data++ = pool_stats->recycle_stats.cached;
- *data++ = pool_stats->recycle_stats.cache_full;
- *data++ = pool_stats->recycle_stats.ring;
- *data++ = pool_stats->recycle_stats.ring_full;
- *data++ = pool_stats->recycle_stats.released_refcnt;
+ *data++ = u64_stats_read(&pool_stats->recycle_stats.cached);
+ *data++ = u64_stats_read(&pool_stats->recycle_stats.cache_full);
+ *data++ = u64_stats_read(&pool_stats->recycle_stats.ring);
+ *data++ = u64_stats_read(&pool_stats->recycle_stats.ring_full);
+ *data++ = u64_stats_read(&pool_stats->recycle_stats.released_refcnt);
return data;
}
@@ -270,9 +287,14 @@ static int page_pool_init(struct page_pool *pool,
#ifdef CONFIG_PAGE_POOL_STATS
if (!(pool->slow.flags & PP_FLAG_SYSTEM_POOL)) {
+ unsigned int cpu;
+
pool->recycle_stats = alloc_percpu(struct page_pool_recycle_stats);
if (!pool->recycle_stats)
return -ENOMEM;
+
+ for_each_possible_cpu(cpu)
+ u64_stats_init(&per_cpu_ptr(pool->recycle_stats, cpu)->syncp);
} else {
/* For system page pool instance we use a singular stats object
* instead of allocating a separate percpu variable for each
diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c
index 6677e0c2e2565..0d038c0c8996d 100644
--- a/net/core/page_pool_user.c
+++ b/net/core/page_pool_user.c
@@ -149,15 +149,15 @@ page_pool_nl_stats_fill(struct sk_buff *rsp, const struct page_pool *pool,
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE,
stats.alloc_stats.waive) ||
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED,
- stats.recycle_stats.cached) ||
+ u64_stats_read(&stats.recycle_stats.cached)) ||
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL,
- stats.recycle_stats.cache_full) ||
+ u64_stats_read(&stats.recycle_stats.cache_full)) ||
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING,
- stats.recycle_stats.ring) ||
+ u64_stats_read(&stats.recycle_stats.ring)) ||
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL,
- stats.recycle_stats.ring_full) ||
+ u64_stats_read(&stats.recycle_stats.ring_full)) ||
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT,
- stats.recycle_stats.released_refcnt))
+ u64_stats_read(&stats.recycle_stats.released_refcnt)))
goto err_cancel_msg;
genlmsg_end(rsp, hdr);
--
2.47.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH net-next v2 5/5] page_pool: Convert page_pool_alloc_stats to u64_stats_t.
2025-03-07 11:57 [PATCH net-next v2 0/5] page_pool: Convert stats to u64_stats_t Sebastian Andrzej Siewior
` (3 preceding siblings ...)
2025-03-07 11:57 ` [PATCH net-next v2 4/5] page_pool: Convert page_pool_recycle_stats to u64_stats_t Sebastian Andrzej Siewior
@ 2025-03-07 11:57 ` Sebastian Andrzej Siewior
4 siblings, 0 replies; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2025-03-07 11:57 UTC (permalink / raw)
To: linux-rdma, netdev
Cc: David S. Miller, Andrew Lunn, Eric Dumazet, Ilias Apalodimas,
Jakub Kicinski, Jesper Dangaard Brouer, Joe Damato,
Leon Romanovsky, Paolo Abeni, Saeed Mahameed, Simon Horman,
Tariq Toukan, Thomas Gleixner, Yunsheng Lin,
Sebastian Andrzej Siewior
Using u64 for statistics can lead to inconsistency on 32bit because an
update and a read requires to access two 32bit values.
This can be avoided by using u64_stats_t for the counters and
u64_stats_sync for the required synchronisation on 32bit platforms. The
synchronisation is a NOP on 64bit architectures.
Use u64_stats_t for the counters in page_pool_alloc_stats.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
include/net/page_pool/types.h | 14 ++++++-----
net/core/page_pool.c | 47 +++++++++++++++++++++++++----------
net/core/page_pool_user.c | 12 ++++-----
3 files changed, 48 insertions(+), 25 deletions(-)
diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h
index daf989d01436e..78984b9286c6b 100644
--- a/include/net/page_pool/types.h
+++ b/include/net/page_pool/types.h
@@ -96,6 +96,7 @@ struct page_pool_params {
#ifdef CONFIG_PAGE_POOL_STATS
/**
* struct page_pool_alloc_stats - allocation statistics
+ * @syncp: synchronisations point for updates.
* @fast: successful fast path allocations
* @slow: slow path order-0 allocations
* @slow_high_order: slow path high order allocations
@@ -105,12 +106,13 @@ struct page_pool_params {
* the cache due to a NUMA mismatch
*/
struct page_pool_alloc_stats {
- u64 fast;
- u64 slow;
- u64 slow_high_order;
- u64 empty;
- u64 refill;
- u64 waive;
+ struct u64_stats_sync syncp;
+ u64_stats_t fast;
+ u64_stats_t slow;
+ u64_stats_t slow_high_order;
+ u64_stats_t empty;
+ u64_stats_t refill;
+ u64_stats_t waive;
};
/**
diff --git a/net/core/page_pool.c b/net/core/page_pool.c
index 312bdc5b5a8bf..9f4a390964195 100644
--- a/net/core/page_pool.c
+++ b/net/core/page_pool.c
@@ -42,7 +42,14 @@ static DEFINE_PER_CPU(struct page_pool_recycle_stats, pp_system_recycle_stats) =
};
/* alloc_stat_inc is intended to be used in softirq context */
-#define alloc_stat_inc(pool, __stat) (pool->alloc_stats.__stat++)
+#define alloc_stat_inc(pool, __stat) \
+ do { \
+ struct page_pool_alloc_stats *s = &pool->alloc_stats; \
+ u64_stats_update_begin(&s->syncp); \
+ u64_stats_inc(&s->__stat); \
+ u64_stats_update_end(&s->syncp); \
+ } while (0)
+
/* recycle_stat_inc is safe to use when preemption is possible. */
#define recycle_stat_inc(pool, __stat) \
do { \
@@ -102,19 +109,32 @@ static const char pp_stats_mq[][ETH_GSTRING_LEN] = {
bool page_pool_get_stats(const struct page_pool *pool,
struct page_pool_stats *stats)
{
+ u64 fast, slow, slow_high_order, empty, refill, waive;
+ const struct page_pool_alloc_stats *alloc_stats;
unsigned int start;
int cpu = 0;
if (!stats)
return false;
+ alloc_stats = &pool->alloc_stats;
/* The caller is responsible to initialize stats. */
- stats->alloc_stats.fast += pool->alloc_stats.fast;
- stats->alloc_stats.slow += pool->alloc_stats.slow;
- stats->alloc_stats.slow_high_order += pool->alloc_stats.slow_high_order;
- stats->alloc_stats.empty += pool->alloc_stats.empty;
- stats->alloc_stats.refill += pool->alloc_stats.refill;
- stats->alloc_stats.waive += pool->alloc_stats.waive;
+ do {
+ start = u64_stats_fetch_begin(&alloc_stats->syncp);
+ fast = u64_stats_read(&alloc_stats->fast);
+ slow = u64_stats_read(&alloc_stats->slow);
+ slow_high_order = u64_stats_read(&alloc_stats->slow_high_order);
+ empty = u64_stats_read(&alloc_stats->empty);
+ refill = u64_stats_read(&alloc_stats->refill);
+ waive = u64_stats_read(&alloc_stats->waive);
+ } while (u64_stats_fetch_retry(&alloc_stats->syncp, start));
+
+ u64_stats_add(&stats->alloc_stats.fast, fast);
+ u64_stats_add(&stats->alloc_stats.slow, slow);
+ u64_stats_add(&stats->alloc_stats.slow_high_order, slow_high_order);
+ u64_stats_add(&stats->alloc_stats.empty, empty);
+ u64_stats_add(&stats->alloc_stats.refill, refill);
+ u64_stats_add(&stats->alloc_stats.waive, waive);
for_each_possible_cpu(cpu) {
u64 cached, cache_full, ring, ring_full, released_refcnt;
@@ -173,12 +193,12 @@ u64 *page_pool_ethtool_stats_get(u64 *data, const void *stats)
{
const struct page_pool_stats *pool_stats = stats;
- *data++ = pool_stats->alloc_stats.fast;
- *data++ = pool_stats->alloc_stats.slow;
- *data++ = pool_stats->alloc_stats.slow_high_order;
- *data++ = pool_stats->alloc_stats.empty;
- *data++ = pool_stats->alloc_stats.refill;
- *data++ = pool_stats->alloc_stats.waive;
+ *data++ = u64_stats_read(&pool_stats->alloc_stats.fast);
+ *data++ = u64_stats_read(&pool_stats->alloc_stats.slow);
+ *data++ = u64_stats_read(&pool_stats->alloc_stats.slow_high_order);
+ *data++ = u64_stats_read(&pool_stats->alloc_stats.empty);
+ *data++ = u64_stats_read(&pool_stats->alloc_stats.refill);
+ *data++ = u64_stats_read(&pool_stats->alloc_stats.waive);
*data++ = u64_stats_read(&pool_stats->recycle_stats.cached);
*data++ = u64_stats_read(&pool_stats->recycle_stats.cache_full);
*data++ = u64_stats_read(&pool_stats->recycle_stats.ring);
@@ -303,6 +323,7 @@ static int page_pool_init(struct page_pool *pool,
pool->recycle_stats = &pp_system_recycle_stats;
pool->system = true;
}
+ u64_stats_init(&pool->alloc_stats.syncp);
#endif
if (ptr_ring_init(&pool->ring, ring_qsize, GFP_KERNEL) < 0) {
diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c
index 0d038c0c8996d..c368cb141147f 100644
--- a/net/core/page_pool_user.c
+++ b/net/core/page_pool_user.c
@@ -137,17 +137,17 @@ page_pool_nl_stats_fill(struct sk_buff *rsp, const struct page_pool *pool,
nla_nest_end(rsp, nest);
if (nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST,
- stats.alloc_stats.fast) ||
+ u64_stats_read(&stats.alloc_stats.fast)) ||
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW,
- stats.alloc_stats.slow) ||
+ u64_stats_read(&stats.alloc_stats.slow)) ||
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER,
- stats.alloc_stats.slow_high_order) ||
+ u64_stats_read(&stats.alloc_stats.slow_high_order)) ||
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY,
- stats.alloc_stats.empty) ||
+ u64_stats_read(&stats.alloc_stats.empty)) ||
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL,
- stats.alloc_stats.refill) ||
+ u64_stats_read(&stats.alloc_stats.refill)) ||
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE,
- stats.alloc_stats.waive) ||
+ u64_stats_read(&stats.alloc_stats.waive)) ||
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED,
u64_stats_read(&stats.recycle_stats.cached)) ||
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL,
--
2.47.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH net-next v2 2/5] page_pool: Add per-queue statistics.
2025-03-07 11:57 ` [PATCH net-next v2 2/5] page_pool: Add per-queue statistics Sebastian Andrzej Siewior
@ 2025-03-07 16:11 ` Jakub Kicinski
2025-03-07 16:50 ` Sebastian Andrzej Siewior
0 siblings, 1 reply; 11+ messages in thread
From: Jakub Kicinski @ 2025-03-07 16:11 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: linux-rdma, netdev, David S. Miller, Andrew Lunn, Eric Dumazet,
Ilias Apalodimas, Jesper Dangaard Brouer, Joe Damato,
Leon Romanovsky, Paolo Abeni, Saeed Mahameed, Simon Horman,
Tariq Toukan, Thomas Gleixner, Yunsheng Lin
On Fri, 7 Mar 2025 12:57:19 +0100 Sebastian Andrzej Siewior wrote:
> The mlx5 driver supports per-channel statistics. To make support generic
> it is required to have a template to fill the individual channel/ queue.
>
> Provide page_pool_ethtool_stats_get_strings_mq() to fill the strings for
> multiple queue.
Sorry to say this is useless as a common helper, you should move it
to mlx5.
The page pool stats have a standard interface, they are exposed over
netlink. If my grep-foo isn't failing me no driver uses the exact
strings mlx5 uses. "New drivers" are not supposed to add these stats
to ethtool -S, and should just steer users towards the netlink stats.
IOW mlx5 is and will remain the only user of this helper forever.
--
pw-bot: cr
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH net-next v2 2/5] page_pool: Add per-queue statistics.
2025-03-07 16:11 ` Jakub Kicinski
@ 2025-03-07 16:50 ` Sebastian Andrzej Siewior
2025-03-07 16:59 ` Jakub Kicinski
0 siblings, 1 reply; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2025-03-07 16:50 UTC (permalink / raw)
To: Jakub Kicinski
Cc: linux-rdma, netdev, David S. Miller, Andrew Lunn, Eric Dumazet,
Ilias Apalodimas, Jesper Dangaard Brouer, Joe Damato,
Leon Romanovsky, Paolo Abeni, Saeed Mahameed, Simon Horman,
Tariq Toukan, Thomas Gleixner, Yunsheng Lin
On 2025-03-07 08:11:35 [-0800], Jakub Kicinski wrote:
> On Fri, 7 Mar 2025 12:57:19 +0100 Sebastian Andrzej Siewior wrote:
> > The mlx5 driver supports per-channel statistics. To make support generic
> > it is required to have a template to fill the individual channel/ queue.
> >
> > Provide page_pool_ethtool_stats_get_strings_mq() to fill the strings for
> > multiple queue.
>
> Sorry to say this is useless as a common helper, you should move it
> to mlx5.
>
> The page pool stats have a standard interface, they are exposed over
> netlink. If my grep-foo isn't failing me no driver uses the exact
> strings mlx5 uses. "New drivers" are not supposed to add these stats
> to ethtool -S, and should just steer users towards the netlink stats.
>
> IOW mlx5 is and will remain the only user of this helper forever.
Okay, so per-runqueue stats is not something other/ new drivers are
interested in?
The strings are the same, except for the rx%d_ prefix, but yes this
makes it unique.
The mlx5 folks seem to be the only one interested in this. The veth
driver for instance iterates over real_num_rx_queues and adds all
per-queue stats into one counter. It could also expose this per-runqueue
as it does with xdp_packets for instance. But then it uses the
rx_queue_%d prefix…
I don't care, I just intended to provide some generic facility so we
don't have every driver rolling its own thing. I have no problem to move
this to the mlx5 driver.
Sebastian
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH net-next v2 2/5] page_pool: Add per-queue statistics.
2025-03-07 16:50 ` Sebastian Andrzej Siewior
@ 2025-03-07 16:59 ` Jakub Kicinski
2025-03-07 17:05 ` Sebastian Andrzej Siewior
0 siblings, 1 reply; 11+ messages in thread
From: Jakub Kicinski @ 2025-03-07 16:59 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: linux-rdma, netdev, David S. Miller, Andrew Lunn, Eric Dumazet,
Ilias Apalodimas, Jesper Dangaard Brouer, Joe Damato,
Leon Romanovsky, Paolo Abeni, Saeed Mahameed, Simon Horman,
Tariq Toukan, Thomas Gleixner, Yunsheng Lin
On Fri, 7 Mar 2025 17:50:46 +0100 Sebastian Andrzej Siewior wrote:
> On 2025-03-07 08:11:35 [-0800], Jakub Kicinski wrote:
> > On Fri, 7 Mar 2025 12:57:19 +0100 Sebastian Andrzej Siewior wrote:
> > > The mlx5 driver supports per-channel statistics. To make support generic
> > > it is required to have a template to fill the individual channel/ queue.
> > >
> > > Provide page_pool_ethtool_stats_get_strings_mq() to fill the strings for
> > > multiple queue.
> >
> > Sorry to say this is useless as a common helper, you should move it
> > to mlx5.
> >
> > The page pool stats have a standard interface, they are exposed over
> > netlink. If my grep-foo isn't failing me no driver uses the exact
> > strings mlx5 uses. "New drivers" are not supposed to add these stats
> > to ethtool -S, and should just steer users towards the netlink stats.
> >
> > IOW mlx5 is and will remain the only user of this helper forever.
>
> Okay, so per-runqueue stats is not something other/ new drivers are
> interested in?
> The strings are the same, except for the rx%d_ prefix, but yes this
> makes it unique.
> The mlx5 folks seem to be the only one interested in this. The veth
> driver for instance iterates over real_num_rx_queues and adds all
> per-queue stats into one counter. It could also expose this per-runqueue
> as it does with xdp_packets for instance. But then it uses the
> rx_queue_%d prefix…
What I'm saying is they are already available per queue, via netlink,
with no driver work necessary. See tools/net/ynl/samples/page-pool.c
The mlx5 stats predate the standard interface.
> I don't care, I just intended to provide some generic facility so we
> don't have every driver rolling its own thing. I have no problem to move
> this to the mlx5 driver.
Thanks, and sorry for not catching the conversation earlier.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH net-next v2 2/5] page_pool: Add per-queue statistics.
2025-03-07 16:59 ` Jakub Kicinski
@ 2025-03-07 17:05 ` Sebastian Andrzej Siewior
0 siblings, 0 replies; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2025-03-07 17:05 UTC (permalink / raw)
To: Jakub Kicinski
Cc: linux-rdma, netdev, David S. Miller, Andrew Lunn, Eric Dumazet,
Ilias Apalodimas, Jesper Dangaard Brouer, Joe Damato,
Leon Romanovsky, Paolo Abeni, Saeed Mahameed, Simon Horman,
Tariq Toukan, Thomas Gleixner, Yunsheng Lin
On 2025-03-07 08:59:46 [-0800], Jakub Kicinski wrote:
> What I'm saying is they are already available per queue, via netlink,
> with no driver work necessary. See tools/net/ynl/samples/page-pool.c
> The mlx5 stats predate the standard interface.
ach, got you.
> > I don't care, I just intended to provide some generic facility so we
> > don't have every driver rolling its own thing. I have no problem to move
> > this to the mlx5 driver.
>
> Thanks, and sorry for not catching the conversation earlier.
No worries, thanks.
Sebastian
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH net-next v2 1/5] page_pool: Provide an empty page_pool_stats for disabled stats.
2025-03-07 11:57 ` [PATCH net-next v2 1/5] page_pool: Provide an empty page_pool_stats for disabled stats Sebastian Andrzej Siewior
@ 2025-03-13 14:40 ` Ilias Apalodimas
0 siblings, 0 replies; 11+ messages in thread
From: Ilias Apalodimas @ 2025-03-13 14:40 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: linux-rdma, netdev, David S. Miller, Andrew Lunn, Eric Dumazet,
Jakub Kicinski, Jesper Dangaard Brouer, Joe Damato,
Leon Romanovsky, Paolo Abeni, Saeed Mahameed, Simon Horman,
Tariq Toukan, Thomas Gleixner, Yunsheng Lin
Hi Sebastian
[...]
> @@ -81,6 +81,12 @@ static inline u64 *page_pool_ethtool_stats_get(u64 *data, const void *stats)
> {
> return data;
> }
> +
> +static inline bool page_pool_get_stats(const struct page_pool *pool,
> + struct page_pool_stats *stats)
> +{
> + return false;
> +}
[...]
That looks reasonable. Unfortunately, we have some drivers that don't
check the result of this function, but I guess that is a driver-only
problem...
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2025-03-13 14:40 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-07 11:57 [PATCH net-next v2 0/5] page_pool: Convert stats to u64_stats_t Sebastian Andrzej Siewior
2025-03-07 11:57 ` [PATCH net-next v2 1/5] page_pool: Provide an empty page_pool_stats for disabled stats Sebastian Andrzej Siewior
2025-03-13 14:40 ` Ilias Apalodimas
2025-03-07 11:57 ` [PATCH net-next v2 2/5] page_pool: Add per-queue statistics Sebastian Andrzej Siewior
2025-03-07 16:11 ` Jakub Kicinski
2025-03-07 16:50 ` Sebastian Andrzej Siewior
2025-03-07 16:59 ` Jakub Kicinski
2025-03-07 17:05 ` Sebastian Andrzej Siewior
2025-03-07 11:57 ` [PATCH net-next v2 3/5] mlx5: Use generic code for page_pool statistics Sebastian Andrzej Siewior
2025-03-07 11:57 ` [PATCH net-next v2 4/5] page_pool: Convert page_pool_recycle_stats to u64_stats_t Sebastian Andrzej Siewior
2025-03-07 11:57 ` [PATCH net-next v2 5/5] page_pool: Convert page_pool_alloc_stats " Sebastian Andrzej Siewior
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).