diff --git a/CMakeLists.txt b/CMakeLists.txt index edf4f524..1a70b947 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,9 +47,11 @@ endif() add_subdirectory(src) -# Run the tests -enable_testing() -add_subdirectory(test) +if(NOT IMPORT_AS_LIB) + # Run the tests + enable_testing() + add_subdirectory(test) -# Generate and inspect documentation -add_subdirectory(docs) + # Generate and inspect documentation + add_subdirectory(docs) +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6c659545..b434e90a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,7 +8,7 @@ set(rscore_srcs init.c core/sync.c datatypes/msg_queue.c - distributed/control_msg.c + core/control_msg.c gvt/fossil.c gvt/gvt.c gvt/termination.c @@ -35,7 +35,7 @@ endif() add_library(rscore STATIC ${rscore_srcs}) target_compile_definitions(rscore PRIVATE ROOTSIM_VERSION="${PROJECT_VERSION}") -target_include_directories(rscore PRIVATE .) +target_include_directories(rscore PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include/) target_link_libraries(rscore ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBS}) if(NOT DISABLE_MPI) @@ -44,5 +44,7 @@ if(NOT DISABLE_MPI) target_link_libraries(rscore ${MPI_C_LIBRARIES}) endif() -install(FILES ROOT-Sim.h DESTINATION include) -install(TARGETS rscore LIBRARY DESTINATION lib) +if(NOT IMPORT_AS_LIB) + install(DIRECTORY include/ DESTINATION include) + install(TARGETS rscore LIBRARY DESTINATION lib) +endif() diff --git a/src/core/control_msg.c b/src/core/control_msg.c new file mode 100644 index 00000000..bc0ca241 --- /dev/null +++ b/src/core/control_msg.c @@ -0,0 +1,135 @@ +/** + * @file core/control_msg.c + * + * @brief MPI remote control messages module + * + * The module in which remote control messages are wired to the other modules + * + * SPDX-FileCopyrightText: 2008-2023 HPDCS Group + * SPDX-License-Identifier: GPL-3.0-only + */ +#include "include/ROOT-Sim/sdk.h" +#include "control_msg.h" +#include "distributed/mpi.h" + +/// This structure is used to store the handlers for the control messages +struct library_handler { + /// The control message id + unsigned control_msg_id; + /// The handler for the control message + control_msg_handler_t handler; +}; + +/// The array of handlers for the control messages +static struct library_handler *library_handlers = NULL; +/// The capacity of the array of handlers for the control messages +static size_t library_handlers_capacity = 0; +/// The current number of used slots in the array of handlers for the control messages +static size_t library_handlers_size = 0; +/// The next control message ID +static int next_control_msg_id = FIRST_LIBRARY_CONTROL_MSG_ID; + +/** + * @brief Initialize the control message module + */ +void control_msg_init(void) +{ + if(library_handlers != NULL) { + logger(LOG_WARN, "Trying to reinitialize control message module, ignoring!"); + return; + } + + size_t size = INITIAL_HANDLERS_CAPACITY * sizeof(*library_handlers); + void *ptr = malloc(size); + if (ptr != NULL) { + library_handlers_capacity = INITIAL_HANDLERS_CAPACITY; + library_handlers = ptr; + } else { + logger(LOG_FATAL, "Error initializing control message module!"); + abort(); + } +} + +/** + * @brief Finalize the control message module + */ +void control_msg_fini(void) +{ + if(library_handlers != NULL) { + free(library_handlers); + library_handlers = NULL; + } +} + +int control_msg_register_handler(control_msg_handler_t handler) +{ + if (library_handlers_size >= library_handlers_capacity) { + size_t new_capacity = library_handlers_capacity * 2; + struct library_handler *new_handlers = realloc(library_handlers, new_capacity * sizeof(*new_handlers)); + if (new_handlers == NULL) { + logger(LOG_FATAL, "Error registering external library handler!"); + abort(); + } + library_handlers = new_handlers; + library_handlers_capacity = new_capacity; + } + + int ret = next_control_msg_id++; + library_handlers[library_handlers_size].control_msg_id = ret; + library_handlers[library_handlers_size].handler = handler; + library_handlers_size++; + return ret; +} + + +/** + * @brief Invoke a library handler + * @param code the control message ID + * @param payload the payload of the control message + */ +void invoke_library_handler(unsigned code, const void *payload) +{ + for (size_t i = 0; i < library_handlers_size; i++) { + if (library_handlers[i].control_msg_id == code) { + library_handlers[i].handler(code, payload); + return; + } + } + logger(LOG_FATAL, "No library handler registered for code %u", code); + abort(); +} + + +/** + * @brief Handle a received control message + * @param ctrl the tag of the received control message + */ +void control_msg_process(enum platform_ctrl_msg_code ctrl) +{ + switch(ctrl) { + case MSG_CTRL_GVT_START: + gvt_start_processing(); + break; + case MSG_CTRL_GVT_DONE: + gvt_on_done_ctrl_msg(); + break; + case MSG_CTRL_TERMINATION: + termination_on_ctrl_msg(); + break; + default: +#ifndef NDEBUG + logger(LOG_WARN, "Unknown control message code %d", ctrl); +#else + __builtin_unreachable(); +#endif + } +} + +void control_msg_broadcast(unsigned ctrl, const void *payload, size_t size) +{ + if(global_config.serial || (n_nodes == 1)) { + invoke_library_handler(ctrl, payload); + } else { + mpi_library_control_msg_broadcast(ctrl, payload, size); + } +} diff --git a/src/core/control_msg.h b/src/core/control_msg.h new file mode 100644 index 00000000..a7fa3123 --- /dev/null +++ b/src/core/control_msg.h @@ -0,0 +1,49 @@ +/** + * @file core/control_msg.h + * + * @brief MPI remote control messages header + * + * The module in which remote control messages are wired to the other modules + * + * SPDX-FileCopyrightText: 2008-2023 HPDCS Group + * SPDX-License-Identifier: GPL-3.0-only + */ +#pragma once + +#include "lp/msg.h" +#include "gvt/gvt.h" +#include "gvt/termination.h" +#include "include/ROOT-Sim/sdk.h" + +/// The initial size of the handlers dynamic vector +#define INITIAL_HANDLERS_CAPACITY 4 +/// The first control message ID that will be returned to the external libraries +#define FIRST_LIBRARY_CONTROL_MSG_ID 0 + +/// The size of the maximum payload of a control message +#define CONTROL_MSG_PAYLOAD_SIZE 16 + +/// A control message MPI tag value +enum platform_ctrl_msg_code { + /// Used by the master to start a new gvt reduction operation + MSG_CTRL_GVT_START = 1, + /// Used by slaves to signal their completion of the gvt protocol + MSG_CTRL_GVT_DONE, + /// Used in broadcast to signal that local LPs can terminate + MSG_CTRL_TERMINATION +}; + +/// A control message that can be user by higher-level libraries to synchronize actions +/* cppcheck-suppress misra-c2012-2.4 + * The payload is anything used specified, and the size is checked in the code */ +struct library_ctrl_msg { + /// The control message code + unsigned ctrl_code; + /// The payload of the control message + unsigned char payload[CONTROL_MSG_PAYLOAD_SIZE]; +}; + +extern void control_msg_init(void); +extern void control_msg_fini(void); +extern void control_msg_process(enum platform_ctrl_msg_code ctrl); +extern void invoke_library_handler(unsigned code, const void *payload); diff --git a/src/distributed/control_msg.c b/src/distributed/control_msg.c deleted file mode 100644 index 5b285320..00000000 --- a/src/distributed/control_msg.c +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @file distributed/control_msg.c - * - * @brief MPI remote control messages module - * - * The module in which remote control messages are wired to the other modules - * - * SPDX-FileCopyrightText: 2008-2023 HPDCS Group - * SPDX-License-Identifier: GPL-3.0-only - */ -#include - -/** - * @brief Handle a received control message - * @param ctrl the tag of the received control message - */ -void control_msg_process(enum msg_ctrl_code ctrl) -{ - switch(ctrl) { - case MSG_CTRL_GVT_START: - gvt_start_processing(); - break; - case MSG_CTRL_GVT_DONE: - gvt_on_done_ctrl_msg(); - break; - case MSG_CTRL_TERMINATION: - termination_on_ctrl_msg(); - break; - default: - __builtin_unreachable(); - } -} diff --git a/src/distributed/control_msg.h b/src/distributed/control_msg.h deleted file mode 100644 index a7796cbf..00000000 --- a/src/distributed/control_msg.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @file distributed/control_msg.h - * - * @brief MPI remote control messages header - * - * The module in which remote control messages are wired to the other modules - * - * SPDX-FileCopyrightText: 2008-2023 HPDCS Group - * SPDX-License-Identifier: GPL-3.0-only - */ -#pragma once - -#include -#include - -/// A control message MPI tag value -enum msg_ctrl_code { - /// Used by the master to start a new gvt reduction operation - MSG_CTRL_GVT_START = 1, - /// Used by slaves to signal their completion of the gvt protocol - MSG_CTRL_GVT_DONE, - /// Used in broadcast to signal that local LPs can terminate - MSG_CTRL_TERMINATION -}; - -extern void control_msg_process(enum msg_ctrl_code ctrl); diff --git a/src/distributed/mpi.c b/src/distributed/mpi.c index 8c1f4e0b..40ca7f41 100644 --- a/src/distributed/mpi.c +++ b/src/distributed/mpi.c @@ -9,6 +9,8 @@ * SPDX-FileCopyrightText: 2008-2023 HPDCS Group * SPDX-License-Identifier: GPL-3.0-only */ +#include + #include #include @@ -17,16 +19,16 @@ #include -enum { - RS_MSG_TAG = 0, - RS_DATA_TAG +enum { RS_MSG_TAG = 0, + RS_DATA_TAG, + RS_CTRL_TAG }; /// Array of control codes values to be able to get their address for MPI_Send() -static const enum msg_ctrl_code ctrl_msgs[] = { - [MSG_CTRL_GVT_START] = MSG_CTRL_GVT_START, - [MSG_CTRL_GVT_DONE] = MSG_CTRL_GVT_DONE, - [MSG_CTRL_TERMINATION] = MSG_CTRL_TERMINATION +static const enum platform_ctrl_msg_code ctrl_msgs[] = { + [MSG_CTRL_GVT_START] = MSG_CTRL_GVT_START, + [MSG_CTRL_GVT_DONE] = MSG_CTRL_GVT_DONE, + [MSG_CTRL_TERMINATION] = MSG_CTRL_TERMINATION }; /// The MPI request associated with the non blocking scatter gather collective @@ -136,11 +138,37 @@ void mpi_remote_anti_msg_send(struct lp_msg *msg, nid_t dest_nid) MPI_Request_free(&req); } + +/** + * @brief Sends a library control message to all the nodes, including self + * @param ctrl the control message to send + * @param payload the payload to send with the message + * @param size the size of the payload + */ +void mpi_library_control_msg_broadcast(unsigned ctrl, const void *payload, size_t size) +{ + nid_t i = n_nodes; + struct library_ctrl_msg msg = {.ctrl_code = ctrl, {0}}; + if(unlikely(payload != NULL)) { + if(unlikely(size >= CONTROL_MSG_PAYLOAD_SIZE)) { + logger(LOG_FATAL, "Payload too big for a library control message"); + abort(); + } + memcpy(&msg.payload, payload, size); + } + + while(i--) { + MPI_Request req; + MPI_Isend(&msg, sizeof(msg), MPI_BYTE, i, RS_CTRL_TAG, MPI_COMM_WORLD, &req); + MPI_Request_free(&req); + } +} + /** * @brief Sends a platform control message to all the nodes, including self * @param ctrl the control message to send */ -void mpi_control_msg_broadcast(enum msg_ctrl_code ctrl) +void mpi_control_msg_broadcast(enum platform_ctrl_msg_code ctrl) { nid_t i = n_nodes; while(i--) { @@ -153,7 +181,7 @@ void mpi_control_msg_broadcast(enum msg_ctrl_code ctrl) * @param ctrl the control message to send * @param dest the id of the destination node */ -void mpi_control_msg_send_to(enum msg_ctrl_code ctrl, nid_t dest) +void mpi_control_msg_send_to(enum platform_ctrl_msg_code ctrl, nid_t dest) { MPI_Request req; MPI_Isend(&ctrl_msgs[ctrl], sizeof(*ctrl_msgs), MPI_BYTE, dest, RS_MSG_TAG, MPI_COMM_WORLD, &req); @@ -165,18 +193,27 @@ void mpi_control_msg_send_to(enum msg_ctrl_code ctrl, nid_t dest) * each one of them. * * This routine checks, using the MPI probing mechanism, for new remote messages and it handles them accordingly. - * Control messages are handled by the respective platform handler. Simulation messages are unpacked and put in the - * queue. Anti-messages are matched and accordingly processed by the message map. + * Control messages are handled by the respective platform handler or library handler. Simulation messages are unpacked + * and put in the queue. Anti-messages are matched and accordingly processed by the message map. */ void mpi_remote_msg_handle(void) { - while(1) { - int pending; - MPI_Message mpi_msg; - MPI_Status status; + int pending; + MPI_Message mpi_msg; + MPI_Status status; - MPI_Improbe(MPI_ANY_SOURCE, RS_MSG_TAG, MPI_COMM_WORLD, &pending, &mpi_msg, &status); + while(true) { + MPI_Improbe(MPI_ANY_SOURCE, RS_CTRL_TAG, MPI_COMM_WORLD, &pending, &mpi_msg, &status); + if(likely(!pending)) + break; + + struct library_ctrl_msg ctrl_msg; + MPI_Mrecv(&ctrl_msg, sizeof(ctrl_msg), MPI_BYTE, &mpi_msg, MPI_STATUS_IGNORE); + invoke_library_handler(ctrl_msg.ctrl_code, &ctrl_msg.payload); + } + while(true) { + MPI_Improbe(MPI_ANY_SOURCE, RS_MSG_TAG, MPI_COMM_WORLD, &pending, &mpi_msg, &status); if(!pending) return; @@ -184,8 +221,8 @@ void mpi_remote_msg_handle(void) MPI_Get_count(&status, MPI_BYTE, &size); struct lp_msg *msg; if(unlikely(size <= (int)msg_remote_anti_size())) { - if(unlikely(size == sizeof(enum msg_ctrl_code))) { - enum msg_ctrl_code c; + if(unlikely(size == sizeof(enum platform_ctrl_msg_code))) { + enum platform_ctrl_msg_code c; MPI_Mrecv(&c, sizeof(c), MPI_BYTE, &mpi_msg, MPI_STATUS_IGNORE); control_msg_process(c); continue; @@ -215,14 +252,23 @@ void mpi_remote_msg_handle(void) */ void mpi_remote_msg_drain(void) { + int pending; + MPI_Message mpi_msg; + MPI_Status status; struct lp_msg *msg = NULL; int msg_size = 0; - while(1) { - int pending; - MPI_Message mpi_msg; - MPI_Status status; + while(true) { + MPI_Improbe(MPI_ANY_SOURCE, RS_CTRL_TAG, MPI_COMM_WORLD, &pending, &mpi_msg, &status); + if(likely(!pending)) + break; + + struct library_ctrl_msg ctrl_msg; + MPI_Mrecv(&ctrl_msg, sizeof(ctrl_msg), MPI_BYTE, &mpi_msg, MPI_STATUS_IGNORE); + invoke_library_handler(ctrl_msg.ctrl_code, &ctrl_msg.payload); + } + while(true) { MPI_Improbe(MPI_ANY_SOURCE, RS_MSG_TAG, MPI_COMM_WORLD, &pending, &mpi_msg, &status); if(!pending) @@ -231,8 +277,8 @@ void mpi_remote_msg_drain(void) int size; MPI_Get_count(&status, MPI_BYTE, &size); - if(unlikely(size == sizeof(enum msg_ctrl_code))) { - enum msg_ctrl_code c; + if(unlikely(size == sizeof(enum platform_ctrl_msg_code))) { + enum platform_ctrl_msg_code c; MPI_Mrecv(&c, sizeof(c), MPI_BYTE, &mpi_msg, MPI_STATUS_IGNORE); control_msg_process(c); continue; diff --git a/src/distributed/mpi.h b/src/distributed/mpi.h index 660a6638..86bcf82d 100644 --- a/src/distributed/mpi.h +++ b/src/distributed/mpi.h @@ -15,7 +15,7 @@ */ #pragma once -#include +#include "core/control_msg.h" #include extern void mpi_global_init(int *argc_p, char ***argv_p); @@ -24,8 +24,9 @@ extern void mpi_global_fini(void); extern void mpi_remote_msg_send(struct lp_msg *msg, nid_t dest_nid); extern void mpi_remote_anti_msg_send(struct lp_msg *msg, nid_t dest_nid); -extern void mpi_control_msg_broadcast(enum msg_ctrl_code ctrl); -extern void mpi_control_msg_send_to(enum msg_ctrl_code ctrl, nid_t dest); +extern void mpi_library_control_msg_broadcast(unsigned ctrl, const void *payload, size_t size); +extern void mpi_control_msg_broadcast(enum platform_ctrl_msg_code ctrl); +extern void mpi_control_msg_send_to(enum platform_ctrl_msg_code ctrl, nid_t dest); extern void mpi_remote_msg_handle(void); extern void mpi_remote_msg_drain(void); diff --git a/src/ROOT-Sim.h b/src/include/ROOT-Sim.h similarity index 97% rename from src/ROOT-Sim.h rename to src/include/ROOT-Sim.h index 9b4c2503..01656333 100644 --- a/src/ROOT-Sim.h +++ b/src/include/ROOT-Sim.h @@ -99,8 +99,8 @@ enum log_level { LOG_INFO, //!< The logging level reserved to useful runtime messages LOG_WARN, //!< The logging level reserved to unexpected, non deal breaking conditions LOG_ERROR, //!< The logging level reserved to unexpected, problematic conditions - LOG_FATAL, //!< The logging level reserved to unexpected, fatal conditions - LOG_SILENT //!< Emit no message during the simulation + LOG_FATAL, //!< The logging level reserved to unexpected, fatal conditions + LOG_SILENT //!< Emit no message during the simulation }; /// A set of configurable values used by other modules diff --git a/src/include/ROOT-Sim/sdk.h b/src/include/ROOT-Sim/sdk.h new file mode 100644 index 00000000..f748c3ea --- /dev/null +++ b/src/include/ROOT-Sim/sdk.h @@ -0,0 +1,55 @@ +/** + * @file sdk.h + * + * @brief ROOT-Sim header for internal library development + * + * This header is intended to be used by ROOT-Sim library developers only. + * It defines all the symbols which are needed to develop a library to be + * used by simulation models. + * + * SPDX-FileCopyrightText: 2008-2022 HPDCS Group + * SPDX-License-Identifier: GPL-3.0-only + */ +#pragma once + +#include +#include + +/// The type of control message handlers that libraries can register +typedef void (*control_msg_handler_t)(unsigned ctrl_msg_id, const void *payload); + +/** + * @brief Register a new control message handler + * + * This function registers a control message handler for internal library use. + * When a handler is registered, a control message ID is automatically allocated + * and returned to the caller. + * The library function should then use that ID to send control messages to the + * various MPI ranks. The size of the payloads of such control messages is fixed. + * + * @param handler the handler to register + * @return the ID of the registered control message ID + */ +extern int control_msg_register_handler(control_msg_handler_t handler); + +/** + * @brief Send a control message to all simulation nodes. + * + * This function sends a control message to all nodes of the simulation. + * The corresponding handler must be registered first via control_msg_register_handler(). + * + * @param ctrl the control message ID, as returned by control_msg_register_handler() + * @param payload the payload of the control message, must be of size CONTROL_MSG_PAYLOAD_SIZE at most + * @param size the size of the payload + */ +extern void control_msg_broadcast(unsigned ctrl, const void *payload, size_t size); + + +extern void vlogger(enum log_level level, char *file, unsigned line, const char *fmt, ...); + +/** + * @brief Produce a log message + * @param level the logging level associated to the message + * @param ... the format string followed by its arguments if needed + */ +#define logger(level, ...) vlogger(level, __FILE__, __LINE__, __VA_ARGS__) diff --git a/src/init.c b/src/init.c index 8e63c61e..c82b87f4 100644 --- a/src/init.c +++ b/src/init.c @@ -11,12 +11,9 @@ #include #include #include -#include #include #include -#include - #include #include @@ -110,16 +107,28 @@ int RootsimInit(const struct simulation_configuration *conf) log_init(global_config.logfile); - if (global_config.serial) - global_config.n_threads = 1; - else if (global_config.n_threads == 0) - global_config.n_threads = thread_cores_count(); - if(global_config.termination_time == 0) global_config.termination_time = SIMTIME_MAX; + logger(LOG_INFO, "Initializing %s simulation", global_config.serial ? "serial" : "parallel"); + if(global_config.serial) { + global_config.n_threads = 1; + serial_simulation_init(); + } else { + if(global_config.n_threads == 0) { + global_config.n_threads = thread_cores_count(); + } + mpi_global_init(NULL, NULL); + parallel_global_init(); + } + configuration_done = true; + if(global_config.log_level < LOG_SILENT && !rid && !nid) { + print_logo(); + print_config(); + } + return 0; } @@ -138,14 +147,6 @@ int RootsimRun(void) if(!configuration_done) return -1; - if(!global_config.serial) - mpi_global_init(NULL, NULL); - - if(global_config.log_level < LOG_SILENT && !rid) { - print_logo(); - print_config(); - } - if(global_config.serial) { ret = serial_simulation(); } else { diff --git a/src/log/log.c b/src/log/log.c index 7ae3b447..22f49b29 100644 --- a/src/log/log.c +++ b/src/log/log.c @@ -11,9 +11,10 @@ #include #include +#include #include -#include #include +#include /// The file to write logging information to static FILE *logfile = NULL; diff --git a/src/log/log.h b/src/log/log.h index 76d5d5b2..b53917db 100644 --- a/src/log/log.h +++ b/src/log/log.h @@ -10,15 +10,6 @@ */ #pragma once -#include - -extern void vlogger(enum log_level level, char *file, unsigned line, const char *fmt, ...); - -/** - * @brief Produce a log message - * @param level the logging level associated to the message - * @param ... the format string followed by its arguments if needed - */ -#define logger(level, ...) vlogger(level, __FILE__, __LINE__, __VA_ARGS__) +#include extern void log_init(FILE *file); diff --git a/src/mm/buddy/multi.c b/src/mm/buddy/multi.c index 9ba3c96a..03a3e5f4 100644 --- a/src/mm/buddy/multi.c +++ b/src/mm/buddy/multi.c @@ -6,9 +6,9 @@ * SPDX-FileCopyrightText: 2008-2023 HPDCS Group * SPDX-License-Identifier: GPL-3.0-only */ -#include +#include -#include +#include #include #include #include diff --git a/src/parallel/parallel.c b/src/parallel/parallel.c index 0daedbbf..cece86b5 100644 --- a/src/parallel/parallel.c +++ b/src/parallel/parallel.c @@ -82,17 +82,19 @@ static thrd_ret_t THREAD_CALL_CONV parallel_thread_run(void *rid_arg) return THREAD_RET_SUCCESS; } -static void parallel_global_init(void) +void parallel_global_init(void) { stats_global_init(); lp_global_init(); msg_queue_global_init(); termination_global_init(); gvt_global_init(); + control_msg_init(); } static void parallel_global_fini(void) { + control_msg_fini(); msg_queue_global_fini(); lp_global_fini(); stats_global_fini(); @@ -100,8 +102,6 @@ static void parallel_global_fini(void) int parallel_simulation(void) { - logger(LOG_INFO, "Initializing parallel simulation"); - parallel_global_init(); stats_global_time_take(STATS_GLOBAL_INIT_END); thr_id_t thrs[global_config.n_threads]; diff --git a/src/parallel/parallel.h b/src/parallel/parallel.h index a17d0219..03deadd7 100644 --- a/src/parallel/parallel.h +++ b/src/parallel/parallel.h @@ -9,3 +9,4 @@ #pragma once extern int parallel_simulation(void); +extern void parallel_global_init(void); diff --git a/src/serial/serial.c b/src/serial/serial.c index fa012006..65b00f4a 100644 --- a/src/serial/serial.c +++ b/src/serial/serial.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -20,12 +21,13 @@ static heap_declare(struct lp_msg *) queue; /** * @brief Initialize the serial simulation environment */ -static void serial_simulation_init(void) +void serial_simulation_init(void) { stats_global_init(); stats_init(); msg_allocator_init(); heap_init(queue); + control_msg_init(); lps = mm_alloc(sizeof(*lps) * global_config.lps); memset(lps, 0, sizeof(*lps) * global_config.lps); @@ -71,6 +73,7 @@ static void serial_simulation_fini(void) mm_free(lps); + control_msg_fini(); heap_fini(queue); msg_allocator_fini(); stats_global_fini(); @@ -145,8 +148,6 @@ int serial_simulation(void) { int ret; - logger(LOG_INFO, "Initializing serial simulation"); - serial_simulation_init(); stats_global_time_take(STATS_GLOBAL_INIT_END); stats_global_time_take(STATS_GLOBAL_EVENTS_START); diff --git a/src/serial/serial.h b/src/serial/serial.h index 908eb105..8ae20508 100644 --- a/src/serial/serial.h +++ b/src/serial/serial.h @@ -10,6 +10,7 @@ #include +extern void serial_simulation_init(void); extern int serial_simulation(void); extern void ScheduleNewEvent_serial(lp_id_t receiver, simtime_t timestamp, unsigned event_type, const void *payload, unsigned payload_size); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a63bce6e..7fb3bc8c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,11 +6,11 @@ add_library(test_framework_lib STATIC framework/test.c framework/thread.c ) -target_include_directories(test_framework_lib PRIVATE ../src .) +target_include_directories(test_framework_lib PRIVATE ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/include ${CMAKE_CURRENT_SOURCE_DIR}) function(test_program name) add_executable(test_${name} ${ARGN}) - target_include_directories(test_${name} PRIVATE ../src .) + target_include_directories(test_${name} PRIVATE ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/include ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(test_${name} test_framework_lib rscore) # FIXME this doesn't need to be in all the tests add_test(NAME test_${name} COMMAND test_${name}) set_tests_properties(test_${name} PROPERTIES TIMEOUT 60) @@ -21,6 +21,11 @@ function(test_program_xf name) set_tests_properties(test_${name} PROPERTIES WILL_FAIL TRUE) endfunction() +function(test_program_mpi name) + test_program(${name} ${ARGN}) + set_property(TARGET test_${name} PROPERTY CROSSCOMPILING_EMULATOR "${MPIEXEC_EXECUTABLE};${MPIEXEC_NUMPROC_FLAG};2") +endfunction() + # Test framework tests test_program(self_main framework/self-tests/stubs.c framework/self-tests/main.c) test_program_xf(self_fail_assert framework/self-tests/stubs.c framework/self-tests/fail_assert.c) @@ -43,6 +48,9 @@ test_program(load tests/core/load.c) test_program(bitmap tests/datatypes/bitmap.c) test_program(mm tests/mm/buddy.c tests/mm/buddy_hard.c tests/mm/parallel.c tests/mm/main.c) test_program(termination tests/gvt/termination.c) +test_program(control_msg_serial tests/sdk/control_msg.c tests/sdk/serial.c) +test_program(control_msg_parallel tests/sdk/control_msg.c tests/sdk/parallel.c) +test_program_mpi(control_msg_distributed tests/sdk/control_msg.c tests/sdk/distributed.c) # Test the statistics subsystem test_program(stats tests/log/stats.c) @@ -61,4 +69,6 @@ test_program(sync tests/core/sync.c) # Integration tests test_program(correctness_serial tests/integration/correctness/serial.c tests/integration/correctness/application.c tests/integration/correctness/functions.c tests/integration/correctness/output_256.c) test_program(correctness_parallel tests/integration/correctness/parallel.c tests/integration/correctness/application.c tests/integration/correctness/functions.c tests/integration/correctness/output_256.c) +test_program_mpi(correctness_parallel_mpi tests/integration/correctness/parallel.c tests/integration/correctness/application.c tests/integration/correctness/functions.c tests/integration/correctness/output_256.c) test_program(phold tests/integration/phold.c) +test_program_mpi(phold_mpi tests/integration/phold.c) diff --git a/test/tests/integration/phold.c b/test/tests/integration/phold.c index f6a150ce..ff13bbf6 100644 --- a/test/tests/integration/phold.c +++ b/test/tests/integration/phold.c @@ -105,7 +105,7 @@ struct simulation_configuration conf = { .log_level = LOG_INFO, .stats_file = "phold", .ckpt_interval = 0, - .core_binding = true, + .core_binding = false, .serial = false, .dispatcher = ProcessEvent, .committed = CanEnd, diff --git a/test/tests/log/rootsim_stats_test.py b/test/tests/log/rootsim_stats_test.py index fe6f7962..d2d815df 100644 --- a/test/tests/log/rootsim_stats_test.py +++ b/test/tests/log/rootsim_stats_test.py @@ -77,7 +77,7 @@ def test_stats_file(base_name, expected): if __name__ == "__main__": rs_script_path, bin_folder = test_init() stats_regex = regex_get() - test_stats_file("empty_stats", ["NZ", "0", "1", "2", "0", "0", "0", "0", "0", "0", "0", "0.00", "0.00", "100.00", + test_stats_file("empty_stats", ["NZ", "0", "1", "2", "123", "0", "0", "0", "0", "0", "0", "0.00", "0.00", "100.00", "0", "0", "0", "0", "0.0", "0", "0.0", "0", "NZ"]) test_stats_file("single_gvt_stats", ["NZ", "0", "1", "2", "16", "0", "0", "0", "0", "0", "0", "0.00", "0.00", "100.00", "0", "0", "0", "0", "0.0", "1", "0.0", "NZ", "NZ"]) diff --git a/test/tests/log/stats.c b/test/tests/log/stats.c index 313e9cae..84eb9edb 100644 --- a/test/tests/log/stats.c +++ b/test/tests/log/stats.c @@ -87,8 +87,7 @@ int stats_measures_test(_unused void *arg) static void stats_subsystem_test(const char *name, test_fn thread_fn) { - conf.stats_file = name; - RootsimInit(&conf); + global_config.stats_file = name; stats_global_init(); test_parallel("Testing statistics module", thread_fn, NULL, N_THREADS); stats_global_fini(); @@ -96,6 +95,7 @@ static void stats_subsystem_test(const char *name, test_fn thread_fn) int main(void) { + RootsimInit(&conf); stats_subsystem_test("empty_stats", stats_empty_test); n_lps_node = 16; stats_subsystem_test("single_gvt_stats", stats_single_gvt_test); diff --git a/test/tests/old_tests/gvt/gvt_test.c b/test/tests/old_tests/gvt/gvt_test.c index 66b4f6de..0be50703 100644 --- a/test/tests/old_tests/gvt/gvt_test.c +++ b/test/tests/old_tests/gvt/gvt_test.c @@ -6,10 +6,10 @@ * SPDX-FileCopyrightText: 2008-2023 HPDCS Group * SPDX-License-Identifier: GPL-3.0-only */ -#include "test.h" +#include #include -#include "gvt/gvt.h" +#include #define N_THREADS 3 diff --git a/test/tests/sdk/control_msg.c b/test/tests/sdk/control_msg.c new file mode 100644 index 00000000..b40af109 --- /dev/null +++ b/test/tests/sdk/control_msg.c @@ -0,0 +1,71 @@ +/** + * @file test/tests/sdk/control_msg.c + * + * @brief Test: Higher-level control messages + * + * SPDX-FileCopyrightText: 2008-2022 HPDCS Group + * SPDX-License-Identifier: GPL-3.0-only + */ +#include + +#include +#include "core/control_msg.h" +#include + +#include +#include + +#include "control_msg.h" + +static long value = 1234L; + +static unsigned ctrl_msg_id1 = 0; +static unsigned ctrl_msg_id2 = 0; + +static unsigned short inv1 = 0; +static unsigned short inv2 = 0; + +#ifdef NDEBUG +#define UNUSED _unused +#else +#define UNUSED +#endif + + +void handler(unsigned ctrl_msg_id, UNUSED const void *payload) +{ + assert(*(const long *)payload == value); + + if(ctrl_msg_id == ctrl_msg_id1) { + inv1++; + } else if(ctrl_msg_id == ctrl_msg_id2) { + inv2++; + } else { + assert(false); + } +} + +int test_ctrl_msg(bool distributed) +{ + ctrl_msg_id1 = control_msg_register_handler(handler); + ctrl_msg_id2 = control_msg_register_handler(handler); + + assert(ctrl_msg_id1 == FIRST_LIBRARY_CONTROL_MSG_ID); + assert(ctrl_msg_id2 > FIRST_LIBRARY_CONTROL_MSG_ID); + + control_msg_broadcast(ctrl_msg_id1, &value, sizeof(value)); + control_msg_broadcast(ctrl_msg_id2, &value, sizeof(value)); + + if(distributed) { + mpi_remote_msg_handle(); + } + + assert(inv1 != 0); + assert(inv2 != 0); + + return inv1 != inv2; +} + +void ProcessEvent(_unused lp_id_t me, _unused simtime_t now, _unused unsigned event_type, _unused const void *content, + _unused unsigned size, _unused void *s) +{} diff --git a/test/tests/sdk/control_msg.h b/test/tests/sdk/control_msg.h new file mode 100644 index 00000000..0762e89b --- /dev/null +++ b/test/tests/sdk/control_msg.h @@ -0,0 +1,15 @@ +/** +* @file test/tests/sdk/control_msg.h +* +* @brief Test: Higher-level control messages +* +* SPDX-FileCopyrightText: 2008-2022 HPDCS Group +* SPDX-License-Identifier: GPL-3.0-only + */ +#pragma once + +#include + +extern int test_ctrl_msg(bool distributed); +extern void ProcessEvent(_unused lp_id_t me, _unused simtime_t now, _unused unsigned event_type, + _unused const void *content, _unused unsigned size, _unused void *s); diff --git a/test/tests/sdk/distributed.c b/test/tests/sdk/distributed.c new file mode 100644 index 00000000..98468157 --- /dev/null +++ b/test/tests/sdk/distributed.c @@ -0,0 +1,29 @@ +/** + * @file test/tests/sdk/distributed.c + * + * @brief Test: Higher-level control messages (MPI test) + * + * SPDX-FileCopyrightText: 2008-2022 HPDCS Group + * SPDX-License-Identifier: GPL-3.0-only + */ +#include + +#include + +#include "control_msg.h" + +struct simulation_configuration conf = { + .lps = 16, + .n_threads = 1, + .serial = false, + .dispatcher = (ProcessEvent_t)1, + .committed = (CanEnd_t)1, +}; + +int main(void) +{ + RootsimInit(&conf); + int ret = test_ctrl_msg(true); + mpi_global_fini(); + return ret; +} diff --git a/test/tests/sdk/parallel.c b/test/tests/sdk/parallel.c new file mode 100644 index 00000000..5f474b08 --- /dev/null +++ b/test/tests/sdk/parallel.c @@ -0,0 +1,25 @@ +/** +* @file test/tests/sdk/parallel.c +* +* @brief Test: Higher-level control messages (parallel test) +* +* SPDX-FileCopyrightText: 2008-2022 HPDCS Group +* SPDX-License-Identifier: GPL-3.0-only +*/ +#include + +#include "control_msg.h" + +struct simulation_configuration conf = { + .lps = 16, + .n_threads = 0, + .serial = false, + .dispatcher = (ProcessEvent_t)1, + .committed = (CanEnd_t)1, +}; + +int main(void) +{ + RootsimInit(&conf); + return test_ctrl_msg(false); +} diff --git a/test/tests/sdk/serial.c b/test/tests/sdk/serial.c new file mode 100644 index 00000000..28532a3e --- /dev/null +++ b/test/tests/sdk/serial.c @@ -0,0 +1,25 @@ +/** +* @file test/tests/sdk/distributed.c +* +* @brief Test: Higher-level control messages (sequential test) +* +* SPDX-FileCopyrightText: 2008-2022 HPDCS Group +* SPDX-License-Identifier: GPL-3.0-only +*/ +#include + +#include "control_msg.h" + +struct simulation_configuration conf = { + .lps = 16, + .n_threads = 0, + .serial = true, + .dispatcher = (ProcessEvent_t)ProcessEvent, + .committed = (CanEnd_t)1, +}; + +int main(void) +{ + RootsimInit(&conf); + return test_ctrl_msg(false); +}