LCOV - code coverage report
Current view: top level - core/test - test.c Hit Total Coverage
Test: ROOT-Sim master Documentation Coverage Lines: 13 15 86.7 %
Date: 2021-03-25 15:11:55

          Line data    Source code
       1           1 : /**
       2             :  * @file test/test.c
       3             :  *
       4             :  * @brief Test framework source
       5             :  *
       6             :  * The source of the minimal test framework used in the code base tests
       7             :  *
       8             :  * SPDX-FileCopyrightText: 2008-2021 HPDCS Group <rootsim@googlegroups.com>
       9             :  * SPDX-License-Identifier: GPL-3.0-only
      10             :  */
      11             : #include <test.h>
      12             : 
      13             : #include <arch/thread.h>
      14             : 
      15             : #include <limits.h>
      16             : #include <memory.h>
      17             : #include <stdarg.h>
      18             : #include <stdatomic.h>
      19             : #include <stdbool.h>
      20             : #include <stdlib.h>
      21             : 
      22             : #ifndef ROOTSIM_TEST_NAME
      23           0 : #define ROOTSIM_TEST_NAME "rs_test"
      24             : #endif
      25             : 
      26             : #ifdef ROOTSIM_MPI
      27           1 : __attribute__((weak)) nid_t nid;
      28           1 : __attribute__((weak)) nid_t n_nodes = 1;
      29             : #endif
      30           1 : __attribute__((weak)) lp_id_t n_lps;
      31           1 : __attribute__((weak)) rid_t n_threads;
      32           1 : __attribute__((weak)) __thread rid_t rid;
      33           1 : __attribute__((weak)) int log_level;
      34             : 
      35           0 : static char **test_argv;
      36             : 
      37             : __attribute__((weak))
      38           1 : void _log_log(int level, const char *file, unsigned line, const char *fmt, ...)
      39             : {
      40             :         (void) level;
      41             :         (void) file;
      42             :         (void) line;
      43             :         (void) fmt;
      44             : }
      45             : 
      46           1 : int main(int argc, char **argv);
      47             : 
      48             : /**
      49             :  * @brief Initializes ISO C compliant argc and argv from the test configuration
      50             :  * @param argc_p a pointer to a variable which will hold the computed argc value
      51             :  * @param argv_p a pointer to a variable which will hold the computer argv value
      52             :  * @return 0 in case of success, -1 in case of failure
      53             :  */
      54           1 : static int init_arguments(int *argc_p, char ***argv_p)
      55             : {
      56             :         int argc = 0;
      57             :         if (test_config.test_arguments) {
      58             :                 while (test_config.test_arguments[argc]) {
      59             :                         ++argc;
      60             :                 }
      61             :         }
      62             :         ++argc;
      63             : 
      64             :         char **argv = malloc(sizeof(*argv) * (argc + 1));
      65             :         if(argv == NULL)
      66             :                 return -1;
      67             : 
      68             :         argv[0] = ROOTSIM_TEST_NAME;
      69             : 
      70             :         if (test_config.test_arguments) {
      71             :                 memcpy(&argv[1], test_config.test_arguments,
      72             :                        sizeof(*argv) * argc);
      73             :         } else {
      74             :                 argv[1] = NULL;
      75             :         }
      76             : 
      77             :         *argc_p = argc;
      78             :         *argv_p = argv;
      79             :         return 0;
      80             : }
      81             : 
      82             : /**
      83             :  * @brief The exit handler, to exit cleanly even in case of errors
      84             :  */
      85           1 : static void test_atexit(void)
      86             : {
      87             :         free(test_argv);
      88             : }
      89             : 
      90             : /**
      91             :  * @brief The test wrapper which allows to intervene before the actual main()
      92             :  */
      93             : __attribute__((constructor))
      94           1 : void main_wrapper(void)
      95             : {
      96             :         int test_argc = 0;
      97             : 
      98             :         puts("Starting " ROOTSIM_TEST_NAME " test");
      99             : 
     100             :         n_threads = test_config.threads_count;
     101             : 
     102             :         atexit(test_atexit);
     103             : 
     104             :         if (init_arguments(&test_argc, &test_argv) == -1)
     105             :                 exit(TEST_BAD_FAIL_EXIT_CODE);
     106             : 
     107             :         int test_ret = main(test_argc, test_argv);
     108             :         if (!test_ret)
     109             :                 puts("Successfully run " ROOTSIM_TEST_NAME " test");
     110             : 
     111             :         exit(test_ret);
     112             : }
     113             : 
     114             : /**
     115             :  * @brief Synchronizes threads on a barrier
     116             :  * @return true if this thread has been elected as leader, false otherwise
     117             :  *
     118             :  * This is a more battle tested although worse performing version of the thread
     119             :  * barrier. We can't rely on the pthread barrier because it's not portable.
     120             :  */
     121           1 : bool test_thread_barrier(void)
     122             : {
     123             :         static atomic_uint b_in, b_out, b_cr;
     124             : 
     125             :         unsigned i;
     126             :         unsigned count = test_config.threads_count;
     127             :         unsigned max_in_before_reset = (UINT_MAX / 2) - (UINT_MAX / 2) % count;
     128             :         do {
     129             :                 i = atomic_fetch_add_explicit(
     130             :                                 &b_in, 1U, memory_order_acq_rel) + 1;
     131             :         } while (__builtin_expect(i > max_in_before_reset, 0));
     132             : 
     133             :         unsigned cr = atomic_load_explicit(&b_cr, memory_order_relaxed);
     134             : 
     135             :         bool leader = i == cr + count;
     136             :         if (leader)
     137             :                 atomic_store_explicit(&b_cr, cr + count, memory_order_release);
     138             :         else
     139             :                 while (i > cr)
     140             :                         cr = atomic_load_explicit(&b_cr, memory_order_relaxed);
     141             : 
     142             :         atomic_thread_fence(memory_order_acquire);
     143             : 
     144             :         unsigned o = atomic_fetch_add_explicit(&b_out, 1,
     145             :                         memory_order_release) + 1;
     146             :         if (__builtin_expect(o == max_in_before_reset, 0)) {
     147             :                 atomic_thread_fence(memory_order_acquire);
     148             :                 atomic_store_explicit(&b_cr, 0, memory_order_relaxed);
     149             :                 atomic_store_explicit(&b_out, 0, memory_order_relaxed);
     150             :                 atomic_store_explicit(&b_in, 0, memory_order_release);
     151             :         }
     152             :         return leader;
     153             : }

Generated by: LCOV version 1.14