EM-ODP 4.4.0
Event Machine on ODP
Loading...
Searching...
No Matches
em_init.c
1/* Copyright (c) 2020-2026 Nokia Solutions and Networks
2 * All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef _GNU_SOURCE
8#define _GNU_SOURCE
9#endif
10
11#ifdef HAVE_CONFIG_H
12#include "config.h"
13#endif
14
15#include <stdbool.h>
16#include <stdint.h>
17#include <stdio.h>
18#include <string.h>
19#include <sys/types.h>
20#include <unistd.h> /* getpid() */
21
22#include <odp_api.h>
23#include <odp/helper/odph_api.h>
24
25#include <event_machine.h>
27
28#include "em_atomic_group.h"
29#include "em_chaining.h"
30#include "em_chaining_types.h"
31#include "em_cli.h"
32#include "em_core.h"
33#include "em_dispatcher.h"
34#include "em_eo.h"
35#include "em_error.h"
36#include "em_error_types.h"
37#include "em_event.h"
38#include "em_event_group.h"
39#include "em_event_state.h"
40#include "em_hooks.h"
41#include "em_init.h"
42#include "em_init_types.h"
43#include "em_internal_event.h"
44#include "em_libconfig.h"
45#include "em_mem.h"
46#include "em_pool.h"
47#include "em_queue.h"
48#include "em_queue_group.h"
49#include "em_timer.h"
50
51const em_locm_t locm_init_values = EM_LOCM_INIT_VALUES;
52
53bool is_core_initialized(void)
54{
55 const em_locm_t *const locm = &em_locm;
56
57 /*
58 * Compare the PID stored in TLS with the current PID.
59 * A mismatch means either:
60 * - First use: init_pid is 0 (from EM_LOCM_INIT_VALUES) while
61 * getpid() returns a non-zero PID.
62 * - Post-fork child (process-per-core mode): the child inherited
63 * the parent's TLS with init_pid == parent PID, but getpid()
64 * now returns the child's PID.
65 * In both cases the core is not yet initialized.
66 *
67 * After a successful init, init_thr_mem() sets init_pid = getpid()
68 * and em_init_local()/em_init_core() set is_core_local_inited = true.
69 * Subsequent calls in the same process/thread will see a matching
70 * PID and return is_core_local_inited.
71 */
72 if (locm->init_pid != getpid())
73 return false;
74
75 return locm->is_core_local_inited;
76}
77
78static em_status_t input_poll_init_local(const em_conf_local_t *conf_local)
79{
80 em_locm_t *const locm = &em_locm;
81
82 locm->input_poll_fn = conf_local->input_poll_fn;
83
84 return EM_OK;
85}
86
87static em_status_t output_drain_init_local(const em_conf_local_t *conf_local)
88{
89 em_locm_t *const locm = &em_locm;
90
91 locm->output_drain_fn = conf_local->output_drain_fn;
92
93 return EM_OK;
94}
95
96void core_log_fn_set(em_log_func_t func)
97{
98 em_locm_t *const locm = &em_locm;
99
100 locm->log_fn = func;
101}
102
103void core_vlog_fn_set(em_vlog_func_t func)
104{
105 em_locm_t *const locm = &em_locm;
106
107 locm->vlog_fn = func;
108}
109
110em_status_t init_cli_thread(void)
111{
112 em_locm_t *const locm = &em_locm;
113 odp_shm_t shm;
114 em_shm_t *shm_addr;
115 em_status_t stat = EM_OK;
116
117 /* Make sure that em_shm is available in this external thread */
118 shm = odp_shm_lookup("em_shm");
119 RETURN_ERROR_IF(shm == ODP_SHM_INVALID,
120 EM_ERR_NOT_FOUND, EM_ESCOPE_INIT_CORE,
121 "Shared memory lookup failed!");
122
123 shm_addr = odp_shm_addr(shm);
124 RETURN_ERROR_IF(shm_addr == NULL, EM_ERR_BAD_POINTER, EM_ESCOPE_INIT_CORE,
125 "Shared memory ptr NULL");
126
127 if (em_shm != shm_addr)
128 em_shm = shm_addr;
129
130 RETURN_ERROR_IF(shm_addr != em_shm, EM_ERR_BAD_POINTER, EM_ESCOPE_INIT_CORE,
131 "Shared memory init fails: em_shm:%p != shm_addr:%p",
132 em_shm, shm_addr);
133
134 stat = emcli_init_local();
135 RETURN_ERROR_IF(stat != EM_OK, stat, EM_ESCOPE_INIT_CORE,
136 "emcli_init_local() fails: %" PRIxSTAT "", stat);
137
138 /*
139 * Mark that this is an external thread, i.e. not an EM-core and thus
140 * will not participate in EM event dispatching.
141 */
142 locm->is_external_thread = true;
143
144 return EM_OK;
145}
146
147em_status_t sync_api_init_local(void)
148{
149 em_locm_t *const locm = &em_locm;
150 int thr = odp_thread_id();
151 em_queue_t unsched_queue;
152 queue_elem_t *q_elem;
153
154 unsched_queue = queue_id2hdl(em_shm->queue_tbl.first_internal_queue_id + (uint16_t)thr);
155 if (unlikely(unsched_queue == EM_QUEUE_UNDEF))
156 return EM_ERR_NOT_FOUND;
157 q_elem = queue_elem_get(unsched_queue);
158 if (unlikely(!q_elem))
159 return EM_ERR_BAD_POINTER;
160 locm->sync_api.ctrl_poll.thr_unsched_queue = unsched_queue;
161 locm->sync_api.ctrl_poll.thr_unsched_qelem = q_elem;
162 locm->sync_api.ctrl_poll.thr_odp_plain_queue = q_elem->odp_queue;
163
164 unsched_queue = queue_id2hdl(em_shm->queue_tbl.shared_internal_queue_id);
165 if (unlikely(unsched_queue == EM_QUEUE_UNDEF))
166 return EM_ERR_NOT_FOUND;
167 q_elem = queue_elem_get(unsched_queue);
168 if (unlikely(!q_elem))
169 return EM_ERR_BAD_POINTER;
170 locm->sync_api.ctrl_poll.shared_unsched_queue = unsched_queue;
171 locm->sync_api.ctrl_poll.shared_unsched_qelem = q_elem;
172 locm->sync_api.ctrl_poll.shared_odp_plain_queue = q_elem->odp_queue;
173
174 locm->sync_api.in_progress = false;
175
176 return EM_OK;
177}
178
179static em_status_t init_thr_mem(void)
180{
181 em_locm_t *const locm = &em_locm;
182 odp_shm_t shm;
183 em_shm_t *shm_addr;
184
185 memset(locm, 0, sizeof(em_locm_t));
186 *locm = locm_init_values;
187 locm->init_pid = getpid();
188
189 /* Lookup the EM shared memory on each EM-core */
190 shm = odp_shm_lookup("em_shm");
191 if (unlikely(shm == ODP_SHM_INVALID)) {
192 EM_LOG(EM_LOG_ERR, "Shared memory lookup failed!");
193 return EM_ERR_NOT_FOUND;
194 }
195
196 shm_addr = odp_shm_addr(shm);
197 if (unlikely(shm_addr == NULL)) {
198 EM_LOG(EM_LOG_ERR, "Shared memory ptr NULL");
199 return EM_ERR_BAD_POINTER;
200 }
201
202 /* Process mode or EM external processes might need to update em_shm */
203 if (em_shm != shm_addr)
204 em_shm = shm_addr;
205
206 if (unlikely(shm_addr != em_shm)) {
207 EM_LOG(EM_LOG_ERR, "Shared memory init fails: em_shm:%p != shm_addr:%p",
208 em_shm, shm_addr);
209 return EM_ERR_BAD_POINTER;
210 }
211
212 return EM_OK;
213}
214
215em_status_t init_local(const em_conf_local_t *conf_local, em_escope_t escope)
216{
217 em_status_t stat;
218
219 stat = init_thr_mem();
220 RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, escope,
221 "init_thr_mem() failed:%" PRIxSTAT "", stat);
222
223 em_locm_t *const locm = &em_locm;
224
225 /* store the given local conf */
226 locm->conf_local = *conf_local;
227
228 /* locm->evhdr_nonem all-zero here: set only non-zero fields */
230 locm->evhdr_nonem.user_area.isinit = 1;
231
232 /*
233 * Create the core specific unsched control queue before local core-map
234 * init to avoid having another core targeting the queue before it's
235 * available.
236 */
237 stat = create_ctrl_queue();
238 RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, escope,
239 "create_ctrl_queue() failed:%" PRIxSTAT "", stat);
240
241 /* Initialize core mappings not known yet in core_map_init() */
242 stat = core_map_init_local(&em_shm->core_map, conf_local);
243 RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, escope,
244 "core_map_init_local() failed:%" PRIxSTAT "", stat);
245
246 stat = queue_group_init_local();
247 RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, escope,
248 "queue_group_init_local() failed:%" PRIxSTAT "", stat);
249
250 stat = dispatch_init_local();
251 RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, escope,
252 "dispatch_init_local() failed:%" PRIxSTAT "", stat);
253
254 /* Check if input_poll_fn should be executed on this core */
255 stat = input_poll_init_local(conf_local);
256 RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, escope,
257 "input_poll_init_local() failed:%" PRIxSTAT "", stat);
258
259 /* Check if output_drain_fn should be executed on this core */
260 stat = output_drain_init_local(conf_local);
261 RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, escope,
262 "output_drain_init_local() failed:%" PRIxSTAT "", stat);
263
264 stat = queue_init_local();
265 RETURN_ERROR_IF(stat != EM_OK, stat, escope,
266 "queue_init_local() failed:%" PRIxSTAT "", stat);
267
268 /*
269 * Initialize EM timer. If global init was not done (config),
270 * this is just a NOP
271 */
272 stat = timer_init_local();
273 RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, escope,
274 "timer_init_local() failed:%" PRIxSTAT "", stat);
275
276 stat = sync_api_init_local();
277 RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, escope,
278 "sync_api_init_local() failed:%" PRIxSTAT "", stat);
279
280 /* Init the EM CLI locally on this core (only if enabled) */
281 stat = emcli_init_local();
282 RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, escope,
283 "emcli_init_local() failed:%" PRIxSTAT "", stat);
284
285 /* Initialize debug timestamps to 1 if enabled to differentiate from disabled */
287 for (int i = 0; i < EM_DEBUG_TSP_LAST; i++)
288 locm->debug_ts[i] = 1;
289
290 /* Mark this thread as an EM-core that has a core-id and calls dispatch */
291 locm->is_em_core = true;
292 locm->is_external_thread = false;
293
294 /* Now OK to call EM APIs */
295
296 env_sync_mem();
297
298 /* Run EO local-start funcs for all EOs on a new core (if configured) */
299 eo_start_local_fn_at_init();
300
301 return EM_OK;
302}
303
304em_status_t init_extthr(const em_conf_local_t *conf_local, em_escope_t escope)
305{
306 em_status_t stat;
307
308 stat = init_thr_mem();
309 RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, escope,
310 "init_thr_mem() failed:%" PRIxSTAT "", stat);
311
312 em_locm_t *const locm = &em_locm;
313
314 /* store the given local conf */
315 locm->conf_local = *conf_local;
316
317 stat = create_ctrl_queue();
318 RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, escope,
319 "create_ctrl_queue() failed:%" PRIxSTAT "", stat);
320
321 stat = core_map_init_extthr(&em_shm->core_map);
322 RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, escope,
323 "core_map_init_extthr() failed:%" PRIxSTAT "", stat);
324
325 stat = sync_api_init_local();
326 RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, escope,
327 "sync_api_init_local() failed:%" PRIxSTAT "", stat);
328
329 /* Init the EM CLI locally on this core (only if enabled) */
330 stat = emcli_init_local();
331 RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, escope,
332 "emcli_init_local() failed:%" PRIxSTAT "", stat);
333
334 /* Mark this thread as an EM-control thread */
335 locm->is_em_core = false;
336 locm->is_external_thread = true;
337
338 return EM_OK;
339}
340
341void flush_scheduler_events(void)
342{
343 odp_event_t odp_ev_tbl[EM_SCHED_MULTI_MAX_BURST];
345 em_event_t em_ev_tbl[EM_SCHED_MULTI_MAX_BURST];
346 int num_events;
347
348 do {
349 num_events = odp_schedule_multi_no_wait(NULL, odp_ev_tbl, EM_SCHED_MULTI_MAX_BURST);
350 /* the check 'num_events > EM_SCHED_MULTI_MAX_BURST' avoids a gcc warning */
351 if (num_events <= 0 || num_events > EM_SCHED_MULTI_MAX_BURST)
352 break;
353 /*
354 * Events might originate from outside of EM and need init.
355 */
356 event_init_odp_multi(odp_ev_tbl, em_ev_tbl/*out*/, ev_hdr_tbl/*out*/,
357 num_events, true/*is_extev*/,
358 NULL/*not a dispatch: always scan*/);
359 em_free_multi(em_ev_tbl, num_events);
360 } while (num_events > 0);
361}
362
363em_status_t term_core(em_escope_t escope)
364{
365 em_status_t stat = EM_OK;
366 em_status_t ret_stat = EM_OK;
367 em_locm_t *const locm = &em_locm;
368 const int thr = odp_thread_id();
369
370 /* Run EO local-stop funcs for all EOs during term-core (if configured) */
371 eo_stop_local_fn_at_term();
372
373 /* continue core termination: */
374
375 int current_core_count = core_map_term_local(&em_shm->core_map, escope);
376
377 RETURN_ERROR_IF(current_core_count < 0, EM_ERR_LIB_FAILED, escope,
378 "core_map_term_local(): current_core_count=%d", current_core_count);
379
380 /*
381 * Poll internal unscheduled ctrl queues to complete ctrl actions
382 * and flush them.
383 */
384 int32_t cnt = 0;
385
386 do {
388
389 cnt = odp_atomic_load_u32(&em_shm->core_map.ongoing_term_reqs[thr]);
390 RETURN_ERROR_IF(cnt < 0, EM_ERR_TOO_SMALL, escope,
391 "%s(): ongoing_term_reqs[%02d]=%d", __func__, thr, cnt);
392 } while (!locm->is_term_thread_done || cnt);
393
394 /*
395 * Flush the scheduler from locally stashed events.
396 */
397 if (!locm->is_sched_paused) {
398 locm->is_sched_paused = true;
399 odp_schedule_pause();
400 }
401 flush_scheduler_events();
402
403 /* Stop EM Timer. Just a NOP if timer was not enabled (config) */
404 stat = timer_term_local();
405 if (stat != EM_OK) {
406 ret_stat = stat;
407 INTERNAL_ERROR(stat, escope,
408 "timer_term_local() fails: %" PRIxSTAT "", stat);
409 }
410
411 /* Term the EM CLI locally (if enabled) */
412 stat = emcli_term_local();
413 if (stat != EM_OK) {
414 ret_stat = stat;
415 INTERNAL_ERROR(stat, escope,
416 "emcli_term_local() fails: %" PRIxSTAT "", stat);
417 }
418
419 /* Delete the local queues */
420 stat = queue_term_local();
421 if (stat != EM_OK) {
422 ret_stat = stat;
423 INTERNAL_ERROR(stat, escope,
424 "queue_term_local() fails: %" PRIxSTAT "", stat);
425 }
426
427 bool flush_orphan_qgrps = em_shm->opt.queue_group.term_local_flush_orphans;
428
429 queue_group_leave_all(flush_orphan_qgrps);
430
431 locm->is_em_core = false;
432 locm->is_external_thread = false;
433
434 return ret_stat == EM_OK ? EM_OK : EM_ERR;
435}
436
437em_status_t term_extthr(em_escope_t escope)
438{
439 em_status_t stat = EM_OK;
440 em_status_t ret_stat = EM_OK;
441 em_locm_t *const locm = &em_locm;
442
443 int current_core_count = core_map_term_extthr(&em_shm->core_map, escope);
444
445 RETURN_ERROR_IF(current_core_count < 0, EM_ERR_LIB_FAILED, escope,
446 "core_map_term_extthr(): current_core_count=%d", current_core_count);
447
448 /*
449 * Poll internal unscheduled ctrl queues to complete ctrl actions
450 * and flush them.
451 */
452 do {
454 } while (!locm->is_term_thread_done);
455
456 /* Term the EM CLI locally (if enabled) */
457 stat = emcli_term_local();
458 if (stat != EM_OK) {
459 ret_stat = stat;
460 INTERNAL_ERROR(stat, escope,
461 "emcli_term_local() fails: %" PRIxSTAT "", stat);
462 }
463
464 locm->is_em_core = false;
465 locm->is_external_thread = false;
466
467 return ret_stat == EM_OK ? EM_OK : EM_ERR;
468}
469
470static void fill_startup_pools_str(char *startup_pools_str,
471 size_t startup_pools_str_size,
472 uint32_t num_startup_pools)
473{
474 size_t offset = 0;
475
476 for (uint32_t i = 0; i < num_startup_pools; i++) {
477 const em_startup_pool_conf_t *conf = &em_shm->opt.startup_pools.conf[i];
478
479 /* event_type */
480 const char *event_type_str = "UNKNOWN";
481
482 if (conf->cfg.event_type == EM_EVENT_TYPE_SW)
483 event_type_str = "EM_EVENT_TYPE_SW";
484 else if (conf->cfg.event_type == EM_EVENT_TYPE_PACKET)
485 event_type_str = "EM_EVENT_TYPE_PACKET";
486 else if (conf->cfg.event_type == EM_EVENT_TYPE_VECTOR)
487 event_type_str = "EM_EVENT_TYPE_VECTOR";
488
489 offset += snprintf(startup_pools_str + offset,
490 startup_pools_str_size - offset,
491 " conf[%u]:\n"
492 " name: %s\n"
493 " pool: %" PRI_POOL "\n"
494 " pool_cfg.event_type: %s\n"
495 " pool_cfg.align_offset.in_use: %s\n"
496 " pool_cfg.align_offset.value: %u\n"
497 " pool_cfg.user_area.in_use: %s\n"
498 " pool_cfg.user_area.size: %zu\n"
499 " pool_cfg.pkt.headroom.in_use: %s\n"
500 " pool_cfg.pkt.headroom.value: %u\n"
501 " pool_cfg.num_subpools: %u\n", i,
502 conf->name[0] ? conf->name : "(not set)",
503 conf->pool, event_type_str,
504 conf->cfg.align_offset.in_use ? "true" : "false",
505 conf->cfg.align_offset.value,
506 conf->cfg.user_area.in_use ? "true" : "false",
507 conf->cfg.user_area.size,
508 conf->cfg.pkt.headroom.in_use ? "true" : "false",
509 conf->cfg.pkt.headroom.value,
510 conf->cfg.num_subpools);
511
512 for (int j = 0; j < conf->cfg.num_subpools; j++) {
513 offset += snprintf(startup_pools_str + offset,
514 startup_pools_str_size - offset,
515 " pool_cfg.subpool[%d].size: %u\n"
516 " pool_cfg.subpool[%d].num: %u\n"
517 " pool_cfg.subpool[%d].cache_size: %u\n",
518 j, conf->cfg.subpool[j].size,
519 j, conf->cfg.subpool[j].num,
520 j, conf->cfg.subpool[j].cache_size);
521 }
522 }
523}
524
525void cfgfile_opts_print(void)
526{
527 size_t offset = 0;
528 char *startup_pools_str = NULL;
529 const uint32_t custom_map_size = 64;
530 char queue_priority_custom_map[custom_map_size];
531 uint32_t num_startup_pools = em_shm->opt.startup_pools.num;
532 size_t startup_pools_str_size = 1000 * num_startup_pools;
533
534 /* Allocate buffer based on actual number of pools: ~1000 bytes per pool */
535 if (num_startup_pools) {
536 startup_pools_str = malloc(startup_pools_str_size);
537 if (!startup_pools_str) {
538 EM_LOG(EM_LOG_ERR, "Failed to malloc(%zu) for startup_pools_str\n",
539 startup_pools_str_size);
540 return;
541 }
542 fill_startup_pools_str(startup_pools_str, startup_pools_str_size,
543 num_startup_pools);
544 }
545
546 if (em_shm->opt.queue.priority.map_mode != 2) {
547 queue_priority_custom_map[0] = '\0';
548 } else {
549 offset += snprintf(queue_priority_custom_map + offset,
550 custom_map_size - offset,
551 " priority.custom_map: [");
552
553 for (int i = 0; i < EM_QUEUE_PRIO_NUM - 1; i++) {
554 offset += snprintf(queue_priority_custom_map + offset,
555 custom_map_size - offset, "%d, ",
556 em_shm->opt.queue.priority.custom_map[i]);
557 }
558
559 snprintf(queue_priority_custom_map + offset,
560 custom_map_size - offset, "%d]\n",
561 em_shm->opt.queue.priority.custom_map[EM_QUEUE_PRIO_NUM - 1]);
562 }
563
564 EM_PRINT("\n"
565 "======================\n"
566 "EM Config File Options\n"
567 "======================\n"
568 "\ncli:\n"
569 " enable: %s\n"
570 " ip_addr: %s\n"
571 " port: %d\n"
572 "\ndispatch:\n"
573 " poll_ctrl_interval: %u\n"
574 " poll_ctrl_interval_ns: %" PRIu64 " ns\n"
575 " poll_drain_interval: %u\n"
576 " poll_drain_interval_ns: %" PRIu64 " ns\n"
577 " sched_wait_ns: %" PRIu64 " ns\n"
578 " sched_pause: %s\n"
579 "\neo:\n"
580 " start_local_fn_at_init: %s\n"
581 " stop_local_fn_at_term: %s\n"
582 "\nesv:\n"
583 " enable: %s\n"
584 " store_state: %s\n"
585 " store_payload_first_u32: %s\n"
586 " prealloc_pools: %s\n"
587 "\nevent_chaining:\n"
588 " order_keep: %s\n"
589 " num_order_queues: %u\n"
590 "\npool:\n"
591 " statistics.available: %u\n"
592 " statistics.alloc_ops: %u\n"
593 " statistics.alloc_fails: %u\n"
594 " statistics.free_ops: %u\n"
595 " statistics.total_ops: %u\n"
596 " statistics.cache_available: %u\n"
597 " statistics.cache_alloc_ops: %u\n"
598 " statistics.cache_free_ops: %u\n"
599 " statistics.core_cache_available: %u\n"
600 " align_offset: %u bytes\n"
601 " user_area_size: %zu bytes\n"
602 " pkt_headroom: %u bytes\n"
603 "\nqueue:\n"
604 " num_static: %u\n"
605 " num_dynamic: %u\n"
606 " min_events_default: %u\n"
607 " priority.map_mode: %d\n%s\n"
608 "\nqueue_group:\n"
609 " create_core_queue_groups: %s\n"
610 " term_local_flush_orphans: %s\n"
611 "\ntimer:\n"
612 " shared_tmo_pool_enable: %s\n"
613 " shared_tmo_pool_size: %u\n"
614 " tmo_pool_cache: %u\n"
615 " ring.timer_event_pool_size: %u\n"
616 " ring.timer_event_pool_cache: %u\n"
617 "\nvector:\n"
618 " backend: %s\n"
619 "\nstartup_pools:\n"
620 " num: %u\n%s\n",
621 em_shm->opt.cli.enable ? "true" : "false",
622 em_shm->opt.cli.ip_addr ? em_shm->opt.cli.ip_addr : "(null)",
623 em_shm->opt.cli.port,
624 em_shm->opt.dispatch.poll_ctrl_interval,
625 em_shm->opt.dispatch.poll_ctrl_interval_ns,
626 em_shm->opt.dispatch.poll_drain_interval,
627 em_shm->opt.dispatch.poll_drain_interval_ns,
628 em_shm->opt.dispatch.sched_wait_ns,
629 em_shm->opt.dispatch.sched_pause ? "true" : "false",
630 em_shm->opt.eo.start_local_fn_at_init ? "true" : "false",
631 em_shm->opt.eo.stop_local_fn_at_term ? "true" : "false",
632 em_shm->opt.esv.enable ? "true" : "false",
633 em_shm->opt.esv.store_state ? "true" : "false",
634 em_shm->opt.esv.store_first_u32 ? "true" : "false",
635 em_shm->opt.esv.prealloc_pools ? "true" : "false",
636 em_shm->opt.event_chaining.order_keep ? "true" : "false",
637 em_shm->opt.event_chaining.num_order_queues,
638 em_shm->opt.pool.statistics.available,
639 em_shm->opt.pool.statistics.alloc_ops,
640 em_shm->opt.pool.statistics.alloc_fails,
641 em_shm->opt.pool.statistics.free_ops,
642 em_shm->opt.pool.statistics.total_ops,
643 em_shm->opt.pool.statistics.cache_available,
644 em_shm->opt.pool.statistics.cache_alloc_ops,
645 em_shm->opt.pool.statistics.cache_free_ops,
646 em_shm->opt.pool.statistics.core_cache_available,
647 em_shm->opt.pool.align_offset,
648 em_shm->opt.pool.user_area_size,
649 em_shm->opt.pool.pkt_headroom,
650 em_shm->opt.queue.num_static,
651 em_shm->opt.queue.num_dynamic,
652 em_shm->opt.queue.min_events_default,
653 em_shm->opt.queue.priority.map_mode,
654 queue_priority_custom_map,
655 em_shm->opt.queue_group.create_core_queue_groups ? "true" : "false",
656 em_shm->opt.queue_group.term_local_flush_orphans ? "true" : "false",
657 em_shm->opt.timer.shared_tmo_pool_enable ? "true" : "false",
658 em_shm->opt.timer.shared_tmo_pool_size,
659 em_shm->opt.timer.tmo_pool_cache,
660 em_shm->opt.timer.ring.timer_event_pool_size,
661 em_shm->opt.timer.ring.timer_event_pool_cache,
662 em_shm->opt.vector.backend_str,
663 num_startup_pools,
664 startup_pools_str ? startup_pools_str : "");
665
666 if (startup_pools_str)
667 free(startup_pools_str);
668}
669
670void conf_local_opts_print(void)
671{
672 const char *core_type_str;
673 const em_locm_t *const locm = &em_locm;
674 const em_conf_local_t *conf_local = &locm->conf_local;
675
676 /* Format core type string */
677 switch (conf_local->core_type) {
679 core_type_str = "EM_CORE_TYPE_WORKER";
680 break;
682 core_type_str = "EM_CORE_TYPE_CONTROL";
683 break;
685 core_type_str = "EM_CORE_TYPE_EXTERNAL";
686 break;
687 default:
688 core_type_str = "UNKNOWN";
689 break;
690 }
691
692 EM_PRINT("\n"
693 "============================================\n"
694 "EM core-local config given to em_init_local()\n"
695 "or used by em_init_core()\n"
696 "============================================\n"
697 "\ncore_type: %s\n"
698 "core_id: %d\n"
699 "input_poll_fn: %s\n"
700 "output_drain_fn: %s\n"
701 "\n",
702 core_type_str,
703 conf_local->core_id,
704 conf_local->input_poll_fn ? "(set)" : "(not set)",
705 conf_local->output_drain_fn ? "(set)" : "(not set)");
706}
707
708void conf_opts_print(void)
709{
710 const em_conf_t *conf = &em_shm->conf;
711 char phys_mask_str[EM_CORE_MASK_STRLEN];
712 char default_pool_str[1024];
713 size_t offset = 0;
714
715 /* Format physical core mask */
716 em_core_mask_tostr(phys_mask_str, sizeof(phys_mask_str), &conf->phys_mask);
717
718 /* Format default pool config */
719 const em_pool_cfg_t *pool_cfg = &conf->default_pool_cfg;
720 const char *event_type_str = "UNKNOWN";
721
722 if (pool_cfg->event_type == EM_EVENT_TYPE_SW)
723 event_type_str = "EM_EVENT_TYPE_SW";
724 else if (pool_cfg->event_type == EM_EVENT_TYPE_PACKET)
725 event_type_str = "EM_EVENT_TYPE_PACKET";
726 else if (pool_cfg->event_type == EM_EVENT_TYPE_VECTOR)
727 event_type_str = "EM_EVENT_TYPE_VECTOR";
728
729 offset += snprintf(default_pool_str + offset,
730 sizeof(default_pool_str) - offset,
731 " event_type: %s\n"
732 " align_offset.in_use: %s\n"
733 " align_offset.value: %u\n"
734 " user_area.in_use: %s\n"
735 " user_area.size: %zu\n"
736 " pkt.headroom.in_use: %s\n"
737 " pkt.headroom.value: %u\n"
738 " num_subpools: %u\n",
739 event_type_str,
740 pool_cfg->align_offset.in_use ? "true" : "false",
741 pool_cfg->align_offset.value,
742 pool_cfg->user_area.in_use ? "true" : "false",
743 pool_cfg->user_area.size,
744 pool_cfg->pkt.headroom.in_use ? "true" : "false",
745 pool_cfg->pkt.headroom.value,
746 pool_cfg->num_subpools);
747
748 for (int i = 0; i < pool_cfg->num_subpools; i++) {
749 offset += snprintf(default_pool_str + offset,
750 sizeof(default_pool_str) - offset,
751 " subpool[%d].size: %u\n"
752 " subpool[%d].num: %u\n"
753 " subpool[%d].cache_size: %u\n",
754 i, pool_cfg->subpool[i].size,
755 i, pool_cfg->subpool[i].num,
756 i, pool_cfg->subpool[i].cache_size);
757 }
758
759 EM_PRINT("\n"
760 "====================================\n"
761 "EM runtime config given to em_init()\n"
762 "====================================\n"
763 "\ndevice_id: %u\n"
764 "event_timer: %s\n"
765 "thread_per_core: %s\n"
766 "process_per_core: %s\n"
767 "core_count: %u\n"
768 "phys_mask: %s\n"
769 "\ndefault_pool_cfg:\n%s\n"
770 "log.log_fn: %s\n"
771 "log.vlog_fn: %s\n"
772 "\napi_hooks.alloc_hook: %s\n"
773 "api_hooks.free_hook: %s\n"
774 "api_hooks.send_hook: %s\n"
775 "\nidle_hooks.to_idle_hook: %s\n"
776 "idle_hooks.to_active_hook: %s\n"
777 "idle_hooks.while_idle_hook: %s\n"
778 "\n",
779 conf->device_id,
780 conf->event_timer ? "true" : "false",
781 conf->thread_per_core ? "true" : "false",
782 conf->process_per_core ? "true" : "false",
783 conf->core_count,
784 phys_mask_str,
785 default_pool_str,
786 conf->log.log_fn ? "(set)" : "(not set)",
787 conf->log.vlog_fn ? "(set)" : "(not set)",
788 conf->api_hooks.alloc_hook ? "(set)" : "(not set)",
789 conf->api_hooks.free_hook ? "(set)" : "(not set)",
790 conf->api_hooks.send_hook ? "(set)" : "(not set)",
791 conf->idle_hooks.to_idle_hook ? "(set)" : "(not set)",
792 conf->idle_hooks.to_active_hook ? "(set)" : "(not set)",
793 conf->idle_hooks.while_idle_hook ? "(set)" : "(not set)");
794}
#define INTERNAL_ERROR(error, escope, fmt,...)
Definition em_error.h:58
#define RETURN_ERROR_IF(cond, error, escope, fmt,...)
Definition em_error.h:65
#define EM_LOCM_INIT_VALUES
Definition em_init.h:61
em_status_t create_ctrl_queue(void)
Create EM's internal unscheduled control queues at startup - one per core.
void poll_unsched_ctrl_queue(void)
Poll EM's internal unscheduled control queues during dispatch.
ENV_LOCAL em_locm_t em_locm
em_shm_t * em_shm
#define EM_DEBUG_TIMESTAMP_ENABLE
#define EM_QUEUE_PRIO_NUM
#define EM_SCHED_MULTI_MAX_BURST
void em_core_mask_tostr(char *mask_str, int len, const em_core_mask_t *mask)
#define EM_CORE_MASK_STRLEN
#define PRI_POOL
#define EM_QUEUE_UNDEF
em_status_t emcli_init_local(void)
Initialize the EM CLI locally on an EM core (if enabled)
Definition em_cli.c:2455
em_status_t emcli_term_local(void)
Terminate the EM CLI locally on an EM core (if enabled)
Definition em_cli.c:2465
@ EM_CORE_TYPE_CONTROL
@ EM_CORE_TYPE_EXTERNAL
@ EM_CORE_TYPE_WORKER
#define EM_OK
uint32_t em_escope_t
uint32_t em_status_t
int(* em_log_func_t)(em_log_level_t level, const char *fmt,...) __attribute__((format(printf
int(*) typedef int(* em_vlog_func_t)(em_log_level_t level, const char *fmt, va_list args)
@ EM_ERR_NOT_FOUND
@ EM_ERR_TOO_SMALL
@ EM_ERR_LIB_FAILED
@ EM_ERR_BAD_POINTER
void em_free_multi(em_event_t events[], int num)
@ EM_EVENT_TYPE_SW
@ EM_EVENT_TYPE_ODP
@ EM_EVENT_TYPE_PACKET
@ EM_EVENT_TYPE_VECTOR
em_input_poll_func_t input_poll_fn
em_output_drain_func_t output_drain_fn
em_core_type_t core_type
em_pool_cfg_t default_pool_cfg
em_core_mask_t phys_mask
bool is_core_local_inited
Definition em_mem.h:260
bool is_em_core
Definition em_mem.h:254
bool is_term_thread_done
Definition em_mem.h:258
bool is_sched_paused
Definition em_mem.h:252
em_output_drain_func_t output_drain_fn
Definition em_mem.h:247
event_hdr_t evhdr_nonem
Definition em_mem.h:306
em_input_poll_func_t input_poll_fn
Definition em_mem.h:245
uint64_t debug_ts[EM_DEBUG_TSP_LAST]
Definition em_mem.h:289
em_conf_local_t conf_local
Definition em_mem.h:295
em_log_func_t log_fn
Definition em_mem.h:280
em_vlog_func_t vlog_fn
Definition em_mem.h:283
sync_api_t sync_api
Definition em_mem.h:286
pid_t init_pid
Definition em_mem.h:272
bool is_external_thread
Definition em_mem.h:256
struct em_pool_cfg_t::@23 subpool[EM_MAX_SUBPOOLS]
em_event_type_t event_type
struct em_pool_cfg_t::@20 align_offset
em_conf_t conf
Definition em_mem.h:93
em_cfgfile_opts_t opt
Definition em_mem.h:99
ev_hdr_user_area_t user_area
em_event_type_t event_type
odp_queue_t odp_queue
em_queue_t shared_unsched_queue
em_queue_t thr_unsched_queue
odp_queue_t thr_odp_plain_queue
queue_elem_t * thr_unsched_qelem
odp_queue_t shared_odp_plain_queue
queue_elem_t * shared_unsched_qelem