diff --git a/CHANGE_NOTES b/CHANGE_NOTES index edc89285..7132d839 100644 --- a/CHANGE_NOTES +++ b/CHANGE_NOTES @@ -52,6 +52,32 @@ Examples: - See em-odp/README for usage and compilation instructions. - See em-odp/include/event_machine/README_API for API changes +-------------------------------------------------------------------------------- +Event Machine (EM) on ODP v3.7.0 +-------------------------------------------------------------------------------- +- Support for EM API v3.7 (em-odp/include/), + see API additions and changes in em-odp/include/event_machine/README_API. + Summary: + * Timer: em_timer_get_all() update + * Helper APIs: em_version_print(), em_info_print() + +- Startup printouts changed + The EM startup printouts / logging has been changed to reduce startup clutter + and give more control to the user about what is being printed and when. + EM will print the version information at startup (wuth the same content as + produced by the new helper API em_version_print()) but further printouts with + info about the running instance has been moved into another new helper API + em_info_print(), which the user can now call on demand + (as is done by the EM example applications, see programs/common/cm_setup.c). + +- configure, build: disable strict-aliasing (use -fno-strict-aliasing) + + Don't allow the compiler to assume the strictest aliasing rules. + Unless turned off, the -fstrict-aliasing option is enabled at + optimization levels -O2, -O3, -Os. + + EM contains some type casting that might violate C strict aliasing rules. + -------------------------------------------------------------------------------- Event Machine (EM) on ODP v3.6.0 -------------------------------------------------------------------------------- diff --git a/configure.ac b/configure.ac index 91c7cdcc..d882cd5d 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.69]) # Version ############################ m4_define([em_version_api_major], [3]) -m4_define([em_version_api_minor], [6]) +m4_define([em_version_api_minor], [7]) m4_define([em_version_implementation], [0]) m4_define([em_version_fix], [0]) @@ -82,7 +82,6 @@ AM_SILENT_RULES([yes]) AC_PROG_CXX AC_PROG_CC AC_PROG_CPP -AM_PROG_CC_C_O AM_PROG_AR # Use libtool @@ -144,7 +143,7 @@ AC_ARG_WITH([config-file], [default_config_file="${withval/#\~/$HOME}"], dnl replace ~ with $HOME []) -rel_default_config_file=`realpath --relative-to=$(pwd) ${default_config_file}` +rel_default_config_file=$(realpath --relative-to=$(pwd) ${default_config_file}) AC_SUBST([default_config_file]) AC_SUBST([rel_default_config_file]) @@ -154,6 +153,7 @@ EM_LIBCONFIG([$rel_default_config_file]) # Default warning setup ########################################################################## EM_CFLAGS="$EM_CFLAGS -W -Wall -Werror" +EM_CXXFLAGS="$EM_CXXFLAGS -W -Wall -Werror" # Additional warnings: EM_CHECK_CFLAG([-Wstrict-prototypes]) @@ -174,7 +174,7 @@ EM_CHECK_CFLAG([-Wshadow=local]) # GCC 10,11 sometimes gets confused about object sizes and gives bogus warnings. # Make the affected warnings generate only warnings, not errors. AS_IF([test "$GCC" == yes], - AS_IF([test `$CC -dumpversion | cut -d '.' -f 1` -ge 10], + AS_IF([test $($CC -dumpversion | cut -d '.' -f 1) -ge 10], EM_CHECK_CFLAG([-Wno-error=array-bounds]) EM_CHECK_CFLAG([-Wno-error=stringop-overflow]) EM_CHECK_CXXFLAG([-Wno-error=stringop-overflow]) @@ -184,7 +184,21 @@ AS_IF([test "$GCC" == yes], ) ) +########################################################################## +# Compiler optimization flags +########################################################################## + +# Don't allow the compiler to assume the strictest aliasing rules. +# Unless turned off, the -fstrict-aliasing option is enabled at +# optimization levels -O2, -O3, -Os. +EM_CHECK_CFLAG([-fno-strict-aliasing]) +EM_CHECK_CXXFLAG([-fno-strict-aliasing]) + +########################################################################## +# Set default C and C++ standard version to be used +########################################################################## EM_CFLAGS="$EM_CFLAGS -std=c11" +EM_CXXFLAGS="$EM_CXXFLAGS -std=c++11" # Extra flags for example to suppress certain warning types EM_CFLAGS="$EM_CFLAGS $EM_CFLAGS_EXTRA" @@ -463,7 +477,7 @@ AC_SUBST([EM_SCHED_WAIT_ENABLE]) # Default include setup ########################################################################## AM_CFLAGS="$AM_CFLAGS $EM_CFLAGS" -AM_CXXFLAGS="-std=c++11" +AM_CXXFLAGS="$AM_CXXFLAGS $EM_CXXFLAGS" AM_CPPFLAGS="$AM_CPPFLAGS $EM_CPPFLAGS" AC_CONFIG_FILES([ diff --git a/include/event_machine/README_API b/include/event_machine/README_API index efa12937..370e1e5e 100644 --- a/include/event_machine/README_API +++ b/include/event_machine/README_API @@ -5,6 +5,56 @@ EM API Release Notes - See em-odp/CHANGE_NOTES for changed and added features other than API changes. - See em-odp/README for usage and compilation instructions. +-------------------------------------------------------------------------------- +API 3.7 (EM_VERSION_API_MAJOR=3, EM_VERSION_API_MINOR=7) +-------------------------------------------------------------------------------- +1. Timer, fix: em_timer_get_all() always returns the actual number of timers. + (see include/event_machine/api/event_machine_timer.h) + + The API em_timer_get_all(*tmr_list, max) should, according to the API spec, + always return the actual number of timers regardless of the value of 'max'. + The prev implementation returned a value from 0 to 'max' even if there was + more timers - this is now fixed and the API documentation has been updated. + + num_timers = em_timer_get_all(NULL, 0); + would now always return the number of timers. + + When you also need a list of the timer handles: + num_timers = em_timer_get_all(tmr_list, max); + if (num_timers > max) { + /* more timers exist than could be filled into 'tmr_list' */ + } + +2. Helper: Print EM information + (see include/event_machine/helper/event_machine_helper.h) + + Two new helper APIs were added to enable printing EM version information + as well as various information about the running EM instance. + + Helper APIs: + void em_version_print(void) - Print EM related version information + void em_info_print(void) - Print miscellaneous EM information + + Both em_init() and em_version_print() will output version information: + =========================================================== + EM version information: em-odp + =========================================================== + EM API version: 3.7 + EM version: 3.7.0, 64 bit (EM_CHECK_LEVEL:3, EM_ESV_ENABLE:1) + EM build info: v3.7.0-18-g7ea320af 2024-08-21 14:36 + ODP API version: 1.45.0 + ODP impl name: odp-linux + ODP impl details: odp-linux 1.45.0-0 (v1.45.0) 1.45.0.0 + CPU model: Intel(R) Xeon(R) Gold 6212U CPU + CPU arch: x86 + CPU ISA version: Unknown + SW ISA version (ODP): x86_64 + SW ISA version (EM): x86_64 + + The helper API em_info_print() prints various data about the running + EM instance that previously were part of the em_init() printouts (removed + from em_init() to reduce startup clutter, printed now only on demand). + -------------------------------------------------------------------------------- API 3.6 (EM_VERSION_API_MAJOR=3, EM_VERSION_API_MINOR=6) -------------------------------------------------------------------------------- diff --git a/include/event_machine/api/event_machine_timer.h b/include/event_machine/api/event_machine_timer.h index 55f64894..1c004b4b 100644 --- a/include/event_machine/api/event_machine_timer.h +++ b/include/event_machine/api/event_machine_timer.h @@ -928,16 +928,26 @@ em_status_t em_tmo_ack(em_tmo_t tmo, em_event_t next_tmo_ev); /** * Get a list of currently active timers. * - * Returned timer handles can be used to query more information or to - * destroy all existing timers. + * The timer handles returned via 'tmr_list' can be used for further timer + * queries or to destroy existing timers. * - * The actual number of timers is always returned but 'tmr_list' will only be - * written up to the given 'max' length. + * The return value always reflects the actual number of timers in the + * EM instance but the output parameter 'tmr_list' is only written up to the + * given 'max' length. * - * @param [out] tmr_list Pointer to array of timer handles - * @param max Max number of handles that can written into tmr_list + * Note that the return value (number of timers) can be greater than the given + * 'max'. It is the user's responsibility to check the return value against the + * given 'max'. * - * @return number of active timers + * To only get the current number of active timers, without any timer handles + * output, use the following: num_timers = em_timer_get_all(NULL, 0); + * + * @param[out] tmr_list Pointer to an array of timer handles. + * Use NULL if only interested in the return value. + * @param max Max number of handles that can be written into tmr_list + * 'max' is ignored if 'tmr_list' is NULL. + * + * @return The number of active timers */ int em_timer_get_all(em_timer_t *tmr_list, int max); diff --git a/include/event_machine/helper/event_machine_helper.h b/include/event_machine/helper/event_machine_helper.h index bc070a49..72ff2c6c 100644 --- a/include/event_machine/helper/event_machine_helper.h +++ b/include/event_machine/helper/event_machine_helper.h @@ -50,20 +50,43 @@ extern "C" { /** * Format error string * - * Creates an implementation dependent error report string from EM - * internal errors. + * Creates an error report string from EM internal errors. + * Main use case: application error handlers to create an error report from + * EM internal errors. * * @param[out] str Output string pointer * @param size Maximum string length in characters - * @param eo EO id + * @param eo EO handle * @param error Error code (EM internal) * @param escope Error scope (EM internal) - * @param args Variable arguments + * @param args Variable arguments as passed to the error handler * * @return Output string length. */ int em_error_format_string(char *str /*out*/, size_t size, em_eo_t eo, em_status_t error, em_escope_t escope, va_list args); +/** + * @brief Print EM related version information + * + * Prints the EM version information, as well as version information for the + * used ODP and HW etc. (similar to what EM prints at startup). + * + * For EM API version strings, defines and macros see + * include/event_machine/api/event_machine_version.h + * + * The printed content may vary from one EM release to the next. + */ +void em_version_print(void); + +/** + * @brief Print miscellaneous EM information + * + * Print information about the running EM instance. + * Mainly for debug or startup logging needs. + * + * The printed content may vary from one EM release to the next. + */ +void em_info_print(void); /* * Physical core ids diff --git a/m4/em_libconfig.m4 b/m4/em_libconfig.m4 index 92170d13..c12cfce0 100644 --- a/m4/em_libconfig.m4 +++ b/m4/em_libconfig.m4 @@ -31,7 +31,7 @@ AS_IF([test -z "$1"] || [test ! -f $1], [AC_MSG_ERROR([Default configuration file not found: $1])], []) conf_ver=_em_config_version -file_ver=`$SED 's/ //g' $1 | $GREP -oP '(?<=config_file_version=").*?(?=")'` +file_ver=$($SED 's/ //g' $1 | $GREP -oP '(?<=config_file_version=").*?(?=")') AS_IF([test "x$conf_ver" = "x$file_ver"], [], [AC_MSG_ERROR([Configuration file version mismatch: diff --git a/programs/common/cm_setup.c b/programs/common/cm_setup.c index a0c9ec3c..97d1704d 100644 --- a/programs/common/cm_setup.c +++ b/programs/common/cm_setup.c @@ -856,6 +856,13 @@ static void startup_all_cores(sync_t *sync, const appl_conf_t *appl_conf, odp_barrier_wait(&sync->start_barrier); + int core_id = em_core_id(); + + if (core_id == 0) + em_info_print(); + + odp_barrier_wait(&sync->start_barrier); + if (appl_conf->pktio.if_count > 0) pktio_mem_lookup(is_thread_per_core); @@ -871,7 +878,6 @@ static void startup_all_cores(sync_t *sync, const appl_conf_t *appl_conf, * where they are ready to process events as soon as the EOs have been * started and queues enabled. */ - int core_id = em_core_id(); uint64_t cores = appl_conf->core_count; /* Ensure all EM cores can find the default event pool */ @@ -1053,6 +1059,9 @@ static void startup_one_core_first(sync_t *sync, const appl_conf_t *appl_conf, if (core_id == 0) env_atomic64_inc(&sync->enter_count); } while (env_atomic64_get(&sync->enter_count) <= 2 * cores); + + if (core_id == 0) + em_info_print(); } /* diff --git a/programs/performance/.gitignore b/programs/performance/.gitignore index 4eb4700d..057cfa5f 100644 --- a/programs/performance/.gitignore +++ b/programs/performance/.gitignore @@ -1,5 +1,8 @@ atomic_processing_end loop +loop_multircv +loop_refs +loop_vectors pairs queue_groups queues @@ -8,6 +11,5 @@ queues_output queues_unscheduled send_multi timer_test -timer_test_ring timer_test_periodic -loop_multircv +timer_test_ring diff --git a/programs/performance/Makefile.am b/programs/performance/Makefile.am index 4cb96b3e..f275e73a 100644 --- a/programs/performance/Makefile.am +++ b/programs/performance/Makefile.am @@ -5,6 +5,7 @@ noinst_PROGRAMS = atomic_processing_end \ loop \ loop_multircv \ loop_refs \ + loop_vectors \ queue_groups \ queues \ queues_unscheduled \ @@ -32,6 +33,9 @@ loop_multircv_CFLAGS = $(AM_CFLAGS) loop_refs_LDFLAGS = $(AM_LDFLAGS) loop_refs_CFLAGS = $(AM_CFLAGS) +loop_vectors_LDFLAGS = $(AM_LDFLAGS) +loop_vectors_CFLAGS = $(AM_CFLAGS) + queue_groups_LDFLAGS = $(AM_LDFLAGS) queue_groups_CFLAGS = $(AM_CFLAGS) @@ -70,6 +74,7 @@ dist_pairs_SOURCES = pairs.c dist_loop_SOURCES = loop.c dist_loop_multircv_SOURCES = loop_multircv.c dist_loop_refs_SOURCES = loop_refs.c +dist_loop_vectors_SOURCES = loop_vectors.c dist_queue_groups_SOURCES = queue_groups.c dist_queues_SOURCES = queues.c dist_queues_unscheduled_SOURCES = queues_unscheduled.c diff --git a/programs/performance/loop_vectors.c b/programs/performance/loop_vectors.c index efb37a63..9084eb30 100644 --- a/programs/performance/loop_vectors.c +++ b/programs/performance/loop_vectors.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Nokia Solutions and Networks + * Copyright (c) 2024, Nokia Solutions and Networks * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,7 +31,10 @@ /** * @file * - * Event Machine performance test example + * Event Machine performance test example using event vectors. + * + * Test based on the 'loop' test but changed to use event vectors instead of + * separate events. * * Measures the average cycles consumed during an event send-sched-receive loop * for a certain number of EOs in the system. The test has a number of EOs, each @@ -229,8 +232,11 @@ void test_start(const appl_conf_t *appl_conf) em_pool_cfg_init(&vec_pool_cfg); vec_pool_cfg.event_type = EM_EVENT_TYPE_VECTOR; vec_pool_cfg.num_subpools = 1; - vec_pool_cfg.subpool[0].cache_size = 0; /* all allocated in startup */ - vec_pool_cfg.subpool[0].num = NUM_EO * NUM_EVENT_PER_QUEUE; + if (ALLOC_FREE_PER_EVENT) + vec_pool_cfg.subpool[0].cache_size = 32; + else + vec_pool_cfg.subpool[0].cache_size = 0; /* all allocated in startup */ + vec_pool_cfg.subpool[0].num = NUM_EO * NUM_EVENT_PER_QUEUE * 2; vec_pool_cfg.subpool[0].size = MAX_VECTOR_SIZE; vec_pool = em_pool_create("vector-pool", EM_POOL_UNDEF, &vec_pool_cfg); @@ -443,14 +449,43 @@ perf_receive(void *eo_context, em_event_t event, em_event_type_t type, } if (ALLOC_FREE_PER_EVENT) { - em_pool_t pool = perf_shm->pool; + if (em_event_type_major(type) == EM_EVENT_TYPE_VECTOR) { + em_pool_t vec_pool = perf_shm->vec_pool; - if (em_event_type_major(type) == EM_EVENT_TYPE_VECTOR) - pool = perf_shm->vec_pool; + em_event_t *vectbl = NULL; + uint32_t vec_sz = em_event_vector_tbl(event, &vectbl); - em_free(event); - event = em_alloc(sizeof(perf_event_t), type, pool); - test_fatal_if(event == EM_EVENT_UNDEF, "Event alloc fails"); + test_fatal_if(!vec_sz || !vectbl, + "Vector table invalid: sz=%d vectbl=%p)", + vec_sz, vectbl); + + em_event_t vec = em_alloc(vec_sz, EM_EVENT_TYPE_VECTOR, vec_pool); + + test_fatal_if(vec == EM_EVENT_UNDEF, + "Vector allocation failed, sz=%u, events=%" PRIi64 "", + vec_sz, events + 1); + + em_event_t *vectbl_new = NULL; + uint32_t sz_new = em_event_vector_tbl(vec, &vectbl_new); + + test_fatal_if(sz_new || !vectbl_new, + "Vector table invalid: sz=%d vectbl=%p)", + sz_new, vectbl_new); + + for (uint32_t i = 0; i < vec_sz; i++) + vectbl_new[i] = vectbl[i]; + + em_event_vector_size_set(vec, vec_sz); + + em_event_vector_free(event); + event = vec; + } else { + em_pool_t pool = perf_shm->pool; + + em_free(event); + event = em_alloc(sizeof(perf_event_t), type, pool); + test_fatal_if(event == EM_EVENT_UNDEF, "Event alloc fails"); + } } /* Send the event back into the queue it originated from, i.e. loop */ diff --git a/robot-tests/example/emcli.robot b/robot-tests/example/emcli.robot index 06d6511a..cc91ada4 100644 --- a/robot-tests/example/emcli.robot +++ b/robot-tests/example/emcli.robot @@ -209,7 +209,6 @@ Test EM Info Print # em_info_print @{em_info_regex} = Create List ... ^EM Info on target: em-odp\\s?$(?m) - ... ^EM API version:\\s+\\d+\\.\\d+\\s?$(?m) ... ^Core mapping: EM-core <-> phys-core <-> ODP-thread\\s?$(?m) ... ^ODP Queue Capabilities\\s?$(?m) ... ^EM Queues\\s?$(?m) diff --git a/robot-tests/performance/loop_vectors.robot b/robot-tests/performance/loop_vectors.robot new file mode 100644 index 00000000..5c863760 --- /dev/null +++ b/robot-tests/performance/loop_vectors.robot @@ -0,0 +1,29 @@ +*** Comments *** +Copyright (c) 2024, Nokia Solutions and Networks +All rights reserved. +SPDX-License-Identifier: BSD-3-Clause + + +*** Settings *** +Documentation Test Loop Vectors -c ${CORE_MASK} -${APPLICATION_MODE} +Resource ../common.resource +Test Setup Set Log Level TRACE +Test Teardown Kill Any Hanging Applications + + +*** Variables *** +${FIRST_REGEX} = SEPARATOR= +... cycles/event:\\s*[0-9]+\\.[0-9]+\\s*Mevents/s/core:\\s*[0-9]+\\.[0-9]+ +... \\s*[0-9]+\\s*MHz\\s*core[0-9]+\\s*[0-9]+ + +@{REGEX_MATCH} = +... ${FIRST_REGEX} +... Done\\s*-\\s*exit + + +*** Test Cases *** +Test Loop Vectors + [Documentation] loop_vectors -c ${CORE_MASK} -${APPLICATION_MODE} + [TAGS] ${CORE_MASK} ${APPLICATION_MODE} + + Run EM-ODP Test sleep_time=60 regex_match=${REGEX_MATCH} diff --git a/scripts/robot_test.sh b/scripts/robot_test.sh index 9e574718..8f1e5288 100755 --- a/scripts/robot_test.sh +++ b/scripts/robot_test.sh @@ -37,6 +37,7 @@ apps["atomic_processing_end"]=programs/performance/atomic_processing_end apps["loop"]=programs/performance/loop apps["loop_multircv"]=programs/performance/loop_multircv apps["loop_refs"]=programs/performance/loop_refs +apps["loop_vectors"]=programs/performance/loop_vectors apps["pairs"]=programs/performance/pairs apps["queue_groups"]=programs/performance/queue_groups apps["queues_local"]=programs/performance/queues_local diff --git a/src/Makefile.am b/src/Makefile.am index 8dcf246e..b193d056 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -79,7 +79,7 @@ $(top_srcdir)/include/event_machine/platform/env/env_sharedmem.h \ $(top_srcdir)/include/event_machine/platform/env/env_spinlock.h \ $(top_srcdir)/include/event_machine/platform/env/env_time.h -BUILT_SOURCES = include/em_libconfig_config.h +BUILT_SOURCES = $(top_builddir)/include/em_libconfig_config.h __LIB__libemodp_la_SOURCES = \ event_machine_atomic_group.c \ diff --git a/src/em_core.c b/src/em_core.c index 7bf775f1..cd4c31c7 100644 --- a/src/em_core.c +++ b/src/em_core.c @@ -144,13 +144,6 @@ void mask_em2odp(const em_core_mask_t *const em_core_mask, odp_thrmask_zero(odp_thrmask); - if (unlikely(!em_shm->init.em_init_done)) { - INTERNAL_ERROR(EM_ERR_NOT_INITIALIZED, EM_ESCOPE_INIT, - "Cannot convert EM-mask to ODP-thrmask,\n" - "not all ODP threads are initialized yet."); - return; - } - /* EM cores are consecutive 0 -> em_core_count()-1 */ for (int i = 0; i < core_count; i++) { if (em_core_mask_isset(i, em_core_mask)) { diff --git a/src/em_info.c b/src/em_info.c index 0cf9f3da..391c1e9b 100644 --- a/src/em_info.c +++ b/src/em_info.c @@ -312,21 +312,12 @@ void print_cpu_arch_info(void) "CPU arch: %s\n" "CPU ISA version: %s\n" " SW ISA version (ODP): %s\n" - " SW ISA version (EM): %s\n", + " SW ISA version (EM): %s\n" + "\n", odp_cpu_model_str(), cpu_arch, hw_isa, sw_isa_odp, sw_isa_em); } -static void print_odp_info(void) -{ - EM_PRINT("ODP API version: %s\n" - "ODP impl name: %s\n" - "ODP impl details: %s\n", - odp_version_api_str(), - odp_version_impl_name(), - odp_version_impl_str()); -} - static void print_mem_info(void) { EM_PRINT("EM shared mem size: %zu B\n" @@ -401,14 +392,11 @@ static void print_mem_info(void) ); } -/** - * Print information about EM & the environment - */ -void print_em_info(void) +void print_version_info(void) { EM_PRINT("\n" "===========================================================\n" - "EM Info on target: %s\n" + "EM version information: %s\n" "===========================================================\n" "EM API version: %s\n" "EM version: %s, " @@ -418,13 +406,30 @@ void print_em_info(void) "32 bit " #endif "(EM_CHECK_LEVEL:%d, EM_ESV_ENABLE:%d)\n" - "EM build info: %s\n", + "EM build info: %s\n" + "ODP API version: %s\n" + "ODP impl name: %s\n" + "ODP impl details: %s\n", EM_TARGET_STR, EM_VERSION_API_STR, EM_VERSION_STR, EM_CHECK_LEVEL, EM_ESV_ENABLE, - EM_BUILD_INFO_STR); + EM_BUILD_INFO_STR, + odp_version_api_str(), + odp_version_impl_name(), + odp_version_impl_str()); - print_odp_info(); print_cpu_arch_info(); +} + +/** + * Print information about EM & the environment + */ +void print_em_info(void) +{ + EM_PRINT("\n" + "===========================================================\n" + "EM Info on target: %s\n" + "===========================================================\n", + EM_TARGET_STR); print_mem_info(); print_core_map_info(); print_queue_capa(); diff --git a/src/em_info.h b/src/em_info.h index 08a3e46c..c0060668 100644 --- a/src/em_info.h +++ b/src/em_info.h @@ -41,14 +41,13 @@ extern "C" { #endif -void -print_em_info(void); +void print_version_info(void); -void -print_cpu_arch_info(void); +void print_em_info(void); -void -print_core_map_info(void); +void print_cpu_arch_info(void); + +void print_core_map_info(void); #ifdef __cplusplus } diff --git a/src/em_init.c b/src/em_init.c index 425b5227..75770b79 100644 --- a/src/em_init.c +++ b/src/em_init.c @@ -6,9 +6,8 @@ #include "em_include.h" -em_status_t -poll_drain_mask_check(const em_core_mask_t *logic_mask, - const em_core_mask_t *poll_drain_mask) +static em_status_t poll_drain_mask_check(const em_core_mask_t *logic_mask, + const em_core_mask_t *poll_drain_mask) { /* check if mask is zero (all cores, OK) */ if (em_core_mask_iszero(poll_drain_mask)) @@ -23,53 +22,55 @@ poll_drain_mask_check(const em_core_mask_t *logic_mask, return EM_OK; } -em_status_t -input_poll_init(const em_core_mask_t *logic_mask, const em_conf_t *conf) +em_status_t input_poll_check(const em_core_mask_t *logic_mask, const em_conf_t *conf) { - return poll_drain_mask_check(logic_mask, - &conf->input.input_poll_mask); + return poll_drain_mask_check(logic_mask, &conf->input.input_poll_mask); } -em_status_t -output_drain_init(const em_core_mask_t *logic_mask, const em_conf_t *conf) +em_status_t output_drain_check(const em_core_mask_t *logic_mask, const em_conf_t *conf) { - return poll_drain_mask_check(logic_mask, - &conf->output.output_drain_mask); + return poll_drain_mask_check(logic_mask, &conf->output.output_drain_mask); } -em_status_t -poll_drain_mask_set_local(bool *const result /*out*/, int core_id, - const em_core_mask_t *mask) +static bool poll_drain_check_local(int core_id, const em_core_mask_t *mask) { if (em_core_mask_iszero(mask) || em_core_mask_isset(core_id, mask)) - *result = true; - else - *result = false; - return EM_OK; + return true; + + return false; } -em_status_t -input_poll_init_local(bool *const result /*out*/, int core_id, - const em_conf_t *conf) +em_status_t input_poll_init_local(void) { + const em_conf_t *conf = &em_shm->conf; + em_locm_t *const locm = &em_locm; + if (conf->input.input_poll_fn == NULL) { - *result = false; + locm->do_input_poll = false; return EM_OK; } - return poll_drain_mask_set_local(result, core_id, - &conf->input.input_poll_mask); + + const em_core_mask_t *input_poll_mask = &conf->input.input_poll_mask; + + locm->do_input_poll = poll_drain_check_local(locm->core_id, input_poll_mask); + + return EM_OK; } -em_status_t -output_drain_init_local(bool *const result /*out*/, int core_id, - const em_conf_t *conf) +em_status_t output_drain_init_local(void) { + const em_conf_t *conf = &em_shm->conf; + em_locm_t *const locm = &em_locm; + if (conf->output.output_drain_fn == NULL) { - *result = false; + locm->do_output_drain = false; return EM_OK; } - return poll_drain_mask_set_local(result, core_id, - &conf->output.output_drain_mask); + const em_core_mask_t *output_drain_mask = &conf->output.output_drain_mask; + + locm->do_output_drain = poll_drain_check_local(locm->core_id, output_drain_mask); + + return EM_OK; } void core_log_fn_set(em_log_func_t func) diff --git a/src/em_init.h b/src/em_init.h index 9b1953d2..59c2ac72 100644 --- a/src/em_init.h +++ b/src/em_init.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Nokia Solutions and Networks + * Copyright (c) 2015-2024, Nokia Solutions and Networks * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,18 +41,6 @@ extern "C" { #endif -/** - * Initialization status info - */ -typedef struct { - /** init lock */ - env_spinlock_t lock; - /** Is em_init() completed? */ - int em_init_done; - /** The number of EM cores that have run em_init_core() */ - int em_init_core_cnt; -} init_t; - /** * Pool configuration */ @@ -137,27 +125,11 @@ typedef struct { } startup_pools; } opt_t; -em_status_t -poll_drain_mask_check(const em_core_mask_t *logic_mask, - const em_core_mask_t *poll_drain_mask); - -em_status_t -input_poll_init(const em_core_mask_t *logic_mask, const em_conf_t *conf); - -em_status_t -output_drain_init(const em_core_mask_t *logic_mask, const em_conf_t *conf); - -em_status_t -poll_drain_mask_set_local(bool *const result /*out*/, int core_id, - const em_core_mask_t *mask); - -em_status_t -input_poll_init_local(bool *const result /*out*/, int core_id, - const em_conf_t *conf); +em_status_t input_poll_check(const em_core_mask_t *logic_mask, const em_conf_t *conf); +em_status_t output_drain_check(const em_core_mask_t *logic_mask, const em_conf_t *conf); -em_status_t -output_drain_init_local(bool *const result /*out*/, int core_id, - const em_conf_t *conf); +em_status_t input_poll_init_local(void); +em_status_t output_drain_init_local(void); /** * Set EM core local log function. @@ -166,8 +138,7 @@ output_drain_init_local(bool *const result /*out*/, int core_id, * different log function than EM internal log is needed. * */ -void -core_log_fn_set(em_log_func_t func); +void core_log_fn_set(em_log_func_t func); /** * Set EM core local log function with va_list. diff --git a/src/em_mem.h b/src/em_mem.h index 2e5b053f..3b2d6fba 100644 --- a/src/em_mem.h +++ b/src/em_mem.h @@ -59,8 +59,6 @@ typedef struct { em_vlog_func_t vlog_fn; /** EM configuration as given to em_init() */ em_conf_t conf ENV_CACHE_LINE_ALIGNED; - /** Initialization state data */ - init_t init ENV_CACHE_LINE_ALIGNED; /** EM config file options */ opt_t opt ENV_CACHE_LINE_ALIGNED; /** Mapping between physical core id <-> EM core id */ diff --git a/src/em_queue.c b/src/em_queue.c index 33eeefdc..1b25daee 100644 --- a/src/em_queue.c +++ b/src/em_queue.c @@ -920,8 +920,9 @@ queue_setup_scheduled(queue_elem_t *q_elem /*in,out*/, * Set up a scheduled ODP queue for the EM scheduled queue */ odp_queue_param_t odp_queue_param; - odp_schedule_sync_t odp_schedule_sync; - odp_schedule_prio_t odp_prio; + /* Default values. Always changed unless error: */ + odp_schedule_sync_t odp_schedule_sync = ODP_SCHED_SYNC_PARALLEL; + odp_schedule_prio_t odp_prio = odp_schedule_min_prio(); /* Init odp queue params to default values */ odp_queue_param_init(&odp_queue_param); @@ -1281,14 +1282,12 @@ em_status_t queue_state_change_all(eo_elem_t *const eo_elem, queue_state_t new_state) { em_status_t err = EM_OK; - queue_elem_t *q_elem; + queue_elem_t *q_elem = NULL; list_node_t *pos; const list_node_t *list_node; /* - * Loop through all queues associated with the EO, no need for - * eo_elem-lock since this is called only on single core at the - * end of em_eo_start() + * Loop through all queues associated with the EO */ env_spinlock_lock(&eo_elem->lock); @@ -1301,9 +1300,15 @@ queue_state_change_all(eo_elem_t *const eo_elem, queue_state_t new_state) env_spinlock_unlock(&eo_elem->lock); - RETURN_ERROR_IF(err != EM_OK, err, EM_ESCOPE_QUEUE_STATE_CHANGE, - "EM-Q:%" PRI_QUEUE " inv. state: %d=>%d", - q_elem->queue, q_elem->state, new_state); + if (unlikely(err != EM_OK)) { + uint32_t queue_u32 = q_elem ? q_elem->queue : 0; + queue_state_t state = q_elem ? q_elem->state : EM_QUEUE_STATE_INVALID; + + return INTERNAL_ERROR(err, EM_ESCOPE_QUEUE_STATE_CHANGE, + "EM-Q:%" PRIx32 " inv. state: %d=>%d", + queue_u32, state, new_state); + } + return EM_OK; } diff --git a/src/event_machine_helper.c b/src/event_machine_helper.c index fab3537c..f1631251 100644 --- a/src/event_machine_helper.c +++ b/src/event_machine_helper.c @@ -92,6 +92,16 @@ em_error_format_string(char *str, size_t size, em_eo_t eo, em_status_t error, return MIN((int64_t)size, ret + 1); } +void em_version_print(void) +{ + print_version_info(); +} + +void em_info_print(void) +{ + print_em_info(); +} + int em_core_id_get_physical(int em_core_id) { diff --git a/src/event_machine_init.c b/src/event_machine_init.c index 9ddb54c4..7da717f2 100644 --- a/src/event_machine_init.c +++ b/src/event_machine_init.c @@ -120,8 +120,6 @@ em_status_t em_init(const em_conf_t *conf) sizeof(em_shm->conf.api_hooks)); } - env_spinlock_init(&em_shm->init.lock); - /* Initialize the log & error handling */ log_init(); error_init(); @@ -154,10 +152,10 @@ em_status_t em_init(const em_conf_t *conf) * Masks must be a subset of logical EM core mask. Zero mask means * that input_poll_fn and output_drain_fn are run on all EM cores. */ - stat = input_poll_init(&em_shm->core_map.logic_mask, conf); + stat = input_poll_check(&em_shm->core_map.logic_mask, conf); RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, EM_ESCOPE_INIT, "input_poll_init() failed:%" PRI_STAT "", stat); - stat = output_drain_init(&em_shm->core_map.logic_mask, conf); + stat = output_drain_check(&em_shm->core_map.logic_mask, conf); RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, EM_ESCOPE_INIT, "output_drain_init() failed:%" PRI_STAT "", stat); @@ -238,6 +236,11 @@ em_status_t em_init(const em_conf_t *conf) RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, EM_ESCOPE_INIT, "emcli_init() failed:%" PRI_STAT "", stat); + /* + * Print EM and ODP version information + */ + print_version_info(); + return EM_OK; } @@ -247,7 +250,6 @@ em_status_t em_init_core(void) odp_shm_t shm; em_shm_t *shm_addr; em_status_t stat; - int init_count; /* Lookup the EM shared memory on each EM-core */ shm = odp_shm_lookup("em_shm"); @@ -280,14 +282,12 @@ em_status_t em_init_core(void) "dispatch_init_local() failed:%" PRI_STAT "", stat); /* Check if input_poll_fn should be executed on this core */ - stat = input_poll_init_local(&locm->do_input_poll, - locm->core_id, &em_shm->conf); + stat = input_poll_init_local(); RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, EM_ESCOPE_INIT_CORE, "input_poll_init_local() failed:%" PRI_STAT "", stat); /* Check if output_drain_fn should be executed on this core */ - stat = output_drain_init_local(&locm->do_output_drain, - locm->core_id, &em_shm->conf); + stat = output_drain_init_local(); RETURN_ERROR_IF(stat != EM_OK, EM_ERR_LIB_FAILED, EM_ESCOPE_INIT_CORE, "output_drain_init_local() failed:%" PRI_STAT "", stat); @@ -320,19 +320,8 @@ em_status_t em_init_core(void) for (int i = 0; i < EM_DEBUG_TSP_LAST; i++) locm->debug_ts[i] = 1; - env_spinlock_lock(&em_shm->init.lock); - init_count = ++em_shm->init.em_init_core_cnt; - env_spinlock_unlock(&em_shm->init.lock); - /* Now OK to call EM APIs */ - /* Print info about the Env&HW when the last core has initialized */ - if (init_count == em_core_count()) { - print_em_info(); - /* Last */ - em_shm->init.em_init_done = 1; - } - env_sync_mem(); return EM_OK; diff --git a/src/event_machine_timer.c b/src/event_machine_timer.c index a2bd2cea..6bda48a7 100644 --- a/src/event_machine_timer.c +++ b/src/event_machine_timer.c @@ -1753,23 +1753,26 @@ em_status_t em_tmo_ack(em_tmo_t tmo, em_event_t next_tmo_ev) int em_timer_get_all(em_timer_t *tmr_list, int max) { - if (EM_CHECK_LEVEL > 0 && unlikely(tmr_list == NULL || max < 1)) - return 0; + odp_ticketlock_lock(&em_shm->timers.timer_lock); - int num = 0; + const uint32_t num_timers = em_shm->timers.num_timers; - odp_ticketlock_lock(&em_shm->timers.timer_lock); - for (int i = 0; i < EM_ODP_MAX_TIMERS; i++) { - if (em_shm->timers.timer[i].odp_tmr_pool != ODP_TIMER_POOL_INVALID) { - tmr_list[num] = TMR_I2H(i); - num++; - if (num >= max) - break; + if (tmr_list && max > 0 && num_timers > 0) { + int num = 0; + + for (int i = 0; i < EM_ODP_MAX_TIMERS; i++) { + if (em_shm->timers.timer[i].odp_tmr_pool != ODP_TIMER_POOL_INVALID) { + tmr_list[num] = TMR_I2H(i); + num++; + if (num >= max) + break; + } } } + odp_ticketlock_unlock(&em_shm->timers.timer_lock); - return num; + return num_timers; } em_status_t em_timer_get_attr(em_timer_t tmr, em_timer_attr_t *tmr_attr)