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 : }
|