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 : : .u64 = sn
389 : : };
390 : : }
391 : :
392 [ # # ]: 0 : if (intermediate_queue) {
393 : : uint16_t n = 0;
394 : :
395 : : do {
396 : 0 : n += rte_event_enqueue_forward_burst(p_event_dev_id,
397 : : p_event_port_id,
398 : 0 : out_events + n,
399 : 0 : num - n);
400 [ # # ]: 0 : } while (n != num);
401 : : } else
402 : 0 : rte_atomic_fetch_add_explicit(&app->completed_events, num,
403 : : rte_memory_order_relaxed);
404 : : }
405 : :
406 : : static bool
407 : 0 : never_match(const struct rte_event *event __rte_unused, void *cb_data)
408 : : {
409 : : uint64_t *count = cb_data;
410 : :
411 : 0 : (*count)++;
412 : :
413 : 0 : return false;
414 : : }
415 : :
416 : : static void
417 [ # # ]: 0 : test_app_never_process(uint8_t event_dev_id, uint8_t event_port_id,
418 : : struct rte_event *in_events __rte_unused, uint16_t num, void *cb_data)
419 : : {
420 : : struct cb_count *count = cb_data;
421 : : unsigned int lcore_id = rte_lcore_id();
422 : :
423 [ # # ]: 0 : if (event_dev_id == count->expected_event_dev_id &&
424 [ # # ]: 0 : event_port_id == count->expected_event_port_id[lcore_id])
425 : 0 : rte_atomic_fetch_add_explicit(&count->count, num,
426 : : rte_memory_order_relaxed);
427 : 0 : }
428 : :
429 : : static void
430 [ # # ]: 0 : finalize(uint8_t event_dev_id, uint8_t event_port_id, void *cb_data)
431 : : {
432 : : struct cb_count *count = cb_data;
433 : : unsigned int lcore_id = rte_lcore_id();
434 : :
435 [ # # ]: 0 : if (event_dev_id == count->expected_event_dev_id &&
436 [ # # ]: 0 : event_port_id == count->expected_event_port_id[lcore_id])
437 : 0 : rte_atomic_fetch_add_explicit(&count->count, 1,
438 : : rte_memory_order_relaxed);
439 : 0 : }
440 : :
441 : : static int
442 : 0 : test_app_register_callbacks(struct test_app *app)
443 : : {
444 : : int i;
445 : :
446 : 0 : app->never_match_reg_id =
447 : 0 : rte_dispatcher_register(app->dispatcher, never_match,
448 : 0 : &app->never_match_count,
449 : : test_app_never_process,
450 : 0 : &app->never_process_count);
451 : :
452 [ # # ]: 0 : TEST_ASSERT(app->never_match_reg_id >= 0, "Unable to register "
453 : : "never-match handler");
454 : :
455 [ # # ]: 0 : for (i = 0; i < NUM_QUEUES; i++) {
456 : 0 : struct app_queue *app_queue = &app->queues[i];
457 : 0 : uintptr_t queue_id = app_queue->queue_id;
458 : : int reg_id;
459 : :
460 : 0 : reg_id = rte_dispatcher_register(app->dispatcher,
461 : : match_queue, (void *)queue_id,
462 : : test_app_process_queue,
463 : : app_queue);
464 : :
465 [ # # ]: 0 : TEST_ASSERT(reg_id >= 0, "Unable to register consumer "
466 : : "callback for queue %d", i);
467 : :
468 : 0 : app_queue->dispatcher_reg_id = reg_id;
469 : : }
470 : :
471 : 0 : app->finalize_reg_id =
472 : 0 : rte_dispatcher_finalize_register(app->dispatcher,
473 : : finalize,
474 : 0 : &app->finalize_count);
475 [ # # ]: 0 : TEST_ASSERT_SUCCESS(app->finalize_reg_id, "Error registering "
476 : : "finalize callback");
477 : :
478 : : return TEST_SUCCESS;
479 : : }
480 : :
481 : : static int
482 : 0 : test_app_unregister_callback(struct test_app *app, uint8_t queue_id)
483 : : {
484 : 0 : int reg_id = app->queues[queue_id].dispatcher_reg_id;
485 : : int rc;
486 : :
487 [ # # ]: 0 : if (reg_id < 0) /* unregistered already */
488 : : return 0;
489 : :
490 : 0 : rc = rte_dispatcher_unregister(app->dispatcher, reg_id);
491 : :
492 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to unregister consumer "
493 : : "callback for queue %d", queue_id);
494 : :
495 : 0 : app->queues[queue_id].dispatcher_reg_id = -1;
496 : :
497 : 0 : return TEST_SUCCESS;
498 : : }
499 : :
500 : : static int
501 : 0 : test_app_unregister_callbacks(struct test_app *app)
502 : : {
503 : : int i;
504 : : int rc;
505 : :
506 [ # # ]: 0 : if (app->never_match_reg_id >= 0) {
507 : 0 : rc = rte_dispatcher_unregister(app->dispatcher,
508 : : app->never_match_reg_id);
509 : :
510 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to unregister never-match "
511 : : "handler");
512 : 0 : app->never_match_reg_id = -1;
513 : : }
514 : :
515 [ # # ]: 0 : for (i = 0; i < NUM_QUEUES; i++) {
516 : 0 : rc = test_app_unregister_callback(app, i);
517 [ # # ]: 0 : if (rc != TEST_SUCCESS)
518 : 0 : return rc;
519 : : }
520 : :
521 [ # # ]: 0 : if (app->finalize_reg_id >= 0) {
522 : 0 : rc = rte_dispatcher_finalize_unregister(
523 : : app->dispatcher, app->finalize_reg_id
524 : : );
525 : 0 : app->finalize_reg_id = -1;
526 : : }
527 : :
528 : : return TEST_SUCCESS;
529 : : }
530 : :
531 : : static void
532 : : test_app_start_dispatcher(struct test_app *app)
533 : : {
534 : 0 : rte_dispatcher_start(app->dispatcher);
535 : : }
536 : :
537 : : static void
538 : : test_app_stop_dispatcher(struct test_app *app)
539 : : {
540 : 0 : rte_dispatcher_stop(app->dispatcher);
541 : : }
542 : :
543 : : static int
544 : 0 : test_app_reset_dispatcher_stats(struct test_app *app)
545 : : {
546 : : struct rte_dispatcher_stats stats;
547 : :
548 : 0 : rte_dispatcher_stats_reset(app->dispatcher);
549 : :
550 : : memset(&stats, 0xff, sizeof(stats));
551 : :
552 : 0 : rte_dispatcher_stats_get(app->dispatcher, &stats);
553 : :
554 [ # # ]: 0 : TEST_ASSERT_EQUAL(stats.poll_count, 0, "Poll count not zero");
555 [ # # ]: 0 : TEST_ASSERT_EQUAL(stats.ev_batch_count, 0, "Batch count not zero");
556 [ # # ]: 0 : TEST_ASSERT_EQUAL(stats.ev_dispatch_count, 0, "Dispatch count "
557 : : "not zero");
558 [ # # ]: 0 : TEST_ASSERT_EQUAL(stats.ev_drop_count, 0, "Drop count not zero");
559 : :
560 : : return TEST_SUCCESS;
561 : : }
562 : :
563 : : static int
564 : 0 : test_app_setup_service_core(struct test_app *app, unsigned int lcore_id)
565 : : {
566 : : int rc;
567 : :
568 : 0 : rc = rte_service_lcore_add(lcore_id);
569 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to make lcore %d an event dispatcher "
570 : : "service core", lcore_id);
571 : :
572 : 0 : rc = rte_service_map_lcore_set(app->dispatcher_service_id, lcore_id, 1);
573 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to map event dispatcher service");
574 : :
575 : : return TEST_SUCCESS;
576 : : }
577 : :
578 : : static int
579 : 0 : test_app_setup_service_cores(struct test_app *app)
580 : : {
581 : : int i;
582 : : int lcore_id = -1;
583 : :
584 [ # # ]: 0 : for (i = 0; i < NUM_SERVICE_CORES; i++) {
585 : 0 : lcore_id = rte_get_next_lcore(lcore_id, 1, 0);
586 : :
587 : 0 : app->service_lcores[i] = lcore_id;
588 : : }
589 : :
590 [ # # ]: 0 : for (i = 0; i < NUM_SERVICE_CORES; i++) {
591 : : int rc;
592 : :
593 : 0 : rc = test_app_setup_service_core(app, app->service_lcores[i]);
594 [ # # ]: 0 : if (rc != TEST_SUCCESS)
595 : 0 : return rc;
596 : : }
597 : :
598 : : return TEST_SUCCESS;
599 : : }
600 : :
601 : : static int
602 : 0 : test_app_teardown_service_core(struct test_app *app, unsigned int lcore_id)
603 : : {
604 : : int rc;
605 : :
606 : 0 : rc = rte_service_map_lcore_set(app->dispatcher_service_id, lcore_id, 0);
607 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to unmap event dispatcher service");
608 : :
609 : 0 : rc = rte_service_lcore_del(lcore_id);
610 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable change role of service lcore %d",
611 : : lcore_id);
612 : :
613 : : return TEST_SUCCESS;
614 : : }
615 : :
616 : : static int
617 : 0 : test_app_teardown_service_cores(struct test_app *app)
618 : : {
619 : : int i;
620 : :
621 [ # # ]: 0 : for (i = 0; i < NUM_SERVICE_CORES; i++) {
622 : 0 : unsigned int lcore_id = app->service_lcores[i];
623 : : int rc;
624 : :
625 : 0 : rc = test_app_teardown_service_core(app, lcore_id);
626 [ # # ]: 0 : if (rc != TEST_SUCCESS)
627 : 0 : return rc;
628 : : }
629 : :
630 : : return TEST_SUCCESS;
631 : : }
632 : :
633 : : static int
634 : 0 : test_app_start_service_cores(struct test_app *app)
635 : : {
636 : : int i;
637 : :
638 [ # # ]: 0 : for (i = 0; i < NUM_SERVICE_CORES; i++) {
639 : 0 : unsigned int lcore_id = app->service_lcores[i];
640 : : int rc;
641 : :
642 : 0 : rc = rte_service_lcore_start(lcore_id);
643 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to start service lcore %d",
644 : : lcore_id);
645 : : }
646 : :
647 : : return TEST_SUCCESS;
648 : : }
649 : :
650 : : static int
651 : 0 : test_app_stop_service_cores(struct test_app *app)
652 : : {
653 : : int i;
654 : :
655 [ # # ]: 0 : for (i = 0; i < NUM_SERVICE_CORES; i++) {
656 : 0 : unsigned int lcore_id = app->service_lcores[i];
657 : : int rc;
658 : :
659 : 0 : rc = rte_service_lcore_stop(lcore_id);
660 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to stop service lcore %d",
661 : : lcore_id);
662 : : }
663 : :
664 : : return TEST_SUCCESS;
665 : : }
666 : :
667 : : static int
668 : 0 : test_app_start(struct test_app *app)
669 : : {
670 : : int rc;
671 : :
672 : 0 : rc = test_app_start_event_dev(app);
673 [ # # ]: 0 : if (rc != TEST_SUCCESS)
674 : : return rc;
675 : :
676 : 0 : rc = test_app_start_service_cores(app);
677 [ # # ]: 0 : if (rc != TEST_SUCCESS)
678 : : return rc;
679 : :
680 : : test_app_start_dispatcher(app);
681 : :
682 : 0 : app->running = true;
683 : :
684 : 0 : return TEST_SUCCESS;
685 : : }
686 : :
687 : : static int
688 : 0 : test_app_stop(struct test_app *app)
689 : : {
690 : : int rc;
691 : :
692 : : test_app_stop_dispatcher(app);
693 : :
694 : 0 : rc = test_app_stop_service_cores(app);
695 [ # # ]: 0 : if (rc != TEST_SUCCESS)
696 : : return rc;
697 : :
698 : : test_app_stop_event_dev(app);
699 : :
700 : 0 : app->running = false;
701 : :
702 : 0 : return TEST_SUCCESS;
703 : : }
704 : :
705 : : struct test_app *test_app;
706 : :
707 : : static int
708 : 4 : test_setup(void)
709 : : {
710 : : int rc;
711 : :
712 [ + - ]: 4 : if (rte_lcore_count() < MIN_LCORES) {
713 : : printf("Not enough cores for dispatcher_autotest; expecting at "
714 : : "least %d.\n", MIN_LCORES);
715 : 4 : return TEST_SKIPPED;
716 : : }
717 : :
718 : 0 : test_app = test_app_create();
719 [ # # ]: 0 : TEST_ASSERT(test_app != NULL, "Unable to allocate memory");
720 : :
721 : 0 : rc = test_app_setup_event_dev(test_app);
722 [ # # ]: 0 : if (rc != TEST_SUCCESS)
723 : 0 : goto err_free_app;
724 : :
725 : 0 : rc = test_app_create_dispatcher(test_app);
726 [ # # ]: 0 : if (rc != TEST_SUCCESS)
727 : 0 : goto err_teardown_event_dev;
728 : :
729 : 0 : rc = test_app_setup_service_cores(test_app);
730 [ # # ]: 0 : if (rc != TEST_SUCCESS)
731 : 0 : goto err_free_dispatcher;
732 : :
733 : 0 : rc = test_app_register_callbacks(test_app);
734 [ # # ]: 0 : if (rc != TEST_SUCCESS)
735 : 0 : goto err_teardown_service_cores;
736 : :
737 : 0 : rc = test_app_bind_ports(test_app);
738 [ # # ]: 0 : if (rc != TEST_SUCCESS)
739 : 0 : goto err_unregister_callbacks;
740 : :
741 : : return TEST_SUCCESS;
742 : :
743 : : err_unregister_callbacks:
744 : 0 : test_app_unregister_callbacks(test_app);
745 : 0 : err_teardown_service_cores:
746 : 0 : test_app_teardown_service_cores(test_app);
747 : 0 : err_free_dispatcher:
748 : 0 : test_app_free_dispatcher(test_app);
749 : 0 : err_teardown_event_dev:
750 : 0 : test_app_teardown_event_dev(test_app);
751 : 0 : err_free_app:
752 : 0 : test_app_free(test_app);
753 : :
754 : 0 : test_app = NULL;
755 : :
756 : 0 : return rc;
757 : : }
758 : :
759 : 4 : static void test_teardown(void)
760 : : {
761 [ - + ]: 4 : if (test_app == NULL)
762 : : return;
763 : :
764 [ # # ]: 0 : if (test_app->running)
765 : 0 : test_app_stop(test_app);
766 : :
767 : 0 : test_app_teardown_service_cores(test_app);
768 : :
769 : 0 : test_app_unregister_callbacks(test_app);
770 : :
771 : 0 : test_app_unbind_ports(test_app);
772 : :
773 : 0 : test_app_free_dispatcher(test_app);
774 : :
775 : 0 : test_app_teardown_event_dev(test_app);
776 : :
777 : 0 : test_app_free(test_app);
778 : :
779 : 0 : test_app = NULL;
780 : : }
781 : :
782 : : static int
783 : : test_app_get_completed_events(struct test_app *app)
784 : : {
785 : 0 : return rte_atomic_load_explicit(&app->completed_events,
786 : : rte_memory_order_relaxed);
787 : : }
788 : :
789 : : static int
790 : : test_app_get_errors(struct test_app *app)
791 : : {
792 : 0 : return rte_atomic_load_explicit(&app->errors, rte_memory_order_relaxed);
793 : : }
794 : :
795 : : static int
796 : 0 : test_basic(void)
797 : : {
798 : : int rc;
799 : : int i;
800 : :
801 : 0 : rc = test_app_start(test_app);
802 [ # # ]: 0 : if (rc != TEST_SUCCESS)
803 : : return rc;
804 : :
805 : 0 : uint64_t sns[NUM_FLOWS] = { 0 };
806 : :
807 [ # # ]: 0 : for (i = 0; i < NUM_EVENTS;) {
808 : : struct rte_event events[ENQUEUE_BURST_SIZE];
809 : : int left;
810 : : int batch_size;
811 : : int j;
812 : : uint16_t n = 0;
813 : :
814 : 0 : batch_size = 1 + rte_rand_max(ENQUEUE_BURST_SIZE);
815 : 0 : left = NUM_EVENTS - i;
816 : :
817 : 0 : batch_size = RTE_MIN(left, batch_size);
818 : :
819 [ # # ]: 0 : for (j = 0; j < batch_size; j++) {
820 : : struct rte_event *event = &events[j];
821 : : uint64_t sn;
822 : : uint32_t flow_id;
823 : :
824 : 0 : flow_id = rte_rand_max(NUM_FLOWS);
825 : :
826 : 0 : sn = sns[flow_id]++;
827 : :
828 : 0 : *event = (struct rte_event) {
829 : : .queue_id = 0,
830 : : .flow_id = flow_id,
831 : : .sched_type = RTE_SCHED_TYPE_ATOMIC,
832 : : .op = RTE_EVENT_OP_NEW,
833 : : .priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
834 : : .u64 = sn
835 : : };
836 : : }
837 : :
838 [ # # ]: 0 : while (n < batch_size)
839 : 0 : n += rte_event_enqueue_new_burst(test_app->event_dev_id,
840 : : DRIVER_PORT_ID,
841 : 0 : events + n,
842 : 0 : batch_size - n);
843 : :
844 : 0 : i += batch_size;
845 : : }
846 : :
847 [ # # ]: 0 : while (test_app_get_completed_events(test_app) != NUM_EVENTS)
848 [ # # ]: 0 : rte_event_maintain(test_app->event_dev_id, DRIVER_PORT_ID, 0);
849 : :
850 : 0 : rc = test_app_get_errors(test_app);
851 [ # # ]: 0 : TEST_ASSERT(rc == 0, "%d errors occurred", rc);
852 : :
853 : 0 : rc = test_app_stop(test_app);
854 [ # # ]: 0 : if (rc != TEST_SUCCESS)
855 : : return rc;
856 : :
857 : : struct rte_dispatcher_stats stats;
858 : 0 : rte_dispatcher_stats_get(test_app->dispatcher, &stats);
859 : :
860 [ # # ]: 0 : TEST_ASSERT_EQUAL(stats.ev_drop_count, 0, "Drop count is not zero");
861 [ # # ]: 0 : TEST_ASSERT_EQUAL(stats.ev_dispatch_count, NUM_EVENTS * NUM_QUEUES,
862 : : "Invalid dispatch count");
863 [ # # ]: 0 : TEST_ASSERT(stats.poll_count > 0, "Poll count is zero");
864 : :
865 [ # # ]: 0 : TEST_ASSERT_EQUAL(test_app->never_process_count.count, 0,
866 : : "Never-match handler's process function has "
867 : : "been called");
868 : :
869 : 0 : int finalize_count =
870 : 0 : rte_atomic_load_explicit(&test_app->finalize_count.count,
871 : : rte_memory_order_relaxed);
872 : :
873 [ # # ]: 0 : TEST_ASSERT(finalize_count > 0, "Finalize count is zero");
874 [ # # ]: 0 : TEST_ASSERT(finalize_count <= (int)stats.ev_dispatch_count,
875 : : "Finalize count larger than event count");
876 : :
877 [ # # ]: 0 : TEST_ASSERT_EQUAL(finalize_count, (int)stats.ev_batch_count,
878 : : "%"PRIu64" batches dequeued, but finalize called %d "
879 : : "times", stats.ev_batch_count, finalize_count);
880 : :
881 : : /*
882 : : * The event dispatcher should call often-matching match functions
883 : : * more often, and thus this never-matching match function should
884 : : * be called relatively infrequently.
885 : : */
886 [ # # ]: 0 : TEST_ASSERT(test_app->never_match_count <
887 : : (stats.ev_dispatch_count / 4),
888 : : "Never-matching match function called suspiciously often");
889 : :
890 : 0 : rc = test_app_reset_dispatcher_stats(test_app);
891 [ # # ]: 0 : if (rc != TEST_SUCCESS)
892 : 0 : return rc;
893 : :
894 : : return TEST_SUCCESS;
895 : : }
896 : :
897 : : static int
898 : 0 : test_drop(void)
899 : : {
900 : : int rc;
901 : : uint8_t unhandled_queue;
902 : : struct rte_dispatcher_stats stats;
903 : :
904 : 0 : unhandled_queue = (uint8_t)rte_rand_max(NUM_QUEUES);
905 : :
906 : 0 : rc = test_app_start(test_app);
907 [ # # ]: 0 : if (rc != TEST_SUCCESS)
908 : : return rc;
909 : :
910 : 0 : rc = test_app_unregister_callback(test_app, unhandled_queue);
911 [ # # ]: 0 : if (rc != TEST_SUCCESS)
912 : : return rc;
913 : :
914 : 0 : struct rte_event event = {
915 : : .queue_id = unhandled_queue,
916 : : .flow_id = 0,
917 : : .sched_type = RTE_SCHED_TYPE_ATOMIC,
918 : : .op = RTE_EVENT_OP_NEW,
919 : : .priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
920 : : .u64 = 0
921 : : };
922 : :
923 : : do {
924 : 0 : rc = rte_event_enqueue_burst(test_app->event_dev_id,
925 : : DRIVER_PORT_ID, &event, 1);
926 [ # # ]: 0 : } while (rc == 0);
927 : :
928 : : do {
929 : 0 : rte_dispatcher_stats_get(test_app->dispatcher, &stats);
930 : :
931 [ # # ]: 0 : rte_event_maintain(test_app->event_dev_id, DRIVER_PORT_ID, 0);
932 [ # # # # ]: 0 : } while (stats.ev_drop_count == 0 && stats.ev_dispatch_count == 0);
933 : :
934 : 0 : rc = test_app_stop(test_app);
935 [ # # ]: 0 : if (rc != TEST_SUCCESS)
936 : : return rc;
937 : :
938 [ # # ]: 0 : TEST_ASSERT_EQUAL(stats.ev_drop_count, 1, "Drop count is not one");
939 [ # # ]: 0 : TEST_ASSERT_EQUAL(stats.ev_dispatch_count, 0,
940 : : "Dispatch count is not zero");
941 [ # # ]: 0 : TEST_ASSERT(stats.poll_count > 0, "Poll count is zero");
942 : :
943 : : return TEST_SUCCESS;
944 : : }
945 : :
946 : : #define MORE_THAN_MAX_HANDLERS 1000
947 : : #define MIN_HANDLERS 32
948 : :
949 : : static int
950 : 0 : test_many_handler_registrations(void)
951 : : {
952 : : int rc;
953 : : int num_regs = 0;
954 : : int reg_ids[MORE_THAN_MAX_HANDLERS];
955 : : int reg_id;
956 : : int i;
957 : :
958 : 0 : rc = test_app_unregister_callbacks(test_app);
959 [ # # ]: 0 : if (rc != TEST_SUCCESS)
960 : : return rc;
961 : :
962 [ # # ]: 0 : for (i = 0; i < MORE_THAN_MAX_HANDLERS; i++) {
963 : 0 : reg_id = rte_dispatcher_register(test_app->dispatcher,
964 : : never_match, NULL,
965 : : test_app_never_process, NULL);
966 [ # # ]: 0 : if (reg_id < 0)
967 : : break;
968 : :
969 : 0 : reg_ids[num_regs++] = reg_id;
970 : : }
971 : :
972 [ # # ]: 0 : TEST_ASSERT_EQUAL(reg_id, -ENOMEM, "Incorrect return code. Expected "
973 : : "%d but was %d", -ENOMEM, reg_id);
974 [ # # ]: 0 : TEST_ASSERT(num_regs >= MIN_HANDLERS, "Registration failed already "
975 : : "after %d handler registrations.", num_regs);
976 : :
977 [ # # ]: 0 : for (i = 0; i < num_regs; i++) {
978 : 0 : rc = rte_dispatcher_unregister(test_app->dispatcher,
979 : : reg_ids[i]);
980 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to unregister handler %d",
981 : : reg_ids[i]);
982 : : }
983 : :
984 : : return TEST_SUCCESS;
985 : : }
986 : :
987 : : static void
988 : 0 : dummy_finalize(uint8_t event_dev_id __rte_unused,
989 : : uint8_t event_port_id __rte_unused,
990 : : void *cb_data __rte_unused)
991 : : {
992 : 0 : }
993 : :
994 : : #define MORE_THAN_MAX_FINALIZERS 1000
995 : : #define MIN_FINALIZERS 16
996 : :
997 : : static int
998 : 0 : test_many_finalize_registrations(void)
999 : : {
1000 : : int rc;
1001 : : int num_regs = 0;
1002 : : int reg_ids[MORE_THAN_MAX_FINALIZERS];
1003 : : int reg_id;
1004 : : int i;
1005 : :
1006 : 0 : rc = test_app_unregister_callbacks(test_app);
1007 [ # # ]: 0 : if (rc != TEST_SUCCESS)
1008 : : return rc;
1009 : :
1010 [ # # ]: 0 : for (i = 0; i < MORE_THAN_MAX_FINALIZERS; i++) {
1011 : 0 : reg_id = rte_dispatcher_finalize_register(
1012 : 0 : test_app->dispatcher, dummy_finalize, NULL
1013 : : );
1014 : :
1015 [ # # ]: 0 : if (reg_id < 0)
1016 : : break;
1017 : :
1018 : 0 : reg_ids[num_regs++] = reg_id;
1019 : : }
1020 : :
1021 [ # # ]: 0 : TEST_ASSERT_EQUAL(reg_id, -ENOMEM, "Incorrect return code. Expected "
1022 : : "%d but was %d", -ENOMEM, reg_id);
1023 [ # # ]: 0 : TEST_ASSERT(num_regs >= MIN_FINALIZERS, "Finalize registration failed "
1024 : : "already after %d registrations.", num_regs);
1025 : :
1026 [ # # ]: 0 : for (i = 0; i < num_regs; i++) {
1027 : 0 : rc = rte_dispatcher_finalize_unregister(
1028 : 0 : test_app->dispatcher, reg_ids[i]
1029 : : );
1030 [ # # ]: 0 : TEST_ASSERT_SUCCESS(rc, "Unable to unregister finalizer %d",
1031 : : reg_ids[i]);
1032 : : }
1033 : :
1034 : : return TEST_SUCCESS;
1035 : : }
1036 : :
1037 : : static struct unit_test_suite test_suite = {
1038 : : .suite_name = "Event dispatcher test suite",
1039 : : .unit_test_cases = {
1040 : : TEST_CASE_ST(test_setup, test_teardown, test_basic),
1041 : : TEST_CASE_ST(test_setup, test_teardown, test_drop),
1042 : : TEST_CASE_ST(test_setup, test_teardown,
1043 : : test_many_handler_registrations),
1044 : : TEST_CASE_ST(test_setup, test_teardown,
1045 : : test_many_finalize_registrations),
1046 : : TEST_CASES_END()
1047 : : }
1048 : : };
1049 : :
1050 : : static int
1051 : 1 : test_dispatcher(void)
1052 : : {
1053 : 1 : return unit_test_suite_runner(&test_suite);
1054 : : }
1055 : :
1056 : 251 : REGISTER_FAST_TEST(dispatcher_autotest, false, true, test_dispatcher);
|