Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2023 Ericsson AB
3 : : */
4 : :
5 : : #include <rte_bus_vdev.h>
6 : : #include <rte_dispatcher.h>
7 : : #include <rte_eventdev.h>
8 : : #include <rte_random.h>
9 : : #include <rte_service.h>
10 : : #include <rte_stdatomic.h>
11 : :
12 : : #include "test.h"
13 : :
14 : : #define NUM_WORKERS 3
15 : : #define NUM_PORTS (NUM_WORKERS + 1)
16 : : #define WORKER_PORT_ID(worker_idx) (worker_idx)
17 : : #define DRIVER_PORT_ID (NUM_PORTS - 1)
18 : :
19 : : #define NUM_SERVICE_CORES NUM_WORKERS
20 : : #define MIN_LCORES (NUM_SERVICE_CORES + 1)
21 : :
22 : : /* Eventdev */
23 : : #define NUM_QUEUES 8
24 : : #define LAST_QUEUE_ID (NUM_QUEUES - 1)
25 : : #define MAX_EVENTS 4096
26 : : #define NEW_EVENT_THRESHOLD (MAX_EVENTS / 2)
27 : : #define DEQUEUE_BURST_SIZE 32
28 : : #define ENQUEUE_BURST_SIZE 32
29 : :
30 : : #define NUM_EVENTS 10000000
31 : : #define NUM_FLOWS 16
32 : :
33 : : #define DSW_VDEV "event_dsw0"
34 : :
35 : : struct app_queue {
36 : : uint8_t queue_id;
37 : : uint64_t sn[NUM_FLOWS];
38 : : int dispatcher_reg_id;
39 : : };
40 : :
41 : : struct cb_count {
42 : : uint8_t expected_event_dev_id;
43 : : uint8_t expected_event_port_id[RTE_MAX_LCORE];
44 : : RTE_ATOMIC(int) count;
45 : : };
46 : :
47 : : struct test_app {
48 : : uint8_t event_dev_id;
49 : : struct rte_dispatcher *dispatcher;
50 : : uint32_t dispatcher_service_id;
51 : :
52 : : unsigned int service_lcores[NUM_SERVICE_CORES];
53 : :
54 : : int never_match_reg_id;
55 : : uint64_t never_match_count;
56 : : struct cb_count never_process_count;
57 : :
58 : : struct app_queue queues[NUM_QUEUES];
59 : :
60 : : int finalize_reg_id;
61 : : struct cb_count finalize_count;
62 : :
63 : : bool running;
64 : :
65 : : RTE_ATOMIC(int) completed_events;
66 : : RTE_ATOMIC(int) errors;
67 : : };
68 : :
69 : : static struct test_app *
70 : 0 : test_app_create(void)
71 : : {
72 : : int i;
73 : : struct test_app *app;
74 : :
75 : 0 : app = calloc(1, sizeof(struct test_app));
76 : :
77 [ # # ]: 0 : if (app == NULL)
78 : : return NULL;
79 : :
80 [ # # ]: 0 : for (i = 0; i < NUM_QUEUES; i++)
81 : 0 : app->queues[i].queue_id = i;
82 : :
83 : : return app;
84 : : }
85 : :
86 : : static void
87 : : test_app_free(struct test_app *app)
88 : : {
89 : 0 : free(app);
90 : : }
91 : :
92 : : static int
93 : 0 : test_app_create_vdev(struct test_app *app)
94 : : {
95 : : int rc;
96 : :
97 : 0 : rc = rte_vdev_init(DSW_VDEV, NULL);
98 [ # # ]: 0 : if (rc < 0)
99 : : return TEST_SKIPPED;
100 : :
101 : 0 : rc = rte_event_dev_get_dev_id(DSW_VDEV);
102 : :
103 : 0 : app->event_dev_id = (uint8_t)rc;
104 : :
105 : 0 : return TEST_SUCCESS;
106 : : }
107 : :
108 : : static int
109 : 0 : test_app_destroy_vdev(struct test_app *app)
110 : : {
111 : : int rc;
112 : :
113 : 0 : rc = rte_event_dev_close(app->event_dev_id);
114 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Error while closing event device");
115 : :
116 : 0 : rc = rte_vdev_uninit(DSW_VDEV);
117 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Error while uninitializing virtual device");
118 : :
119 : : return TEST_SUCCESS;
120 : : }
121 : :
122 : : static int
123 : 0 : test_app_setup_event_dev(struct test_app *app)
124 : : {
125 : : int rc;
126 : : int i;
127 : :
128 : 0 : rc = test_app_create_vdev(app);
129 [ # # ]: 0 : if (rc != TEST_SUCCESS)
130 : : return rc;
131 : :
132 : 0 : struct rte_event_dev_config config = {
133 : : .nb_event_queues = NUM_QUEUES,
134 : : .nb_event_ports = NUM_PORTS,
135 : : .nb_events_limit = MAX_EVENTS,
136 : : .nb_event_queue_flows = 64,
137 : : .nb_event_port_dequeue_depth = DEQUEUE_BURST_SIZE,
138 : : .nb_event_port_enqueue_depth = ENQUEUE_BURST_SIZE
139 : : };
140 : :
141 : 0 : rc = rte_event_dev_configure(app->event_dev_id, &config);
142 : :
143 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to configure event device");
144 : :
145 : 0 : struct rte_event_queue_conf queue_config = {
146 : : .priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
147 : : .schedule_type = RTE_SCHED_TYPE_ATOMIC,
148 : : .nb_atomic_flows = 64
149 : : };
150 : :
151 [ # # ]: 0 : for (i = 0; i < NUM_QUEUES; i++) {
152 : : uint8_t queue_id = i;
153 : :
154 : 0 : rc = rte_event_queue_setup(app->event_dev_id, queue_id,
155 : : &queue_config);
156 : :
157 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to setup queue %d", queue_id);
158 : : }
159 : :
160 : 0 : struct rte_event_port_conf port_config = {
161 : : .new_event_threshold = NEW_EVENT_THRESHOLD,
162 : : .dequeue_depth = DEQUEUE_BURST_SIZE,
163 : : .enqueue_depth = ENQUEUE_BURST_SIZE
164 : : };
165 : :
166 [ # # ]: 0 : for (i = 0; i < NUM_PORTS; i++) {
167 : 0 : uint8_t event_port_id = i;
168 : :
169 : 0 : rc = rte_event_port_setup(app->event_dev_id, event_port_id,
170 : : &port_config);
171 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Failed to create event port %d",
172 : : event_port_id);
173 : :
174 [ # # ]: 0 : if (event_port_id == DRIVER_PORT_ID)
175 : 0 : continue;
176 : :
177 : 0 : rc = rte_event_port_link(app->event_dev_id, event_port_id,
178 : : NULL, NULL, 0);
179 : :
180 [ # # ]: 0 : TEST_ASSERT_EQUAL(rc, NUM_QUEUES, "Failed to link port %d",
181 : : event_port_id);
182 : : }
183 : :
184 : : return TEST_SUCCESS;
185 : : }
186 : :
187 : : static int
188 : : test_app_teardown_event_dev(struct test_app *app)
189 : : {
190 : 0 : return test_app_destroy_vdev(app);
191 : : }
192 : :
193 : : static int
194 : 0 : test_app_start_event_dev(struct test_app *app)
195 : : {
196 : : int rc;
197 : :
198 : 0 : rc = rte_event_dev_start(app->event_dev_id);
199 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to start event device");
200 : :
201 : : return TEST_SUCCESS;
202 : : }
203 : :
204 : : static void
205 : : test_app_stop_event_dev(struct test_app *app)
206 : : {
207 : 0 : rte_event_dev_stop(app->event_dev_id);
208 : : }
209 : :
210 : : static int
211 : 0 : test_app_create_dispatcher(struct test_app *app)
212 : : {
213 : : int rc;
214 : :
215 : 0 : app->dispatcher = rte_dispatcher_create(app->event_dev_id);
216 : :
217 [ # # ]: 0 : TEST_ASSERT(app->dispatcher != NULL, "Unable to create event "
218 : : "dispatcher");
219 : :
220 : 0 : app->dispatcher_service_id =
221 : 0 : rte_dispatcher_service_id_get(app->dispatcher);
222 : :
223 : 0 : rc = rte_service_set_stats_enable(app->dispatcher_service_id, 1);
224 : :
225 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to enable event dispatcher service "
226 : : "stats");
227 : :
228 : 0 : rc = rte_service_runstate_set(app->dispatcher_service_id, 1);
229 : :
230 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to set dispatcher service runstate");
231 : :
232 : : return TEST_SUCCESS;
233 : : }
234 : :
235 : : static int
236 : 0 : test_app_free_dispatcher(struct test_app *app)
237 : : {
238 : : int rc;
239 : :
240 : 0 : rc = rte_service_runstate_set(app->dispatcher_service_id, 0);
241 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Error disabling dispatcher service");
242 : :
243 : 0 : rc = rte_dispatcher_free(app->dispatcher);
244 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Error freeing dispatcher");
245 : :
246 : : return TEST_SUCCESS;
247 : : }
248 : :
249 : : static int
250 : 0 : test_app_bind_ports(struct test_app *app)
251 : : {
252 : : int i;
253 : :
254 : 0 : app->never_process_count.expected_event_dev_id =
255 : 0 : app->event_dev_id;
256 : 0 : app->finalize_count.expected_event_dev_id =
257 : : app->event_dev_id;
258 : :
259 [ # # ]: 0 : for (i = 0; i < NUM_WORKERS; i++) {
260 : 0 : unsigned int lcore_id = app->service_lcores[i];
261 : 0 : uint8_t port_id = WORKER_PORT_ID(i);
262 : :
263 : 0 : int rc = rte_dispatcher_bind_port_to_lcore(
264 : : app->dispatcher, port_id, DEQUEUE_BURST_SIZE, 0,
265 : : lcore_id
266 : : );
267 : :
268 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to bind event device port %d "
269 : : "to lcore %d", port_id, lcore_id);
270 : :
271 : 0 : app->never_process_count.expected_event_port_id[lcore_id] =
272 : : port_id;
273 : 0 : app->finalize_count.expected_event_port_id[lcore_id] = port_id;
274 : : }
275 : :
276 : :
277 : : return TEST_SUCCESS;
278 : : }
279 : :
280 : : static int
281 : 0 : test_app_unbind_ports(struct test_app *app)
282 : : {
283 : : int i;
284 : :
285 [ # # ]: 0 : for (i = 0; i < NUM_WORKERS; i++) {
286 : 0 : unsigned int lcore_id = app->service_lcores[i];
287 : :
288 : 0 : int rc = rte_dispatcher_unbind_port_from_lcore(
289 : : app->dispatcher,
290 : : WORKER_PORT_ID(i),
291 : : lcore_id
292 : : );
293 : :
294 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to unbind event device port %d "
295 : : "from lcore %d", WORKER_PORT_ID(i),
296 : : lcore_id);
297 : : }
298 : :
299 : : return TEST_SUCCESS;
300 : : }
301 : :
302 : : static bool
303 : 0 : match_queue(const struct rte_event *event, void *cb_data)
304 : : {
305 : 0 : uintptr_t queue_id = (uintptr_t)cb_data;
306 : :
307 : 0 : return event->queue_id == queue_id;
308 : : }
309 : :
310 : : static int
311 : : test_app_get_worker_index(struct test_app *app, unsigned int lcore_id)
312 : : {
313 : : int i;
314 : :
315 [ # # ]: 0 : for (i = 0; i < NUM_SERVICE_CORES; i++)
316 [ # # ]: 0 : if (app->service_lcores[i] == lcore_id)
317 : : return i;
318 : :
319 : : return -1;
320 : : }
321 : :
322 : : static int
323 : : test_app_get_worker_port(struct test_app *app, unsigned int lcore_id)
324 : : {
325 : : int worker;
326 : :
327 : : worker = test_app_get_worker_index(app, lcore_id);
328 : :
329 [ # # ]: 0 : if (worker < 0)
330 : : return -1;
331 : :
332 : : return WORKER_PORT_ID(worker);
333 : : }
334 : :
335 : : static void
336 : : test_app_queue_note_error(struct test_app *app)
337 : : {
338 : 0 : rte_atomic_fetch_add_explicit(&app->errors, 1, rte_memory_order_relaxed);
339 : : }
340 : :
341 : : static void
342 : 0 : test_app_process_queue(uint8_t p_event_dev_id, uint8_t p_event_port_id,
343 : : struct rte_event *in_events, uint16_t num,
344 : : void *cb_data)
345 : 0 : {
346 : : struct app_queue *app_queue = cb_data;
347 : 0 : struct test_app *app = container_of(app_queue, struct test_app,
348 : : queues[app_queue->queue_id]);
349 : : unsigned int lcore_id = rte_lcore_id();
350 : : bool intermediate_queue = app_queue->queue_id != LAST_QUEUE_ID;
351 : : int event_port_id;
352 : : uint16_t i;
353 : 0 : struct rte_event out_events[num];
354 : :
355 : : event_port_id = test_app_get_worker_port(app, lcore_id);
356 : :
357 [ # # ]: 0 : if (event_port_id < 0 || p_event_dev_id != app->event_dev_id ||
358 [ # # ]: 0 : p_event_port_id != event_port_id) {
359 : : test_app_queue_note_error(app);
360 : 0 : return;
361 : : }
362 : :
363 [ # # ]: 0 : for (i = 0; i < num; i++) {
364 : 0 : const struct rte_event *in_event = &in_events[i];
365 : 0 : struct rte_event *out_event = &out_events[i];
366 : 0 : uint64_t sn = in_event->u64;
367 : : uint64_t expected_sn;
368 : :
369 [ # # ]: 0 : if (in_event->queue_id != app_queue->queue_id) {
370 : : test_app_queue_note_error(app);
371 : 0 : return;
372 : : }
373 : :
374 : 0 : expected_sn = app_queue->sn[in_event->flow_id]++;
375 : :
376 [ # # ]: 0 : if (expected_sn != sn) {
377 : : test_app_queue_note_error(app);
378 : 0 : return;
379 : : }
380 : :
381 [ # # ]: 0 : if (intermediate_queue)
382 : 0 : *out_event = (struct rte_event) {
383 : 0 : .queue_id = in_event->queue_id + 1,
384 : 0 : .flow_id = in_event->flow_id,
385 : : .sched_type = RTE_SCHED_TYPE_ATOMIC,
386 : : .op = RTE_EVENT_OP_FORWARD,
387 : : .priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
388 : 0 : .impl_opaque = in_event->impl_opaque,
389 : : .u64 = sn
390 : : };
391 : : }
392 : :
393 [ # # ]: 0 : if (intermediate_queue) {
394 : : uint16_t n = 0;
395 : :
396 : : do {
397 : 0 : n += rte_event_enqueue_forward_burst(p_event_dev_id,
398 : : p_event_port_id,
399 : 0 : out_events + n,
400 : 0 : num - n);
401 [ # # ]: 0 : } while (n != num);
402 : : } else
403 : 0 : rte_atomic_fetch_add_explicit(&app->completed_events, num,
404 : : rte_memory_order_relaxed);
405 : : }
406 : :
407 : : static bool
408 : 0 : never_match(const struct rte_event *event __rte_unused, void *cb_data)
409 : : {
410 : : uint64_t *count = cb_data;
411 : :
412 : 0 : (*count)++;
413 : :
414 : 0 : return false;
415 : : }
416 : :
417 : : static void
418 [ # # ]: 0 : test_app_never_process(uint8_t event_dev_id, uint8_t event_port_id,
419 : : struct rte_event *in_events __rte_unused, uint16_t num, void *cb_data)
420 : : {
421 : : struct cb_count *count = cb_data;
422 : : unsigned int lcore_id = rte_lcore_id();
423 : :
424 [ # # ]: 0 : if (event_dev_id == count->expected_event_dev_id &&
425 [ # # ]: 0 : event_port_id == count->expected_event_port_id[lcore_id])
426 : 0 : rte_atomic_fetch_add_explicit(&count->count, num,
427 : : rte_memory_order_relaxed);
428 : 0 : }
429 : :
430 : : static void
431 [ # # ]: 0 : finalize(uint8_t event_dev_id, uint8_t event_port_id, void *cb_data)
432 : : {
433 : : struct cb_count *count = cb_data;
434 : : unsigned int lcore_id = rte_lcore_id();
435 : :
436 [ # # ]: 0 : if (event_dev_id == count->expected_event_dev_id &&
437 [ # # ]: 0 : event_port_id == count->expected_event_port_id[lcore_id])
438 : 0 : rte_atomic_fetch_add_explicit(&count->count, 1,
439 : : rte_memory_order_relaxed);
440 : 0 : }
441 : :
442 : : static int
443 : 0 : test_app_register_callbacks(struct test_app *app)
444 : : {
445 : : int i;
446 : :
447 : 0 : app->never_match_reg_id =
448 : 0 : rte_dispatcher_register(app->dispatcher, never_match,
449 : 0 : &app->never_match_count,
450 : : test_app_never_process,
451 : 0 : &app->never_process_count);
452 : :
453 [ # # ]: 0 : TEST_ASSERT(app->never_match_reg_id >= 0, "Unable to register "
454 : : "never-match handler");
455 : :
456 [ # # ]: 0 : for (i = 0; i < NUM_QUEUES; i++) {
457 : 0 : struct app_queue *app_queue = &app->queues[i];
458 : 0 : uintptr_t queue_id = app_queue->queue_id;
459 : : int reg_id;
460 : :
461 : 0 : reg_id = rte_dispatcher_register(app->dispatcher,
462 : : match_queue, (void *)queue_id,
463 : : test_app_process_queue,
464 : : app_queue);
465 : :
466 [ # # ]: 0 : TEST_ASSERT(reg_id >= 0, "Unable to register consumer "
467 : : "callback for queue %d", i);
468 : :
469 : 0 : app_queue->dispatcher_reg_id = reg_id;
470 : : }
471 : :
472 : 0 : app->finalize_reg_id =
473 : 0 : rte_dispatcher_finalize_register(app->dispatcher,
474 : : finalize,
475 : 0 : &app->finalize_count);
476 [ # # ]: 0 : TEST_ASSERT_SUCCESS(app->finalize_reg_id, "Error registering "
477 : : "finalize callback");
478 : :
479 : : return TEST_SUCCESS;
480 : : }
481 : :
482 : : static int
483 : 0 : test_app_unregister_callback(struct test_app *app, uint8_t queue_id)
484 : : {
485 : 0 : int reg_id = app->queues[queue_id].dispatcher_reg_id;
486 : : int rc;
487 : :
488 [ # # ]: 0 : if (reg_id < 0) /* unregistered already */
489 : : return 0;
490 : :
491 : 0 : rc = rte_dispatcher_unregister(app->dispatcher, reg_id);
492 : :
493 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to unregister consumer "
494 : : "callback for queue %d", queue_id);
495 : :
496 : 0 : app->queues[queue_id].dispatcher_reg_id = -1;
497 : :
498 : 0 : return TEST_SUCCESS;
499 : : }
500 : :
501 : : static int
502 : 0 : test_app_unregister_callbacks(struct test_app *app)
503 : : {
504 : : int i;
505 : : int rc;
506 : :
507 [ # # ]: 0 : if (app->never_match_reg_id >= 0) {
508 : 0 : rc = rte_dispatcher_unregister(app->dispatcher,
509 : : app->never_match_reg_id);
510 : :
511 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to unregister never-match "
512 : : "handler");
513 : 0 : app->never_match_reg_id = -1;
514 : : }
515 : :
516 [ # # ]: 0 : for (i = 0; i < NUM_QUEUES; i++) {
517 : 0 : rc = test_app_unregister_callback(app, i);
518 [ # # ]: 0 : if (rc != TEST_SUCCESS)
519 : 0 : return rc;
520 : : }
521 : :
522 [ # # ]: 0 : if (app->finalize_reg_id >= 0) {
523 : 0 : rc = rte_dispatcher_finalize_unregister(
524 : : app->dispatcher, app->finalize_reg_id
525 : : );
526 : 0 : app->finalize_reg_id = -1;
527 : : }
528 : :
529 : : return TEST_SUCCESS;
530 : : }
531 : :
532 : : static void
533 : : test_app_start_dispatcher(struct test_app *app)
534 : : {
535 : 0 : rte_dispatcher_start(app->dispatcher);
536 : : }
537 : :
538 : : static void
539 : : test_app_stop_dispatcher(struct test_app *app)
540 : : {
541 : 0 : rte_dispatcher_stop(app->dispatcher);
542 : : }
543 : :
544 : : static int
545 : 0 : test_app_reset_dispatcher_stats(struct test_app *app)
546 : : {
547 : : struct rte_dispatcher_stats stats;
548 : :
549 : 0 : rte_dispatcher_stats_reset(app->dispatcher);
550 : :
551 : : memset(&stats, 0xff, sizeof(stats));
552 : :
553 : 0 : rte_dispatcher_stats_get(app->dispatcher, &stats);
554 : :
555 [ # # ]: 0 : TEST_ASSERT_EQUAL(stats.poll_count, 0, "Poll count not zero");
556 [ # # ]: 0 : TEST_ASSERT_EQUAL(stats.ev_batch_count, 0, "Batch count not zero");
557 [ # # ]: 0 : TEST_ASSERT_EQUAL(stats.ev_dispatch_count, 0, "Dispatch count "
558 : : "not zero");
559 [ # # ]: 0 : TEST_ASSERT_EQUAL(stats.ev_drop_count, 0, "Drop count not zero");
560 : :
561 : : return TEST_SUCCESS;
562 : : }
563 : :
564 : : static int
565 : 0 : test_app_setup_service_core(struct test_app *app, unsigned int lcore_id)
566 : : {
567 : : int rc;
568 : :
569 : 0 : rc = rte_service_lcore_add(lcore_id);
570 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to make lcore %d an event dispatcher "
571 : : "service core", lcore_id);
572 : :
573 : 0 : rc = rte_service_map_lcore_set(app->dispatcher_service_id, lcore_id, 1);
574 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to map event dispatcher service");
575 : :
576 : : return TEST_SUCCESS;
577 : : }
578 : :
579 : : static int
580 : 0 : test_app_setup_service_cores(struct test_app *app)
581 : : {
582 : : int i;
583 : : int lcore_id = -1;
584 : :
585 [ # # ]: 0 : for (i = 0; i < NUM_SERVICE_CORES; i++) {
586 : 0 : lcore_id = rte_get_next_lcore(lcore_id, 1, 0);
587 : :
588 : 0 : app->service_lcores[i] = lcore_id;
589 : : }
590 : :
591 [ # # ]: 0 : for (i = 0; i < NUM_SERVICE_CORES; i++) {
592 : : int rc;
593 : :
594 : 0 : rc = test_app_setup_service_core(app, app->service_lcores[i]);
595 [ # # ]: 0 : if (rc != TEST_SUCCESS)
596 : 0 : return rc;
597 : : }
598 : :
599 : : return TEST_SUCCESS;
600 : : }
601 : :
602 : : static int
603 : 0 : test_app_teardown_service_core(struct test_app *app, unsigned int lcore_id)
604 : : {
605 : : int rc;
606 : :
607 : 0 : rc = rte_service_map_lcore_set(app->dispatcher_service_id, lcore_id, 0);
608 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to unmap event dispatcher service");
609 : :
610 : 0 : rc = rte_service_lcore_del(lcore_id);
611 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable change role of service lcore %d",
612 : : lcore_id);
613 : :
614 : : return TEST_SUCCESS;
615 : : }
616 : :
617 : : static int
618 : 0 : test_app_teardown_service_cores(struct test_app *app)
619 : : {
620 : : int i;
621 : :
622 [ # # ]: 0 : for (i = 0; i < NUM_SERVICE_CORES; i++) {
623 : 0 : unsigned int lcore_id = app->service_lcores[i];
624 : : int rc;
625 : :
626 : 0 : rc = test_app_teardown_service_core(app, lcore_id);
627 [ # # ]: 0 : if (rc != TEST_SUCCESS)
628 : 0 : return rc;
629 : : }
630 : :
631 : : return TEST_SUCCESS;
632 : : }
633 : :
634 : : static int
635 : 0 : test_app_start_service_cores(struct test_app *app)
636 : : {
637 : : int i;
638 : :
639 [ # # ]: 0 : for (i = 0; i < NUM_SERVICE_CORES; i++) {
640 : 0 : unsigned int lcore_id = app->service_lcores[i];
641 : : int rc;
642 : :
643 : 0 : rc = rte_service_lcore_start(lcore_id);
644 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to start service lcore %d",
645 : : lcore_id);
646 : : }
647 : :
648 : : return TEST_SUCCESS;
649 : : }
650 : :
651 : : static int
652 : 0 : test_app_stop_service_cores(struct test_app *app)
653 : : {
654 : : int i;
655 : :
656 [ # # ]: 0 : for (i = 0; i < NUM_SERVICE_CORES; i++) {
657 : 0 : unsigned int lcore_id = app->service_lcores[i];
658 : : int rc;
659 : :
660 : 0 : rc = rte_service_lcore_stop(lcore_id);
661 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to stop service lcore %d",
662 : : lcore_id);
663 : : }
664 : :
665 : : return TEST_SUCCESS;
666 : : }
667 : :
668 : : static int
669 : 0 : test_app_start(struct test_app *app)
670 : : {
671 : : int rc;
672 : :
673 : 0 : rc = test_app_start_event_dev(app);
674 [ # # ]: 0 : if (rc != TEST_SUCCESS)
675 : : return rc;
676 : :
677 : 0 : rc = test_app_start_service_cores(app);
678 [ # # ]: 0 : if (rc != TEST_SUCCESS)
679 : : return rc;
680 : :
681 : : test_app_start_dispatcher(app);
682 : :
683 : 0 : app->running = true;
684 : :
685 : 0 : return TEST_SUCCESS;
686 : : }
687 : :
688 : : static int
689 : 0 : test_app_stop(struct test_app *app)
690 : : {
691 : : int rc;
692 : :
693 : : test_app_stop_dispatcher(app);
694 : :
695 : 0 : rc = test_app_stop_service_cores(app);
696 [ # # ]: 0 : if (rc != TEST_SUCCESS)
697 : : return rc;
698 : :
699 : : test_app_stop_event_dev(app);
700 : :
701 : 0 : app->running = false;
702 : :
703 : 0 : return TEST_SUCCESS;
704 : : }
705 : :
706 : : struct test_app *test_app;
707 : :
708 : : static int
709 : 4 : test_setup(void)
710 : : {
711 : : int rc;
712 : :
713 [ + - ]: 4 : if (rte_lcore_count() < MIN_LCORES) {
714 : : printf("Not enough cores for dispatcher_autotest; expecting at "
715 : : "least %d.\n", MIN_LCORES);
716 : 4 : return TEST_SKIPPED;
717 : : }
718 : :
719 : 0 : test_app = test_app_create();
720 [ # # ]: 0 : TEST_ASSERT(test_app != NULL, "Unable to allocate memory");
721 : :
722 : 0 : rc = test_app_setup_event_dev(test_app);
723 [ # # ]: 0 : if (rc != TEST_SUCCESS)
724 : 0 : goto err_free_app;
725 : :
726 : 0 : rc = test_app_create_dispatcher(test_app);
727 [ # # ]: 0 : if (rc != TEST_SUCCESS)
728 : 0 : goto err_teardown_event_dev;
729 : :
730 : 0 : rc = test_app_setup_service_cores(test_app);
731 [ # # ]: 0 : if (rc != TEST_SUCCESS)
732 : 0 : goto err_free_dispatcher;
733 : :
734 : 0 : rc = test_app_register_callbacks(test_app);
735 [ # # ]: 0 : if (rc != TEST_SUCCESS)
736 : 0 : goto err_teardown_service_cores;
737 : :
738 : 0 : rc = test_app_bind_ports(test_app);
739 [ # # ]: 0 : if (rc != TEST_SUCCESS)
740 : 0 : goto err_unregister_callbacks;
741 : :
742 : : return TEST_SUCCESS;
743 : :
744 : : err_unregister_callbacks:
745 : 0 : test_app_unregister_callbacks(test_app);
746 : 0 : err_teardown_service_cores:
747 : 0 : test_app_teardown_service_cores(test_app);
748 : 0 : err_free_dispatcher:
749 : 0 : test_app_free_dispatcher(test_app);
750 : 0 : err_teardown_event_dev:
751 : 0 : test_app_teardown_event_dev(test_app);
752 : 0 : err_free_app:
753 : 0 : test_app_free(test_app);
754 : :
755 : 0 : test_app = NULL;
756 : :
757 : 0 : return rc;
758 : : }
759 : :
760 : 4 : static void test_teardown(void)
761 : : {
762 [ - + ]: 4 : if (test_app == NULL)
763 : : return;
764 : :
765 [ # # ]: 0 : if (test_app->running)
766 : 0 : test_app_stop(test_app);
767 : :
768 : 0 : test_app_teardown_service_cores(test_app);
769 : :
770 : 0 : test_app_unregister_callbacks(test_app);
771 : :
772 : 0 : test_app_unbind_ports(test_app);
773 : :
774 : 0 : test_app_free_dispatcher(test_app);
775 : :
776 : 0 : test_app_teardown_event_dev(test_app);
777 : :
778 : 0 : test_app_free(test_app);
779 : :
780 : 0 : test_app = NULL;
781 : : }
782 : :
783 : : static int
784 : : test_app_get_completed_events(struct test_app *app)
785 : : {
786 : 0 : return rte_atomic_load_explicit(&app->completed_events,
787 : : rte_memory_order_relaxed);
788 : : }
789 : :
790 : : static int
791 : : test_app_get_errors(struct test_app *app)
792 : : {
793 : 0 : return rte_atomic_load_explicit(&app->errors, rte_memory_order_relaxed);
794 : : }
795 : :
796 : : static int
797 : 0 : test_basic(void)
798 : : {
799 : : int rc;
800 : : int i;
801 : :
802 : 0 : rc = test_app_start(test_app);
803 [ # # ]: 0 : if (rc != TEST_SUCCESS)
804 : : return rc;
805 : :
806 : 0 : uint64_t sns[NUM_FLOWS] = { 0 };
807 : :
808 [ # # ]: 0 : for (i = 0; i < NUM_EVENTS;) {
809 : : struct rte_event events[ENQUEUE_BURST_SIZE];
810 : : int left;
811 : : int batch_size;
812 : : int j;
813 : : uint16_t n = 0;
814 : :
815 : 0 : batch_size = 1 + rte_rand_max(ENQUEUE_BURST_SIZE);
816 : 0 : left = NUM_EVENTS - i;
817 : :
818 : 0 : batch_size = RTE_MIN(left, batch_size);
819 : :
820 [ # # ]: 0 : for (j = 0; j < batch_size; j++) {
821 : : struct rte_event *event = &events[j];
822 : : uint64_t sn;
823 : : uint32_t flow_id;
824 : :
825 : 0 : flow_id = rte_rand_max(NUM_FLOWS);
826 : :
827 : 0 : sn = sns[flow_id]++;
828 : :
829 : 0 : *event = (struct rte_event) {
830 : : .queue_id = 0,
831 : : .flow_id = flow_id,
832 : : .sched_type = RTE_SCHED_TYPE_ATOMIC,
833 : : .op = RTE_EVENT_OP_NEW,
834 : : .priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
835 : : .u64 = sn
836 : : };
837 : : }
838 : :
839 [ # # ]: 0 : while (n < batch_size)
840 : 0 : n += rte_event_enqueue_new_burst(test_app->event_dev_id,
841 : : DRIVER_PORT_ID,
842 : 0 : events + n,
843 : 0 : batch_size - n);
844 : :
845 : 0 : i += batch_size;
846 : : }
847 : :
848 [ # # ]: 0 : while (test_app_get_completed_events(test_app) != NUM_EVENTS)
849 [ # # ]: 0 : rte_event_maintain(test_app->event_dev_id, DRIVER_PORT_ID, 0);
850 : :
851 : 0 : rc = test_app_get_errors(test_app);
852 [ # # ]: 0 : TEST_ASSERT(rc == 0, "%d errors occurred", rc);
853 : :
854 : 0 : rc = test_app_stop(test_app);
855 [ # # ]: 0 : if (rc != TEST_SUCCESS)
856 : : return rc;
857 : :
858 : : struct rte_dispatcher_stats stats;
859 : 0 : rte_dispatcher_stats_get(test_app->dispatcher, &stats);
860 : :
861 [ # # ]: 0 : TEST_ASSERT_EQUAL(stats.ev_drop_count, 0, "Drop count is not zero");
862 [ # # ]: 0 : TEST_ASSERT_EQUAL(stats.ev_dispatch_count, NUM_EVENTS * NUM_QUEUES,
863 : : "Invalid dispatch count");
864 [ # # ]: 0 : TEST_ASSERT(stats.poll_count > 0, "Poll count is zero");
865 : :
866 [ # # ]: 0 : TEST_ASSERT_EQUAL(test_app->never_process_count.count, 0,
867 : : "Never-match handler's process function has "
868 : : "been called");
869 : :
870 : 0 : int finalize_count =
871 : 0 : rte_atomic_load_explicit(&test_app->finalize_count.count,
872 : : rte_memory_order_relaxed);
873 : :
874 [ # # ]: 0 : TEST_ASSERT(finalize_count > 0, "Finalize count is zero");
875 [ # # ]: 0 : TEST_ASSERT(finalize_count <= (int)stats.ev_dispatch_count,
876 : : "Finalize count larger than event count");
877 : :
878 [ # # ]: 0 : TEST_ASSERT_EQUAL(finalize_count, (int)stats.ev_batch_count,
879 : : "%"PRIu64" batches dequeued, but finalize called %d "
880 : : "times", stats.ev_batch_count, finalize_count);
881 : :
882 : : /*
883 : : * The event dispatcher should call often-matching match functions
884 : : * more often, and thus this never-matching match function should
885 : : * be called relatively infrequently.
886 : : */
887 [ # # ]: 0 : TEST_ASSERT(test_app->never_match_count <
888 : : (stats.ev_dispatch_count / 4),
889 : : "Never-matching match function called suspiciously often");
890 : :
891 : 0 : rc = test_app_reset_dispatcher_stats(test_app);
892 [ # # ]: 0 : if (rc != TEST_SUCCESS)
893 : 0 : return rc;
894 : :
895 : : return TEST_SUCCESS;
896 : : }
897 : :
898 : : static int
899 : 0 : test_drop(void)
900 : : {
901 : : int rc;
902 : : uint8_t unhandled_queue;
903 : : struct rte_dispatcher_stats stats;
904 : :
905 : 0 : unhandled_queue = (uint8_t)rte_rand_max(NUM_QUEUES);
906 : :
907 : 0 : rc = test_app_start(test_app);
908 [ # # ]: 0 : if (rc != TEST_SUCCESS)
909 : : return rc;
910 : :
911 : 0 : rc = test_app_unregister_callback(test_app, unhandled_queue);
912 [ # # ]: 0 : if (rc != TEST_SUCCESS)
913 : : return rc;
914 : :
915 : 0 : struct rte_event event = {
916 : : .queue_id = unhandled_queue,
917 : : .flow_id = 0,
918 : : .sched_type = RTE_SCHED_TYPE_ATOMIC,
919 : : .op = RTE_EVENT_OP_NEW,
920 : : .priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
921 : : .u64 = 0
922 : : };
923 : :
924 : : do {
925 : 0 : rc = rte_event_enqueue_burst(test_app->event_dev_id,
926 : : DRIVER_PORT_ID, &event, 1);
927 [ # # ]: 0 : } while (rc == 0);
928 : :
929 : : do {
930 : 0 : rte_dispatcher_stats_get(test_app->dispatcher, &stats);
931 : :
932 [ # # ]: 0 : rte_event_maintain(test_app->event_dev_id, DRIVER_PORT_ID, 0);
933 [ # # # # ]: 0 : } while (stats.ev_drop_count == 0 && stats.ev_dispatch_count == 0);
934 : :
935 : 0 : rc = test_app_stop(test_app);
936 [ # # ]: 0 : if (rc != TEST_SUCCESS)
937 : : return rc;
938 : :
939 [ # # ]: 0 : TEST_ASSERT_EQUAL(stats.ev_drop_count, 1, "Drop count is not one");
940 [ # # ]: 0 : TEST_ASSERT_EQUAL(stats.ev_dispatch_count, 0,
941 : : "Dispatch count is not zero");
942 [ # # ]: 0 : TEST_ASSERT(stats.poll_count > 0, "Poll count is zero");
943 : :
944 : : return TEST_SUCCESS;
945 : : }
946 : :
947 : : #define MORE_THAN_MAX_HANDLERS 1000
948 : : #define MIN_HANDLERS 32
949 : :
950 : : static int
951 : 0 : test_many_handler_registrations(void)
952 : : {
953 : : int rc;
954 : : int num_regs = 0;
955 : : int reg_ids[MORE_THAN_MAX_HANDLERS];
956 : : int reg_id;
957 : : int i;
958 : :
959 : 0 : rc = test_app_unregister_callbacks(test_app);
960 [ # # ]: 0 : if (rc != TEST_SUCCESS)
961 : : return rc;
962 : :
963 [ # # ]: 0 : for (i = 0; i < MORE_THAN_MAX_HANDLERS; i++) {
964 : 0 : reg_id = rte_dispatcher_register(test_app->dispatcher,
965 : : never_match, NULL,
966 : : test_app_never_process, NULL);
967 [ # # ]: 0 : if (reg_id < 0)
968 : : break;
969 : :
970 : 0 : reg_ids[num_regs++] = reg_id;
971 : : }
972 : :
973 [ # # ]: 0 : TEST_ASSERT_EQUAL(reg_id, -ENOMEM, "Incorrect return code. Expected "
974 : : "%d but was %d", -ENOMEM, reg_id);
975 [ # # ]: 0 : TEST_ASSERT(num_regs >= MIN_HANDLERS, "Registration failed already "
976 : : "after %d handler registrations.", num_regs);
977 : :
978 [ # # ]: 0 : for (i = 0; i < num_regs; i++) {
979 : 0 : rc = rte_dispatcher_unregister(test_app->dispatcher,
980 : : reg_ids[i]);
981 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to unregister handler %d",
982 : : reg_ids[i]);
983 : : }
984 : :
985 : : return TEST_SUCCESS;
986 : : }
987 : :
988 : : static void
989 : 0 : dummy_finalize(uint8_t event_dev_id __rte_unused,
990 : : uint8_t event_port_id __rte_unused,
991 : : void *cb_data __rte_unused)
992 : : {
993 : 0 : }
994 : :
995 : : #define MORE_THAN_MAX_FINALIZERS 1000
996 : : #define MIN_FINALIZERS 16
997 : :
998 : : static int
999 : 0 : test_many_finalize_registrations(void)
1000 : : {
1001 : : int rc;
1002 : : int num_regs = 0;
1003 : : int reg_ids[MORE_THAN_MAX_FINALIZERS];
1004 : : int reg_id;
1005 : : int i;
1006 : :
1007 : 0 : rc = test_app_unregister_callbacks(test_app);
1008 [ # # ]: 0 : if (rc != TEST_SUCCESS)
1009 : : return rc;
1010 : :
1011 [ # # ]: 0 : for (i = 0; i < MORE_THAN_MAX_FINALIZERS; i++) {
1012 : 0 : reg_id = rte_dispatcher_finalize_register(
1013 : 0 : test_app->dispatcher, dummy_finalize, NULL
1014 : : );
1015 : :
1016 [ # # ]: 0 : if (reg_id < 0)
1017 : : break;
1018 : :
1019 : 0 : reg_ids[num_regs++] = reg_id;
1020 : : }
1021 : :
1022 [ # # ]: 0 : TEST_ASSERT_EQUAL(reg_id, -ENOMEM, "Incorrect return code. Expected "
1023 : : "%d but was %d", -ENOMEM, reg_id);
1024 [ # # ]: 0 : TEST_ASSERT(num_regs >= MIN_FINALIZERS, "Finalize registration failed "
1025 : : "already after %d registrations.", num_regs);
1026 : :
1027 [ # # ]: 0 : for (i = 0; i < num_regs; i++) {
1028 : 0 : rc = rte_dispatcher_finalize_unregister(
1029 : 0 : test_app->dispatcher, reg_ids[i]
1030 : : );
1031 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to unregister finalizer %d",
1032 : : reg_ids[i]);
1033 : : }
1034 : :
1035 : : return TEST_SUCCESS;
1036 : : }
1037 : :
1038 : : static struct unit_test_suite test_suite = {
1039 : : .suite_name = "Event dispatcher test suite",
1040 : : .unit_test_cases = {
1041 : : TEST_CASE_ST(test_setup, test_teardown, test_basic),
1042 : : TEST_CASE_ST(test_setup, test_teardown, test_drop),
1043 : : TEST_CASE_ST(test_setup, test_teardown,
1044 : : test_many_handler_registrations),
1045 : : TEST_CASE_ST(test_setup, test_teardown,
1046 : : test_many_finalize_registrations),
1047 : : TEST_CASES_END()
1048 : : }
1049 : : };
1050 : :
1051 : : static int
1052 : 1 : test_dispatcher(void)
1053 : : {
1054 : 1 : return unit_test_suite_runner(&test_suite);
1055 : : }
1056 : :
1057 : 303 : REGISTER_FAST_TEST(dispatcher_autotest, NOHUGE_SKIP, ASAN_OK, test_dispatcher);
|