LCOV - code coverage report
Current view: top level - lib/mbuf - mbuf_history.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 2 11 18.2 %
Date: 2025-11-01 17:50:34 Functions: 1 4 25.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2024 NVIDIA Corporation & Affiliates
       3                 :            :  */
       4                 :            : 
       5                 :            : #include <rte_errno.h>
       6                 :            : #include <eal_export.h>
       7                 :            : #include <rte_bitops.h>
       8                 :            : #include <rte_mempool.h>
       9                 :            : 
      10                 :            : #include "rte_mbuf_history.h"
      11                 :            : #include "rte_mbuf_dyn.h"
      12                 :            : #include "rte_mbuf.h"
      13                 :            : #include "mbuf_log.h"
      14                 :            : 
      15                 :            : /* Dynamic field offset */
      16                 :            : RTE_EXPORT_SYMBOL(rte_mbuf_history_field_offset);
      17                 :            : int rte_mbuf_history_field_offset = -1;
      18                 :            : 
      19                 :            : #ifdef RTE_MBUF_HISTORY_DEBUG
      20                 :            : 
      21                 :            : #define HISTORY_LAST_MASK (RTE_BIT64(RTE_MBUF_HISTORY_BITS) - 1)
      22                 :            : 
      23                 :            : /* Dynamic field definition for mbuf history */
      24                 :            : static const struct rte_mbuf_dynfield mbuf_dynfield_history = {
      25                 :            :         .name = RTE_MBUF_DYNFIELD_HISTORY_NAME,
      26                 :            :         .size = sizeof(rte_mbuf_history_t),
      27                 :            :         .align = RTE_ALIGN(sizeof(rte_mbuf_history_t), 8),
      28                 :            : };
      29                 :            : 
      30                 :            : /* Context structure for statistics counting and history printing */
      31                 :            : struct count_and_print_ctx {
      32                 :            :         uint64_t *stats;
      33                 :            :         FILE *f;
      34                 :            : };
      35                 :            : 
      36                 :            : static uint64_t
      37                 :            : mbuf_history_get(const struct rte_mbuf *m)
      38                 :            : {
      39                 :            :         if (rte_mbuf_history_field_offset < 0 || m == NULL)
      40                 :            :                 return 0;
      41                 :            : 
      42                 :            :         rte_mbuf_history_t *history = RTE_MBUF_DYNFIELD(m,
      43                 :            :                         rte_mbuf_history_field_offset, rte_mbuf_history_t *);
      44                 :            : 
      45                 :            :         return rte_atomic_load_explicit(history, rte_memory_order_acquire);
      46                 :            : }
      47                 :            : 
      48                 :            : static int
      49                 :            : mbuf_history_print(FILE *f, const struct rte_mbuf *m, uint64_t history)
      50                 :            : {
      51                 :            :         return fprintf(f, "mbuf %p: %016" PRIx64 "\n", m, history);
      52                 :            : }
      53                 :            : 
      54                 :            : static void
      55                 :            : mbuf_history_count_stats_and_print(struct rte_mempool *mp __rte_unused,
      56                 :            :                 void *opaque, void *obj, unsigned obj_idx __rte_unused)
      57                 :            : {
      58                 :            :         struct count_and_print_ctx *ctx = (struct count_and_print_ctx *)opaque;
      59                 :            :         struct rte_mbuf *m = (struct rte_mbuf *)obj;
      60                 :            :         uint64_t history;
      61                 :            :         enum rte_mbuf_history_op last_op;
      62                 :            : 
      63                 :            :         if (obj == NULL || ctx == NULL || ctx->stats == NULL || ctx->f == NULL)
      64                 :            :                 return;
      65                 :            : 
      66                 :            :         history = mbuf_history_get(m);
      67                 :            :         /* Extract the most recent operation */
      68                 :            :         last_op = history & HISTORY_LAST_MASK;
      69                 :            :         RTE_ASSERT(last_op < RTE_MBUF_HISTORY_OP_MAX);
      70                 :            :         RTE_BUILD_BUG_ON(HISTORY_LAST_MASK + 1 < RTE_MBUF_HISTORY_OP_MAX);
      71                 :            : 
      72                 :            :         ctx->stats[last_op]++;
      73                 :            :         ctx->stats[RTE_MBUF_HISTORY_OP_MAX]++; /* total */
      74                 :            : 
      75                 :            :         if (history != 0)
      76                 :            :                 mbuf_history_print(ctx->f, m, history);
      77                 :            : }
      78                 :            : 
      79                 :            : static void
      80                 :            : mbuf_history_get_stats(struct rte_mempool *mp, FILE *f)
      81                 :            : {
      82                 :            :         uint64_t stats[RTE_MBUF_HISTORY_OP_MAX + 1] = {0};
      83                 :            :         struct count_and_print_ctx ctx = {
      84                 :            :                 .stats = stats,
      85                 :            :                 .f = f
      86                 :            :         };
      87                 :            : 
      88                 :            :         if (mp->elt_size < sizeof(struct rte_mbuf)) {
      89                 :            :                 MBUF_LOG(ERR, "Invalid mempool element size (less than mbuf)");
      90                 :            :                 return;
      91                 :            :         }
      92                 :            : 
      93                 :            :         if (f == NULL)
      94                 :            :                 return;
      95                 :            : 
      96                 :            :         /* Output mempool header */
      97                 :            :         fprintf(f, "mempool <%s>@%p\n", mp->name, mp);
      98                 :            : 
      99                 :            :         /* Single pass: collect statistics and print mbuf history */
     100                 :            :         rte_mempool_obj_iter(mp, mbuf_history_count_stats_and_print, &ctx);
     101                 :            : 
     102                 :            :         /* Calculate total allocated mbufs */
     103                 :            :         uint64_t total_allocated = 0;
     104                 :            :         for (enum rte_mbuf_history_op op = RTE_MBUF_HISTORY_OP_LIB_ALLOC;
     105                 :            :                         op < RTE_MBUF_HISTORY_OP_MAX; op++)
     106                 :            :                 total_allocated += stats[op];
     107                 :            : 
     108                 :            :         /* Print statistics summary */
     109                 :            :         fprintf(f, "  populated = %u\n", mp->populated_size);
     110                 :            :         fprintf(f, "  never allocated = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_NEVER]);
     111                 :            :         fprintf(f, "  lib free = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_LIB_FREE]);
     112                 :            :         fprintf(f, "  PMD free = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_PMD_FREE]);
     113                 :            :         fprintf(f, "  app free = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_APP_FREE]);
     114                 :            :         fprintf(f, "  allocated = %" PRIu64 "\n", total_allocated);
     115                 :            :         fprintf(f, "  lib alloc = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_LIB_ALLOC]);
     116                 :            :         fprintf(f, "  PMD alloc = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_PMD_ALLOC]);
     117                 :            :         fprintf(f, "  app alloc = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_APP_ALLOC]);
     118                 :            :         fprintf(f, "  Rx = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_RX]);
     119                 :            :         fprintf(f, "  Tx = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_TX]);
     120                 :            :         fprintf(f, "  Tx prep = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_TX_PREP]);
     121                 :            :         fprintf(f, "  Tx busy = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_TX_BUSY]);
     122                 :            :         fprintf(f, "  enqueue = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_ENQUEUE]);
     123                 :            :         fprintf(f, "  dequeue = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_DEQUEUE]);
     124                 :            :         fprintf(f, "  user defined 1 = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_USR1]);
     125                 :            :         fprintf(f, "  user defined 2 = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_USR2]);
     126                 :            :         fprintf(f, "  counted total = %" PRIu64 "\n", stats[RTE_MBUF_HISTORY_OP_MAX]);
     127                 :            : }
     128                 :            : 
     129                 :            : static void
     130                 :            : mbuf_history_get_stats_walking(struct rte_mempool *mp, void *arg)
     131                 :            : {
     132                 :            :         if (mp->elt_size < sizeof(struct rte_mbuf))
     133                 :            :                 return; /* silently ignore while walking in all mempools */
     134                 :            : 
     135                 :            :         mbuf_history_get_stats(mp, arg);
     136                 :            : }
     137                 :            : 
     138                 :            : #endif /* RTE_MBUF_HISTORY_DEBUG */
     139                 :            : 
     140                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_mbuf_history_dump, 25.11)
     141                 :          0 : void rte_mbuf_history_dump(FILE *f, const struct rte_mbuf *m)
     142                 :            : {
     143                 :            : #ifndef RTE_MBUF_HISTORY_DEBUG
     144                 :            :         RTE_SET_USED(f);
     145                 :            :         RTE_SET_USED(m);
     146                 :          0 :         MBUF_LOG(INFO, "mbuf history recorder is not enabled");
     147                 :            : #else
     148                 :            :         if (f == NULL) {
     149                 :            :                 MBUF_LOG(ERR, "Invalid mbuf dump file");
     150                 :            :                 return;
     151                 :            :         }
     152                 :            :         if (m == NULL) {
     153                 :            :                 MBUF_LOG(ERR, "Invalid mbuf pointer");
     154                 :            :                 return;
     155                 :            :         }
     156                 :            :         if (rte_mbuf_history_field_offset < 0) {
     157                 :            :                 MBUF_LOG(WARNING, "mbuf history not initialized, call rte_mbuf_history_init()");
     158                 :            :                 return;
     159                 :            :         }
     160                 :            :         mbuf_history_print(f, m, mbuf_history_get(m));
     161                 :            : #endif
     162                 :          0 : }
     163                 :            : 
     164                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_mbuf_history_dump_mempool, 25.11)
     165                 :          0 : void rte_mbuf_history_dump_mempool(FILE *f, struct rte_mempool *mp)
     166                 :            : {
     167                 :            : #ifndef RTE_MBUF_HISTORY_DEBUG
     168                 :            :         RTE_SET_USED(f);
     169                 :            :         RTE_SET_USED(mp);
     170                 :          0 :         MBUF_LOG(INFO, "mbuf history recorder is not enabled");
     171                 :            : #else
     172                 :            :         if (f == NULL) {
     173                 :            :                 MBUF_LOG(ERR, "Invalid mbuf dump file");
     174                 :            :                 return;
     175                 :            :         }
     176                 :            :         if (mp == NULL) {
     177                 :            :                 MBUF_LOG(ERR, "Invalid mempool pointer");
     178                 :            :                 return;
     179                 :            :         }
     180                 :            :         if (rte_mbuf_history_field_offset < 0) {
     181                 :            :                 MBUF_LOG(WARNING, "mbuf history not initialized, call rte_mbuf_history_init()");
     182                 :            :                 return;
     183                 :            :         }
     184                 :            :         mbuf_history_get_stats(mp, f);
     185                 :            : #endif
     186                 :          0 : }
     187                 :            : 
     188                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_mbuf_history_dump_all, 25.11)
     189                 :          0 : void rte_mbuf_history_dump_all(FILE *f)
     190                 :            : {
     191                 :            : #ifndef RTE_MBUF_HISTORY_DEBUG
     192                 :            :         RTE_SET_USED(f);
     193                 :          0 :         MBUF_LOG(INFO, "mbuf history recorder is not enabled");
     194                 :            : #else
     195                 :            :         if (f == NULL) {
     196                 :            :                 MBUF_LOG(ERR, "Invalid mbuf dump file");
     197                 :            :                 return;
     198                 :            :         }
     199                 :            :         if (rte_mbuf_history_field_offset < 0) {
     200                 :            :                 MBUF_LOG(WARNING, "mbuf history not initialized, call rte_mbuf_history_init()");
     201                 :            :                 return;
     202                 :            :         }
     203                 :            :         fprintf(f, "mbuf history statistics:\n");
     204                 :            :         rte_mempool_walk(mbuf_history_get_stats_walking, f);
     205                 :            : #endif
     206                 :          0 : }
     207                 :            : 
     208                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_mbuf_history_init, 25.11)
     209                 :         24 : void rte_mbuf_history_init(void)
     210                 :            : {
     211                 :            : #ifdef RTE_MBUF_HISTORY_DEBUG
     212                 :            :         if (rte_mbuf_history_field_offset >= 0) {
     213                 :            :                 /* already initialized */
     214                 :            :                 return;
     215                 :            :         }
     216                 :            : 
     217                 :            :         rte_mbuf_history_field_offset = rte_mbuf_dynfield_register(&mbuf_dynfield_history);
     218                 :            :         if (rte_mbuf_history_field_offset < 0) {
     219                 :            :                 MBUF_LOG(ERR, "Failed to register mbuf history dynamic field: %s",
     220                 :            :                         rte_strerror(rte_errno));
     221                 :            :         }
     222                 :            : #endif
     223                 :         24 : }

Generated by: LCOV version 1.14