1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018-2019 Ericsson AB
3 */
4
5 #include "dsw_evdev.h"
6
7 #include <stdbool.h>
8 #include <string.h>
9
10 #include <rte_debug.h>
11
12 /* The high bits in the xstats id is used to store an additional
13 * parameter (beyond the queue or port id already in the xstats
14 * interface).
15 */
16 #define DSW_XSTATS_ID_PARAM_BITS (8)
17 #define DSW_XSTATS_ID_STAT_BITS \
18 (sizeof(unsigned int)*CHAR_BIT - DSW_XSTATS_ID_PARAM_BITS)
19 #define DSW_XSTATS_ID_STAT_MASK ((1 << DSW_XSTATS_ID_STAT_BITS) - 1)
20
21 #define DSW_XSTATS_ID_GET_PARAM(id) \
22 ((id)>>DSW_XSTATS_ID_STAT_BITS)
23
24 #define DSW_XSTATS_ID_GET_STAT(id) \
25 ((id) & DSW_XSTATS_ID_STAT_MASK)
26
27 #define DSW_XSTATS_ID_CREATE(id, param_value) \
28 (((param_value) << DSW_XSTATS_ID_STAT_BITS) | id)
29
30 typedef
31 uint64_t (*dsw_xstats_dev_get_value_fn)(struct dsw_evdev *dsw);
32
33 struct dsw_xstat_dev {
34 const char *name;
35 dsw_xstats_dev_get_value_fn get_value_fn;
36 };
37
38 typedef
39 uint64_t (*dsw_xstats_port_get_value_fn)(struct dsw_evdev *dsw,
40 uint8_t port_id, uint8_t queue_id);
41
42 struct dsw_xstats_port {
43 const char *name_fmt;
44 dsw_xstats_port_get_value_fn get_value_fn;
45 bool per_queue;
46 };
47
48 static uint64_t
dsw_xstats_dev_credits_on_loan(struct dsw_evdev * dsw)49 dsw_xstats_dev_credits_on_loan(struct dsw_evdev *dsw)
50 {
51 return rte_atomic32_read(&dsw->credits_on_loan);
52 }
53
54 static struct dsw_xstat_dev dsw_dev_xstats[] = {
55 { "dev_credits_on_loan", dsw_xstats_dev_credits_on_loan }
56 };
57
58 #define DSW_GEN_PORT_ACCESS_FN(_variable) \
59 static uint64_t \
60 dsw_xstats_port_get_ ## _variable(struct dsw_evdev *dsw, \
61 uint8_t port_id, \
62 uint8_t queue_id __rte_unused) \
63 { \
64 return dsw->ports[port_id]._variable; \
65 }
66
67 DSW_GEN_PORT_ACCESS_FN(new_enqueued)
DSW_GEN_PORT_ACCESS_FN(forward_enqueued)68 DSW_GEN_PORT_ACCESS_FN(forward_enqueued)
69 DSW_GEN_PORT_ACCESS_FN(release_enqueued)
70
71 static uint64_t
72 dsw_xstats_port_get_queue_enqueued(struct dsw_evdev *dsw, uint8_t port_id,
73 uint8_t queue_id)
74 {
75 return dsw->ports[port_id].queue_enqueued[queue_id];
76 }
77
DSW_GEN_PORT_ACCESS_FN(dequeued)78 DSW_GEN_PORT_ACCESS_FN(dequeued)
79
80 static uint64_t
81 dsw_xstats_port_get_queue_dequeued(struct dsw_evdev *dsw, uint8_t port_id,
82 uint8_t queue_id)
83 {
84 return dsw->ports[port_id].queue_dequeued[queue_id];
85 }
86
87 DSW_GEN_PORT_ACCESS_FN(emigrations)
DSW_GEN_PORT_ACCESS_FN(immigrations)88 DSW_GEN_PORT_ACCESS_FN(immigrations)
89
90 static uint64_t
91 dsw_xstats_port_get_migration_latency(struct dsw_evdev *dsw, uint8_t port_id,
92 uint8_t queue_id __rte_unused)
93 {
94 uint64_t total_latency = dsw->ports[port_id].emigration_latency;
95 uint64_t num_emigrations = dsw->ports[port_id].emigrations;
96
97 return num_emigrations > 0 ? total_latency / num_emigrations : 0;
98 }
99
100 static uint64_t
dsw_xstats_port_get_event_proc_latency(struct dsw_evdev * dsw,uint8_t port_id,uint8_t queue_id __rte_unused)101 dsw_xstats_port_get_event_proc_latency(struct dsw_evdev *dsw, uint8_t port_id,
102 uint8_t queue_id __rte_unused)
103 {
104 uint64_t total_busy_cycles =
105 dsw->ports[port_id].total_busy_cycles;
106 uint64_t dequeued =
107 dsw->ports[port_id].dequeued;
108
109 return dequeued > 0 ? total_busy_cycles / dequeued : 0;
110 }
111
112 static uint64_t
dsw_xstats_port_get_busy_cycles(struct dsw_evdev * dsw,uint8_t port_id,uint8_t queue_id __rte_unused)113 dsw_xstats_port_get_busy_cycles(struct dsw_evdev *dsw, uint8_t port_id,
114 uint8_t queue_id __rte_unused)
115 {
116 return dsw->ports[port_id].total_busy_cycles;
117 }
118
119 DSW_GEN_PORT_ACCESS_FN(inflight_credits)
120
DSW_GEN_PORT_ACCESS_FN(pending_releases)121 DSW_GEN_PORT_ACCESS_FN(pending_releases)
122
123 static uint64_t
124 dsw_xstats_port_get_load(struct dsw_evdev *dsw, uint8_t port_id,
125 uint8_t queue_id __rte_unused)
126 {
127 int16_t load;
128
129 load = rte_atomic16_read(&dsw->ports[port_id].load);
130
131 return DSW_LOAD_TO_PERCENT(load);
132 }
133
134 DSW_GEN_PORT_ACCESS_FN(last_bg)
135
136 static struct dsw_xstats_port dsw_port_xstats[] = {
137 { "port_%u_new_enqueued", dsw_xstats_port_get_new_enqueued,
138 false },
139 { "port_%u_forward_enqueued", dsw_xstats_port_get_forward_enqueued,
140 false },
141 { "port_%u_release_enqueued", dsw_xstats_port_get_release_enqueued,
142 false },
143 { "port_%u_queue_%u_enqueued", dsw_xstats_port_get_queue_enqueued,
144 true },
145 { "port_%u_dequeued", dsw_xstats_port_get_dequeued,
146 false },
147 { "port_%u_queue_%u_dequeued", dsw_xstats_port_get_queue_dequeued,
148 true },
149 { "port_%u_emigrations", dsw_xstats_port_get_emigrations,
150 false },
151 { "port_%u_migration_latency", dsw_xstats_port_get_migration_latency,
152 false },
153 { "port_%u_immigrations", dsw_xstats_port_get_immigrations,
154 false },
155 { "port_%u_event_proc_latency", dsw_xstats_port_get_event_proc_latency,
156 false },
157 { "port_%u_busy_cycles", dsw_xstats_port_get_busy_cycles,
158 false },
159 { "port_%u_inflight_credits", dsw_xstats_port_get_inflight_credits,
160 false },
161 { "port_%u_pending_releases", dsw_xstats_port_get_pending_releases,
162 false },
163 { "port_%u_load", dsw_xstats_port_get_load,
164 false },
165 { "port_%u_last_bg", dsw_xstats_port_get_last_bg,
166 false }
167 };
168
169 typedef
170 void (*dsw_xstats_foreach_fn)(const char *xstats_name,
171 enum rte_event_dev_xstats_mode mode,
172 uint8_t queue_port_id, unsigned int xstats_id,
173 void *data);
174
175 static void
dsw_xstats_dev_foreach(dsw_xstats_foreach_fn fn,void * fn_data)176 dsw_xstats_dev_foreach(dsw_xstats_foreach_fn fn, void *fn_data)
177 {
178 unsigned int i;
179
180 for (i = 0; i < RTE_DIM(dsw_dev_xstats); i++)
181 fn(dsw_dev_xstats[i].name, RTE_EVENT_DEV_XSTATS_DEVICE, 0,
182 i, fn_data);
183 }
184
185 static void
dsw_xstats_port_foreach(struct dsw_evdev * dsw,uint8_t port_id,dsw_xstats_foreach_fn fn,void * fn_data)186 dsw_xstats_port_foreach(struct dsw_evdev *dsw, uint8_t port_id,
187 dsw_xstats_foreach_fn fn, void *fn_data)
188 {
189 uint8_t queue_id;
190 unsigned int stat_idx;
191
192 for (stat_idx = 0, queue_id = 0;
193 stat_idx < RTE_DIM(dsw_port_xstats);) {
194 struct dsw_xstats_port *xstat = &dsw_port_xstats[stat_idx];
195 char xstats_name[RTE_EVENT_DEV_XSTATS_NAME_SIZE];
196 unsigned int xstats_id;
197
198 if (xstat->per_queue) {
199 xstats_id = DSW_XSTATS_ID_CREATE(stat_idx, queue_id);
200 snprintf(xstats_name, sizeof(xstats_name),
201 dsw_port_xstats[stat_idx].name_fmt, port_id,
202 queue_id);
203 queue_id++;
204 } else {
205 xstats_id = stat_idx;
206 snprintf(xstats_name, sizeof(xstats_name),
207 dsw_port_xstats[stat_idx].name_fmt, port_id);
208 }
209
210 fn(xstats_name, RTE_EVENT_DEV_XSTATS_PORT, port_id,
211 xstats_id, fn_data);
212
213 if (!(xstat->per_queue && queue_id < dsw->num_queues)) {
214 stat_idx++;
215 queue_id = 0;
216 }
217 }
218 }
219
220 struct store_ctx {
221 struct rte_event_dev_xstats_name *names;
222 unsigned int *ids;
223 unsigned int count;
224 unsigned int capacity;
225 };
226
227 static void
dsw_xstats_store_stat(const char * xstats_name,enum rte_event_dev_xstats_mode mode,uint8_t queue_port_id,unsigned int xstats_id,void * data)228 dsw_xstats_store_stat(const char *xstats_name,
229 enum rte_event_dev_xstats_mode mode,
230 uint8_t queue_port_id, unsigned int xstats_id,
231 void *data)
232 {
233 struct store_ctx *ctx = data;
234
235 RTE_SET_USED(mode);
236 RTE_SET_USED(queue_port_id);
237
238 if (ctx->count < ctx->capacity) {
239 strcpy(ctx->names[ctx->count].name, xstats_name);
240 ctx->ids[ctx->count] = xstats_id;
241 }
242
243 ctx->count++;
244 }
245
246 int
dsw_xstats_get_names(const struct rte_eventdev * dev,enum rte_event_dev_xstats_mode mode,uint8_t queue_port_id,struct rte_event_dev_xstats_name * xstats_names,unsigned int * ids,unsigned int capacity)247 dsw_xstats_get_names(const struct rte_eventdev *dev,
248 enum rte_event_dev_xstats_mode mode,
249 uint8_t queue_port_id,
250 struct rte_event_dev_xstats_name *xstats_names,
251 unsigned int *ids, unsigned int capacity)
252 {
253 struct dsw_evdev *dsw = dsw_pmd_priv(dev);
254
255 struct store_ctx ctx = {
256 .names = xstats_names,
257 .ids = ids,
258 .capacity = capacity
259 };
260
261 switch (mode) {
262 case RTE_EVENT_DEV_XSTATS_DEVICE:
263 dsw_xstats_dev_foreach(dsw_xstats_store_stat, &ctx);
264 return ctx.count;
265 case RTE_EVENT_DEV_XSTATS_PORT:
266 dsw_xstats_port_foreach(dsw, queue_port_id,
267 dsw_xstats_store_stat, &ctx);
268 return ctx.count;
269 case RTE_EVENT_DEV_XSTATS_QUEUE:
270 return 0;
271 default:
272 RTE_ASSERT(false);
273 return -1;
274 }
275 }
276
277 static int
dsw_xstats_dev_get(const struct rte_eventdev * dev,const unsigned int ids[],uint64_t values[],unsigned int n)278 dsw_xstats_dev_get(const struct rte_eventdev *dev,
279 const unsigned int ids[], uint64_t values[], unsigned int n)
280 {
281 struct dsw_evdev *dsw = dsw_pmd_priv(dev);
282 unsigned int i;
283
284 for (i = 0; i < n; i++) {
285 unsigned int id = ids[i];
286 struct dsw_xstat_dev *xstat = &dsw_dev_xstats[id];
287 values[i] = xstat->get_value_fn(dsw);
288 }
289 return n;
290 }
291
292 static int
dsw_xstats_port_get(const struct rte_eventdev * dev,uint8_t port_id,const unsigned int ids[],uint64_t values[],unsigned int n)293 dsw_xstats_port_get(const struct rte_eventdev *dev, uint8_t port_id,
294 const unsigned int ids[], uint64_t values[], unsigned int n)
295 {
296 struct dsw_evdev *dsw = dsw_pmd_priv(dev);
297 unsigned int i;
298
299 for (i = 0; i < n; i++) {
300 unsigned int id = ids[i];
301 unsigned int stat_idx = DSW_XSTATS_ID_GET_STAT(id);
302 struct dsw_xstats_port *xstat = &dsw_port_xstats[stat_idx];
303 uint8_t queue_id = 0;
304
305 if (xstat->per_queue)
306 queue_id = DSW_XSTATS_ID_GET_PARAM(id);
307
308 values[i] = xstat->get_value_fn(dsw, port_id, queue_id);
309 }
310 return n;
311 }
312
313 int
dsw_xstats_get(const struct rte_eventdev * dev,enum rte_event_dev_xstats_mode mode,uint8_t queue_port_id,const unsigned int ids[],uint64_t values[],unsigned int n)314 dsw_xstats_get(const struct rte_eventdev *dev,
315 enum rte_event_dev_xstats_mode mode, uint8_t queue_port_id,
316 const unsigned int ids[], uint64_t values[], unsigned int n)
317 {
318 switch (mode) {
319 case RTE_EVENT_DEV_XSTATS_DEVICE:
320 return dsw_xstats_dev_get(dev, ids, values, n);
321 case RTE_EVENT_DEV_XSTATS_PORT:
322 return dsw_xstats_port_get(dev, queue_port_id, ids, values, n);
323 case RTE_EVENT_DEV_XSTATS_QUEUE:
324 return 0;
325 default:
326 RTE_ASSERT(false);
327 return -1;
328 }
329 return 0;
330 }
331
332 struct find_ctx {
333 const struct rte_eventdev *dev;
334 const char *name;
335 unsigned int *id;
336 uint64_t value;
337 };
338
339 static void
dsw_xstats_find_stat(const char * xstats_name,enum rte_event_dev_xstats_mode mode,uint8_t queue_port_id,unsigned int xstats_id,void * data)340 dsw_xstats_find_stat(const char *xstats_name,
341 enum rte_event_dev_xstats_mode mode,
342 uint8_t queue_port_id, unsigned int xstats_id,
343 void *data)
344 {
345 struct find_ctx *ctx = data;
346
347 if (strcmp(ctx->name, xstats_name) == 0) {
348 if (ctx->id != NULL)
349 *ctx->id = xstats_id;
350 dsw_xstats_get(ctx->dev, mode, queue_port_id, &xstats_id,
351 &ctx->value, 1);
352 }
353 }
354
355 uint64_t
dsw_xstats_get_by_name(const struct rte_eventdev * dev,const char * name,unsigned int * id)356 dsw_xstats_get_by_name(const struct rte_eventdev *dev, const char *name,
357 unsigned int *id)
358 {
359 struct dsw_evdev *dsw = dsw_pmd_priv(dev);
360 uint16_t port_id;
361
362 struct find_ctx ctx = {
363 .dev = dev,
364 .name = name,
365 .id = id,
366 .value = -EINVAL
367 };
368
369 dsw_xstats_dev_foreach(dsw_xstats_find_stat, &ctx);
370
371 for (port_id = 0; port_id < dsw->num_ports; port_id++)
372 dsw_xstats_port_foreach(dsw, port_id, dsw_xstats_find_stat,
373 &ctx);
374
375 return ctx.value;
376 }
377