From: Thomas Monjalon <thomas@monjalon.net>
To: dev@dpdk.org
Cc: shperetz@nvidia.com, viacheslavo@nvidia.com,
bruce.richardson@intel.com, mb@smartsharesystems.com,
stephen@networkplumber.org
Subject: [PATCH v3 2/5] mbuf: record mbuf operations history
Date: Wed, 1 Oct 2025 01:25:03 +0200 [thread overview]
Message-ID: <20250930233828.3999565-3-thomas@monjalon.net> (raw)
In-Reply-To: <20250930233828.3999565-1-thomas@monjalon.net>
From: Shani Peretz <shperetz@nvidia.com>
This feature is designed to monitor the lifecycle of mbufs
as they move between the application and the PMD.
It will allow to track the operations and transitions
of each mbuf throughout the system, helping in debugging
and understanding objects flow.
As a debug feature impacting the data path, it is disabled by default.
The implementation uses a dynamic field to store a 64-bit
atomic history value in each mbuf. Each operation is represented
by a 4-bit value, allowing up to 16 operations to be tracked.
Atomic operations ensure thread safety for cloned mbufs accessed
by multiple lcores. The dynamic field is automatically initialized
when the first mbuf pool is created.
Some operations done in the mbuf library are marked.
More operations from other libraries or the application can be marked.
Signed-off-by: Shani Peretz <shperetz@nvidia.com>
Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
---
config/meson.build | 1 +
lib/mbuf/mbuf_history.c | 214 ++++++++++++++++++++++++++++++++++++
lib/mbuf/meson.build | 2 +
lib/mbuf/rte_mbuf.c | 6 +-
lib/mbuf/rte_mbuf.h | 13 ++-
lib/mbuf/rte_mbuf_dyn.h | 18 +++
lib/mbuf/rte_mbuf_history.h | 174 +++++++++++++++++++++++++++++
meson_options.txt | 2 +
8 files changed, 427 insertions(+), 3 deletions(-)
create mode 100644 lib/mbuf/mbuf_history.c
create mode 100644 lib/mbuf/rte_mbuf_history.h
diff --git a/config/meson.build b/config/meson.build
index 55497f0bf5..d1f21f3115 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -379,6 +379,7 @@ if get_option('mbuf_refcnt_atomic')
dpdk_conf.set('RTE_MBUF_REFCNT_ATOMIC', true)
endif
dpdk_conf.set10('RTE_IOVA_IN_MBUF', get_option('enable_iova_as_pa'))
+dpdk_conf.set10('RTE_MBUF_HISTORY_DEBUG', get_option('enable_mbuf_history'))
compile_time_cpuflags = []
subdir(arch_subdir)
diff --git a/lib/mbuf/mbuf_history.c b/lib/mbuf/mbuf_history.c
new file mode 100644
index 0000000000..852cf0f89a
--- /dev/null
+++ b/lib/mbuf/mbuf_history.c
@@ -0,0 +1,214 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 NVIDIA Corporation & Affiliates
+ */
+
+#include <rte_errno.h>
+#include <eal_export.h>
+#include <rte_bitops.h>
+#include <rte_mempool.h>
+
+#include "rte_mbuf_history.h"
+#include "rte_mbuf_dyn.h"
+#include "rte_mbuf.h"
+#include "mbuf_log.h"
+
+/* Dynamic field offset */
+RTE_EXPORT_SYMBOL(rte_mbuf_history_field_offset);
+int rte_mbuf_history_field_offset = -1;
+
+#if RTE_MBUF_HISTORY_DEBUG
+
+#define HISTORY_LAST_MASK (RTE_BIT64(RTE_MBUF_HISTORY_BITS) - 1)
+
+/* Dynamic field definition for mbuf history */
+static const struct rte_mbuf_dynfield mbuf_dynfield_history = {
+ .name = RTE_MBUF_DYNFIELD_HISTORY_NAME,
+ .size = sizeof(rte_mbuf_history_t),
+ .align = RTE_ALIGN(sizeof(rte_mbuf_history_t), 8),
+};
+
+/* Context structure for statistics counting and history printing */
+struct count_and_print_ctx {
+ uint64_t *stats;
+ FILE *f;
+};
+
+static uint64_t
+mbuf_history_get(const struct rte_mbuf *m)
+{
+ if (rte_mbuf_history_field_offset < 0 || m == NULL)
+ return 0;
+
+ rte_mbuf_history_t *history = RTE_MBUF_DYNFIELD(m,
+ rte_mbuf_history_field_offset, rte_mbuf_history_t *);
+
+ return rte_atomic_load_explicit(history, rte_memory_order_acquire);
+}
+
+static int
+mbuf_history_print(FILE *f, const struct rte_mbuf *m, uint64_t history)
+{
+ return fprintf(f, "mbuf %p: %016" PRIx64 "\n", m, history);
+}
+
+static void
+mbuf_history_count_stats_and_print(struct rte_mempool *mp __rte_unused,
+ void *opaque, void *obj, unsigned obj_idx __rte_unused)
+{
+ struct count_and_print_ctx *ctx = (struct count_and_print_ctx *)opaque;
+ struct rte_mbuf *m = (struct rte_mbuf *)obj;
+ uint64_t history, last_op;
+
+ if (obj == NULL || ctx == NULL || ctx->stats == NULL || ctx->f == NULL)
+ return;
+
+ history = mbuf_history_get(m);
+ /* Extract the most recent operation */
+ last_op = history & HISTORY_LAST_MASK;
+ RTE_ASSERT(last_op < RTE_MBUF_HISTORY_OP_MAX);
+
+ ctx->stats[last_op]++;
+ ctx->stats[RTE_MBUF_HISTORY_OP_MAX]++; /* total */
+
+ if (history != 0)
+ mbuf_history_print(ctx->f, m, history);
+}
+
+static void
+mbuf_history_get_stats(struct rte_mempool *mp, void *arg)
+{
+ FILE *f = (FILE *)arg;
+ uint64_t stats[RTE_MBUF_HISTORY_OP_MAX + 1] = {0};
+ struct count_and_print_ctx ctx = {
+ .stats = stats,
+ .f = f
+ };
+
+ if (f == NULL)
+ return;
+
+ /* Output mempool header */
+ fprintf(f, "mempool <%s>@%p\n", mp->name, mp);
+
+ /* Single pass: collect statistics and print mbuf history */
+ rte_mempool_obj_iter(mp, mbuf_history_count_stats_and_print, &ctx);
+
+ /* Calculate total allocated mbufs */
+ uint64_t total_allocated =
+ stats[RTE_MBUF_HISTORY_OP_LIB_ALLOC] +
+ stats[RTE_MBUF_HISTORY_OP_PMD_ALLOC] +
+ stats[RTE_MBUF_HISTORY_OP_APP_ALLOC] +
+ stats[RTE_MBUF_HISTORY_OP_RX] +
+ stats[RTE_MBUF_HISTORY_OP_TX] +
+ stats[RTE_MBUF_HISTORY_OP_PREP_TX] +
+ stats[RTE_MBUF_HISTORY_OP_BUSY_TX] +
+ stats[RTE_MBUF_HISTORY_OP_ENQUEUE] +
+ stats[RTE_MBUF_HISTORY_OP_DEQUEUE];
+
+ /* Print statistics summary */
+ fprintf(f, " populated = %u\n", mp->populated_size);
+ fprintf(f, " never allocated = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_NEVER]);
+ fprintf(f, " lib free = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_LIB_FREE]);
+ fprintf(f, " PMD free = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_PMD_FREE]);
+ fprintf(f, " app free = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_APP_FREE]);
+ fprintf(f, " allocated = %" PRIu64 "\n", total_allocated);
+ fprintf(f, " lib alloc = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_LIB_ALLOC]);
+ fprintf(f, " PMD alloc = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_PMD_ALLOC]);
+ fprintf(f, " app alloc = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_APP_ALLOC]);
+ fprintf(f, " Rx = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_RX]);
+ fprintf(f, " Tx = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_TX]);
+ fprintf(f, " prep Tx = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_PREP_TX]);
+ fprintf(f, " busy Tx = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_BUSY_TX]);
+ fprintf(f, " enqueue = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_ENQUEUE]);
+ fprintf(f, " dequeue = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_DEQUEUE]);
+ fprintf(f, " user defined 1 = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_USR1]);
+ fprintf(f, " user defined 2 = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_USR2]);
+ fprintf(f, " counted total = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_MAX]);
+}
+
+#endif /* RTE_MBUF_HISTORY_DEBUG */
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_mbuf_history_dump, 25.11)
+void rte_mbuf_history_dump(FILE *f, const struct rte_mbuf *m)
+{
+#if !RTE_MBUF_HISTORY_DEBUG
+ RTE_SET_USED(f);
+ RTE_SET_USED(m);
+ MBUF_LOG(INFO, "mbuf history recorder is not enabled");
+#else
+ if (f == NULL) {
+ MBUF_LOG(ERR, "Invalid mbuf dump file.");
+ return;
+ }
+ if (m == NULL) {
+ fprintf(f, "ERROR: Invalid mbuf pointer\n");
+ return;
+ }
+ if (rte_mbuf_history_field_offset < 0) {
+ fprintf(f, "WARNING: mbuf history not initialized. Call rte_mbuf_history_init() first.\n");
+ return;
+ }
+ mbuf_history_print(f, m, mbuf_history_get(m));
+#endif
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_mbuf_history_dump_mempool, 25.11)
+void rte_mbuf_history_dump_mempool(FILE *f, struct rte_mempool *mp)
+{
+#if !RTE_MBUF_HISTORY_DEBUG
+ RTE_SET_USED(f);
+ RTE_SET_USED(mp);
+ MBUF_LOG(INFO, "mbuf history recorder is not enabled");
+#else
+ if (f == NULL) {
+ MBUF_LOG(ERR, "Invalid mbuf dump file.");
+ return;
+ }
+ if (mp == NULL) {
+ fprintf(f, "ERROR: Invalid mempool pointer\n");
+ return;
+ }
+ if (rte_mbuf_history_field_offset < 0) {
+ fprintf(f, "WARNING: mbuf history not initialized. Call rte_mbuf_history_init() first.\n");
+ return;
+ }
+ mbuf_history_get_stats(mp, f);
+#endif
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_mbuf_history_dump_all, 25.11)
+void rte_mbuf_history_dump_all(FILE *f)
+{
+#if !RTE_MBUF_HISTORY_DEBUG
+ RTE_SET_USED(f);
+ MBUF_LOG(INFO, "mbuf history recorder is not enabled");
+#else
+ if (f == NULL) {
+ MBUF_LOG(ERR, "Invalid mbuf dump file.");
+ return;
+ }
+ fprintf(f, "mbuf history statistics:\n");
+ if (rte_mbuf_history_field_offset < 0) {
+ fprintf(f, "WARNING: mbuf history not initialized. Call rte_mbuf_history_init() first.\n\n");
+ return;
+ }
+ rte_mempool_walk(mbuf_history_get_stats, f);
+#endif
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_mbuf_history_init, 25.11)
+void rte_mbuf_history_init(void)
+{
+#if RTE_MBUF_HISTORY_DEBUG
+ if (rte_mbuf_history_field_offset >= 0) {
+ /* already initialized */
+ return;
+ }
+
+ rte_mbuf_history_field_offset = rte_mbuf_dynfield_register(&mbuf_dynfield_history);
+ if (rte_mbuf_history_field_offset < 0) {
+ MBUF_LOG(ERR, "Failed to register mbuf history dynamic field: %s\n",
+ rte_strerror(rte_errno));
+ }
+#endif
+}
diff --git a/lib/mbuf/meson.build b/lib/mbuf/meson.build
index 0435c5e628..a394db2b19 100644
--- a/lib/mbuf/meson.build
+++ b/lib/mbuf/meson.build
@@ -2,6 +2,7 @@
# Copyright(c) 2017 Intel Corporation
sources = files(
+ 'mbuf_history.c',
'rte_mbuf.c',
'rte_mbuf_ptype.c',
'rte_mbuf_pool_ops.c',
@@ -13,5 +14,6 @@ headers = files(
'rte_mbuf_ptype.h',
'rte_mbuf_pool_ops.h',
'rte_mbuf_dyn.h',
+ 'rte_mbuf_history.h',
)
deps += ['mempool']
diff --git a/lib/mbuf/rte_mbuf.c b/lib/mbuf/rte_mbuf.c
index 22d7cfc475..d96c2196a3 100644
--- a/lib/mbuf/rte_mbuf.c
+++ b/lib/mbuf/rte_mbuf.c
@@ -41,6 +41,8 @@ rte_pktmbuf_pool_init(struct rte_mempool *mp, void *opaque_arg)
sizeof(struct rte_pktmbuf_pool_private));
RTE_ASSERT(mp->elt_size >= sizeof(struct rte_mbuf));
+ rte_mbuf_history_init();
+
/* if no structure is provided, assume no mbuf private area */
user_mbp_priv = opaque_arg;
if (user_mbp_priv == NULL) {
@@ -515,8 +517,10 @@ void rte_pktmbuf_free_bulk(struct rte_mbuf **mbufs, unsigned int count)
} while (m != NULL);
}
- if (nb_pending > 0)
+ if (nb_pending > 0) {
+ rte_mbuf_history_mark_bulk(pending, nb_pending, RTE_MBUF_HISTORY_OP_LIB_FREE);
rte_mempool_put_bulk(pending[0]->pool, (void **)pending, nb_pending);
+ }
}
/* Creates a shallow copy of mbuf */
diff --git a/lib/mbuf/rte_mbuf.h b/lib/mbuf/rte_mbuf.h
index 06ab7502a5..a6c6b21253 100644
--- a/lib/mbuf/rte_mbuf.h
+++ b/lib/mbuf/rte_mbuf.h
@@ -40,6 +40,7 @@
#include <rte_branch_prediction.h>
#include <rte_mbuf_ptype.h>
#include <rte_mbuf_core.h>
+#include <rte_mbuf_history.h>
#ifdef __cplusplus
extern "C" {
@@ -607,6 +608,7 @@ static inline struct rte_mbuf *rte_mbuf_raw_alloc(struct rte_mempool *mp)
if (rte_mempool_get(mp, &ret.ptr) < 0)
return NULL;
__rte_mbuf_raw_sanity_check(ret.m);
+ rte_mbuf_history_mark(ret.m, RTE_MBUF_HISTORY_OP_LIB_ALLOC);
return ret.m;
}
@@ -642,9 +644,12 @@ static __rte_always_inline int
rte_mbuf_raw_alloc_bulk(struct rte_mempool *mp, struct rte_mbuf **mbufs, unsigned int count)
{
int rc = rte_mempool_get_bulk(mp, (void **)mbufs, count);
- if (likely(rc == 0))
- for (unsigned int idx = 0; idx < count; idx++)
+ if (likely(rc == 0)) {
+ for (unsigned int idx = 0; idx < count; idx++) {
__rte_mbuf_raw_sanity_check(mbufs[idx]);
+ rte_mbuf_history_mark(mbufs[idx], RTE_MBUF_HISTORY_OP_LIB_ALLOC);
+ }
+ }
return rc;
}
@@ -667,6 +672,7 @@ rte_mbuf_raw_free(struct rte_mbuf *m)
{
__rte_mbuf_raw_sanity_check(m);
rte_mempool_put(m->pool, m);
+ rte_mbuf_history_mark(m, RTE_MBUF_HISTORY_OP_LIB_FREE);
}
/**
@@ -701,6 +707,7 @@ rte_mbuf_raw_free_bulk(struct rte_mempool *mp, struct rte_mbuf **mbufs, unsigned
RTE_ASSERT(m != NULL);
RTE_ASSERT(m->pool == mp);
__rte_mbuf_raw_sanity_check(m);
+ rte_mbuf_history_mark(mbufs[idx], RTE_MBUF_HISTORY_OP_LIB_FREE);
}
rte_mempool_put_bulk(mp, (void **)mbufs, count);
@@ -1013,6 +1020,8 @@ static inline int rte_pktmbuf_alloc_bulk(struct rte_mempool *pool,
if (unlikely(rc))
return rc;
+ rte_mbuf_history_mark_bulk(mbufs, count, RTE_MBUF_HISTORY_OP_LIB_ALLOC);
+
/* To understand duff's device on loop unwinding optimization, see
* https://en.wikipedia.org/wiki/Duff's_device.
* Here while() loop is used rather than do() while{} to avoid extra
diff --git a/lib/mbuf/rte_mbuf_dyn.h b/lib/mbuf/rte_mbuf_dyn.h
index 865c90f579..dc1d4f146a 100644
--- a/lib/mbuf/rte_mbuf_dyn.h
+++ b/lib/mbuf/rte_mbuf_dyn.h
@@ -69,6 +69,7 @@
#include <stdio.h>
#include <stdint.h>
+#include <rte_stdatomic.h>
#ifdef __cplusplus
extern "C" {
@@ -240,6 +241,23 @@ void rte_mbuf_dyn_dump(FILE *out);
* and parameters together.
*/
+/**
+ * The mbuf history dynamic field provides lifecycle tracking
+ * for mbuf objects through the system.
+ * It records a fixed set of predefined operations for debugging.
+ */
+#define RTE_MBUF_DYNFIELD_HISTORY_NAME "rte_mbuf_dynfield_history"
+
+/**
+ * Type for mbuf history dynamic field.
+ *
+ * Use atomic operations to support cloned mbufs
+ * accessed simultaneously by multiple lcores.
+ *
+ * The size is 64-bit for better performance on modern systems.
+ */
+typedef RTE_ATOMIC(uint64_t) rte_mbuf_history_t;
+
/*
* The metadata dynamic field provides some extra packet information
* to interact with RTE Flow engine. The metadata in sent mbufs can be
diff --git a/lib/mbuf/rte_mbuf_history.h b/lib/mbuf/rte_mbuf_history.h
new file mode 100644
index 0000000000..71019cf914
--- /dev/null
+++ b/lib/mbuf/rte_mbuf_history.h
@@ -0,0 +1,174 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 NVIDIA Corporation & Affiliates
+ */
+
+#ifndef _RTE_MBUF_HISTORY_H_
+#define _RTE_MBUF_HISTORY_H_
+
+/**
+ * @file
+ *
+ * These functions allow to track history of mbuf objects using a dynamic field.
+ *
+ * It tracks the lifecycle of mbuf objects through the system
+ * with a fixed set of predefined events to maintain performance.
+ *
+ * The history is stored as an atomic value (64-bit) in a dynamic field of the mbuf,
+ * with each event encoded in 4 bits, allowing up to 16 events to be tracked.
+ * Atomic operations ensure thread safety for cloned mbufs accessed by multiple lcores.
+ */
+
+#include <rte_common.h>
+#include <rte_debug.h>
+
+#include <rte_mbuf_dyn.h>
+
+/* Forward declaration to avoid circular dependency. */
+struct rte_mbuf;
+struct rte_mempool;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Number of bits for each history operation.
+ */
+#define RTE_MBUF_HISTORY_BITS 4
+
+/**
+ * Maximum number of history operations that can be stored.
+ */
+#define RTE_MBUF_HISTORY_MAX (sizeof(rte_mbuf_history_t) * 8 / RTE_MBUF_HISTORY_BITS)
+
+/**
+ * History operation types.
+ */
+enum rte_mbuf_history_op {
+ RTE_MBUF_HISTORY_OP_NEVER = 0, /**< Initial state - never allocated */
+ RTE_MBUF_HISTORY_OP_LIB_FREE = 1, /**< Freed back to pool */
+ RTE_MBUF_HISTORY_OP_PMD_FREE = 2, /**< Freed by PMD */
+ RTE_MBUF_HISTORY_OP_APP_FREE = 3, /**< Freed by application */
+ RTE_MBUF_HISTORY_OP_LIB_ALLOC = 4, /**< Allocation in mbuf library */
+ RTE_MBUF_HISTORY_OP_PMD_ALLOC = 5, /**< Allocated by PMD for Rx */
+ RTE_MBUF_HISTORY_OP_APP_ALLOC = 6, /**< Allocated by application */
+ RTE_MBUF_HISTORY_OP_RX = 7, /**< Received */
+ RTE_MBUF_HISTORY_OP_TX = 8, /**< Sent */
+ RTE_MBUF_HISTORY_OP_PREP_TX = 9, /**< Being prepared before Tx */
+ RTE_MBUF_HISTORY_OP_BUSY_TX = 10, /**< Returned due to Tx busy */
+ RTE_MBUF_HISTORY_OP_ENQUEUE = 11, /**< Enqueued for processing */
+ RTE_MBUF_HISTORY_OP_DEQUEUE = 12, /**< Dequeued for processing */
+ /* 13 - reserved for future */
+ RTE_MBUF_HISTORY_OP_USR2 = 14, /**< Application-defined event 2 */
+ RTE_MBUF_HISTORY_OP_USR1 = 15, /**< Application-defined event 1 */
+ RTE_MBUF_HISTORY_OP_MAX = 16, /**< Maximum number of operation types */
+};
+
+/**
+ * Global offset for the history dynamic field (set during initialization).
+ */
+extern int rte_mbuf_history_field_offset;
+
+/**
+ * Initialize the mbuf history system.
+ *
+ * This function registers the dynamic field for mbuf history tracking.
+ * It should be called once during application initialization.
+ *
+ * Note: This function is called by rte_pktmbuf_pool_create,
+ * so explicit invocation is usually not required.
+ */
+__rte_experimental
+void rte_mbuf_history_init(void);
+
+/**
+ * Mark an mbuf with a history event.
+ *
+ * @param m
+ * Pointer to the mbuf.
+ * @param op
+ * The operation to record.
+ */
+static inline void rte_mbuf_history_mark(struct rte_mbuf *m, uint32_t op)
+{
+#if !RTE_MBUF_HISTORY_DEBUG
+ RTE_SET_USED(m);
+ RTE_SET_USED(op);
+#else
+ RTE_ASSERT(rte_mbuf_history_field_offset >= 0);
+ RTE_ASSERT(op < RTE_MBUF_HISTORY_OP_MAX);
+ if (unlikely (m == NULL))
+ return;
+
+ rte_mbuf_history_t *history_field = RTE_MBUF_DYNFIELD(m,
+ rte_mbuf_history_field_offset, rte_mbuf_history_t *);
+ uint64_t history = rte_atomic_load_explicit(history_field, rte_memory_order_acquire);
+ history = (history << RTE_MBUF_HISTORY_BITS) | op;
+ rte_atomic_store_explicit(history_field, history, rte_memory_order_release);
+#endif
+}
+
+/**
+ * Mark multiple mbufs with a history event.
+ *
+ * @param mbufs
+ * Array of mbuf pointers.
+ * @param n
+ * Number of mbufs to mark.
+ * @param op
+ * The operation to record.
+ */
+static inline void rte_mbuf_history_mark_bulk(struct rte_mbuf * const *mbufs,
+ uint32_t n, uint32_t op)
+{
+#if !RTE_MBUF_HISTORY_DEBUG
+ RTE_SET_USED(mbufs);
+ RTE_SET_USED(n);
+ RTE_SET_USED(op);
+#else
+ RTE_ASSERT(rte_mbuf_history_field_offset >= 0);
+ RTE_ASSERT(op < RTE_MBUF_HISTORY_OP_MAX);
+ if (unlikely (mbufs == NULL))
+ return;
+
+ while (n--)
+ rte_mbuf_history_mark(*mbufs++, op);
+#endif
+}
+
+/**
+ * Dump mbuf history for a single mbuf to a file.
+ *
+ * @param f
+ * File pointer to write the history to.
+ * @param m
+ * Pointer to the mbuf to dump history for.
+ */
+__rte_experimental
+void rte_mbuf_history_dump(FILE *f, const struct rte_mbuf *m);
+
+/**
+ * Dump mbuf history statistics for a single mempool to a file.
+ *
+ * @param f
+ * File pointer to write the history statistics to.
+ * @param mp
+ * Pointer to the mempool to dump history for.
+ */
+__rte_experimental
+void rte_mbuf_history_dump_mempool(FILE *f, struct rte_mempool *mp);
+
+/**
+ * Dump mbuf history statistics for all mempools to a file.
+ *
+ * @param f
+ * File pointer to write the history statistics to.
+ */
+__rte_experimental
+void rte_mbuf_history_dump_all(FILE *f);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_MBUF_HISTORY_H_ */
diff --git a/meson_options.txt b/meson_options.txt
index e28d24054c..5543a07583 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -26,6 +26,8 @@ option('enable_driver_sdk', type: 'boolean', value: false, description:
'Install headers to build drivers.')
option('enable_libs', type: 'string', value: '', description:
'Comma-separated list of optional libraries to explicitly enable. [NOTE: mandatory libs are always enabled]')
+option('enable_mbuf_history', type: 'boolean', value: false, description:
+ 'Track mbufs for debugging purpose. Default is false.')
option('examples', type: 'string', value: '', description:
'Comma-separated list of examples to build by default')
option('ibverbs_link', type: 'combo', choices : ['static', 'shared', 'dlopen'], value: 'shared', description:
--
2.51.0
next prev parent reply other threads:[~2025-09-30 23:39 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-16 7:29 [RFC PATCH 0/5] Introduce mempool object new debug capabilities Shani Peretz
2025-06-16 7:29 ` [RFC PATCH 1/5] mempool: record mempool objects operations history Shani Peretz
2025-06-16 7:29 ` [RFC PATCH 2/5] drivers: add mempool history compilation flag Shani Peretz
2025-06-16 7:29 ` [RFC PATCH 3/5] net/mlx5: mark an operation in mempool object's history Shani Peretz
2025-06-16 7:29 ` [RFC PATCH 4/5] app/testpmd: add testpmd command to dump mempool history Shani Peretz
2025-06-16 7:29 ` [RFC PATCH 5/5] usertool: add a script to parse mempool history dump Shani Peretz
2025-06-16 15:30 ` [RFC PATCH 0/5] Introduce mempool object new debug capabilities Stephen Hemminger
2025-06-19 12:57 ` Morten Brørup
2025-07-07 5:46 ` Shani Peretz
2025-07-07 5:45 ` Shani Peretz
2025-07-07 12:10 ` Morten Brørup
2025-07-19 14:39 ` Morten Brørup
2025-08-25 11:27 ` Slava Ovsiienko
2025-09-01 15:34 ` Morten Brørup
2025-09-16 15:12 ` [PATCH v2 0/4] add mbuf " Shani Peretz
2025-09-16 15:12 ` [PATCH v2 1/4] mbuf: record mbuf operations history Shani Peretz
2025-09-16 21:17 ` Stephen Hemminger
2025-09-16 21:33 ` Thomas Monjalon
2025-09-17 1:22 ` Morten Brørup
2025-09-17 14:46 ` Morten Brørup
2025-09-19 9:14 ` Shani Peretz
2025-09-16 15:12 ` [PATCH v2 2/4] net/mlx5: mark an operation in mbuf's history Shani Peretz
2025-09-16 21:14 ` Stephen Hemminger
2025-09-16 21:31 ` Thomas Monjalon
2025-09-17 15:04 ` Stephen Hemminger
2025-09-16 15:12 ` [PATCH v2 3/4] app/testpmd: add testpmd command to dump mbuf history Shani Peretz
2025-09-16 15:12 ` [PATCH v2 4/4] usertool: add a script to parse mbuf history dump Shani Peretz
2025-09-30 23:25 ` [PATCH v3 0/5] add mbuf debug capabilities Thomas Monjalon
2025-09-30 23:25 ` [PATCH v3 1/5] mbuf: move header include for logs Thomas Monjalon
2025-09-30 23:25 ` Thomas Monjalon [this message]
2025-10-01 0:12 ` [PATCH v3 2/5] mbuf: record mbuf operations history Thomas Monjalon
2025-09-30 23:25 ` [PATCH v3 3/5] ethdev: mark mbufs in burst functions Thomas Monjalon
2025-09-30 23:25 ` [PATCH v3 4/5] app/testpmd: add commands to dump mbuf history Thomas Monjalon
2025-10-01 8:20 ` Stephen Hemminger
2025-09-30 23:25 ` [PATCH v3 5/5] usertools/mbuf: parse mbuf history dump Thomas Monjalon
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=20250930233828.3999565-3-thomas@monjalon.net \
--to=thomas@monjalon.net \
--cc=bruce.richardson@intel.com \
--cc=dev@dpdk.org \
--cc=mb@smartsharesystems.com \
--cc=shperetz@nvidia.com \
--cc=stephen@networkplumber.org \
--cc=viacheslavo@nvidia.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;
as well as URLs for NNTP newsgroup(s).