summaryrefslogblamecommitdiffstats
path: root/testsuites/smptests/smplock01/init.c
blob: 2defa2b5c080f0dd8b5448035f462c6e47db0dc9 (plain) (tree)
1
2
3
4
5

                                           
  
                                                         
  



















                                                                              


                    
                   

      
                                
                                   
                                   
                            



                    

                                           



                       
                     
 
                
                                   

                          
                                    
                                                                


                                                                    


                            
                                                                         

                                            
               

                                     



                                                        
                                     

                                           

  
                                         
 
                                            

 




                                    
 
                         

 

                                                           

                      


                           


                       
 
                                         
                        

















                                        
 




                                                
 
                                        

                                                      
 


                         

                

                   
                     


         


                                            
                       
       
    



                                                                              
 

                        



                                    

 

                                            
                            
                                
 
                                                     

                                                 


              












                                                                       


                    


                  


                        



                                    

 

                                            
                            

                                    
                                                     




                                                                          












                                                                       


                    


                  


                        



                                    

 

                                            
                            
                                
 
                                                     
                                                 
                         
                                                 


              












                                                                       


                     


                  

 
                        



                                    

 

                                            


                                    
                                                     





                                                                          












                                                                       


                     


                  


                        



                                    

 

                                            
                            
                        
                                
 
                                       
 
                                                     

                                            


              

                           












                                                                       


                    


                  

 
                        



                                    

 

                                            









                                              
                                                     







                                                        












                                                                       


                    


                  


                        



                                    

 

                                            
                            
                        
                                
 
                                       
 
                                                     
                                            



                                                                     
                                            


              

                           












                                                                       


                     


                  

 
                        



                                    

 

                                            









                                              
                                                     











                                                                     












                                                                       


                     


                  

 








                                    
                        



                                    

 

                                            
                            
                                
 
                                                     
                                                 
                   
                                                 


              












                                                                       


                  


                  

 
                        



                                    

 

                                            


                                    
                                                     





                                                                          












                                                                       


                


                  

 
                         



                                    

 

                                            


                            

                                                           









                                                           
                                                       















                                                                   
                                                                       

 



                                    

 



                                            


                         


                  

 
































                                                                             


                    







































                                                                             


                    




                  























































                                                              









                         

   


                      
                                     
 

                                              
                                                                   
                                            



                                         
               


         
             



                                                
                                                         
 
                                              










                                                               

                                                                 




                                        
/* SPDX-License-Identifier: BSD-2-Clause */

/*
 * Copyright (C) 2013, 2024 embedded brains GmbH & Co. KG
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <rtems/score/smplock.h>
#include <rtems/score/smplockmcs.h>
#include <rtems/score/smplockseq.h>
#include <rtems/test-info.h>
#include <rtems.h>

#include "tmacros.h"

const char rtems_test_name[] = "SMPLOCK 1";

#define TASK_PRIORITY 1

#define CPU_COUNT 32

#define TEST_COUNT 13

typedef struct {
  rtems_test_parallel_context base;
  const char *test_sep;
  const char *counter_sep;
  unsigned long counter[TEST_COUNT];
  unsigned long local_counter[CPU_COUNT][TEST_COUNT][CPU_COUNT];
  SMP_lock_Control lock RTEMS_ALIGNED(CPU_CACHE_LINE_BYTES);
  Atomic_Uint flag RTEMS_ALIGNED(CPU_CACHE_LINE_BYTES);
  SMP_MCS_lock_Control mcs_lock RTEMS_ALIGNED(CPU_CACHE_LINE_BYTES);
#if defined(RTEMS_PROFILING)
  SMP_lock_Stats mcs_stats;
#endif
  SMP_sequence_lock_Control seq_lock RTEMS_ALIGNED(CPU_CACHE_LINE_BYTES);
  int a RTEMS_ALIGNED(CPU_CACHE_LINE_BYTES);
  int b RTEMS_ALIGNED(CPU_CACHE_LINE_BYTES);
} test_context;

static test_context test_instance = {
  .lock = SMP_LOCK_INITIALIZER("global ticket"),
#if defined(RTEMS_PROFILING)
  .mcs_stats = SMP_LOCK_STATS_INITIALIZER("global MCS"),
#endif
  .flag = ATOMIC_INITIALIZER_UINT(0),
  .mcs_lock = SMP_MCS_LOCK_INITIALIZER,
  .seq_lock = SMP_SEQUENCE_LOCK_INITIALIZER
};

static rtems_interval test_duration(void)
{
  return rtems_clock_get_ticks_per_second();
}

static rtems_interval test_init(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers
)
{
  return test_duration();
}

static const rtems_test_parallel_job test_jobs[TEST_COUNT];

static void test_fini(
  test_context *ctx,
  const char *lock_type,
  bool global_lock,
  const char *section_type,
  size_t test,
  size_t active_workers
)
{
  bool cascade = test_jobs[test].cascade;
  unsigned long sum = 0;
  const char *value_sep;
  size_t i;

  if (active_workers == 1 || !cascade) {
    printf(
      "%s{\n"
      "    \"lock-type\": \"%s\",\n"
      "    \"lock-object\": \"%s\",\n"
      "    \"section-type\": \"%s\",\n"
      "    \"results\": [",
      ctx->test_sep,
      lock_type,
      global_lock ? "global" : "local",
      section_type
    );
    ctx->test_sep = ", ";
    ctx->counter_sep = "\n      ";
  }

  printf(
    "%s{\n"
    "        \"counter\": [", ctx->counter_sep);
  ctx->counter_sep = "\n      }, ";
  value_sep = "";

  for (i = 0; i < active_workers; ++i) {
    unsigned long local_counter =
      ctx->local_counter[active_workers - 1][test][i];

    sum += local_counter;

    printf(
      "%s%lu",
      value_sep,
      local_counter
    );
    value_sep = ", ";
  }

  printf(
    "],\n"
    "        \"global-counter\": %lu,\n"
    "        \"sum-of-local-counter\": %lu",
    ctx->counter[test],
    sum
  );

  if (active_workers == rtems_scheduler_get_processor_maximum() || !cascade) {
    printf("\n      }\n    ]\n  }");
  }
}

static void test_0_body(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers,
  size_t worker_index
)
{
  test_context *ctx = (test_context *) base;
  size_t test = 0;
  unsigned long counter = 0;
  SMP_lock_Context lock_context;

  while (!rtems_test_parallel_stop_job(&ctx->base)) {
    _SMP_lock_Acquire(&ctx->lock, &lock_context);
    _SMP_lock_Release(&ctx->lock, &lock_context);
    ++counter;
  }

  ctx->local_counter[active_workers - 1][test][worker_index] = counter;
}

static void test_0_fini(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers
)
{
  test_context *ctx = (test_context *) base;

  test_fini(
    ctx,
    "Ticket Lock",
    true,
    "local counter",
    0,
    active_workers
  );
}

static void test_1_body(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers,
  size_t worker_index
)
{
  test_context *ctx = (test_context *) base;
  size_t test = 1;
  unsigned long counter = 0;
  SMP_MCS_lock_Context lock_context;

  while (!rtems_test_parallel_stop_job(&ctx->base)) {
    _SMP_MCS_lock_Acquire(&ctx->mcs_lock, &lock_context, &ctx->mcs_stats);
    _SMP_MCS_lock_Release(&ctx->mcs_lock, &lock_context);
    ++counter;
  }

  ctx->local_counter[active_workers - 1][test][worker_index] = counter;
}

static void test_1_fini(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers
)
{
  test_context *ctx = (test_context *) base;

  test_fini(
    ctx,
    "MCS Lock",
    true,
    "local counter",
    1,
    active_workers
  );
}

static void test_2_body(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers,
  size_t worker_index
)
{
  test_context *ctx = (test_context *) base;
  size_t test = 2;
  unsigned long counter = 0;
  SMP_lock_Context lock_context;

  while (!rtems_test_parallel_stop_job(&ctx->base)) {
    _SMP_lock_Acquire(&ctx->lock, &lock_context);
    ++ctx->counter[test];
    _SMP_lock_Release(&ctx->lock, &lock_context);
    ++counter;
  }

  ctx->local_counter[active_workers - 1][test][worker_index] = counter;
}

static void test_2_fini(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers
)
{
  test_context *ctx = (test_context *) base;

  test_fini(
    ctx,
    "Ticket Lock",
    true,
    "global counter",
    2,
    active_workers
  );
}

static void test_3_body(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers,
  size_t worker_index
)
{
  test_context *ctx = (test_context *) base;
  size_t test = 3;
  unsigned long counter = 0;
  SMP_MCS_lock_Context lock_context;

  while (!rtems_test_parallel_stop_job(&ctx->base)) {
    _SMP_MCS_lock_Acquire(&ctx->mcs_lock, &lock_context, &ctx->mcs_stats);
    ++ctx->counter[test];
    _SMP_MCS_lock_Release(&ctx->mcs_lock, &lock_context);
    ++counter;
  }

  ctx->local_counter[active_workers - 1][test][worker_index] = counter;
}

static void test_3_fini(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers
)
{
  test_context *ctx = (test_context *) base;

  test_fini(
    ctx,
    "MCS Lock",
    true,
    "global counter",
    3,
    active_workers
  );
}

static void test_4_body(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers,
  size_t worker_index
)
{
  test_context *ctx = (test_context *) base;
  size_t test = 4;
  unsigned long counter = 0;
  SMP_lock_Control lock;
  SMP_lock_Context lock_context;

  _SMP_lock_Initialize(&lock, "local");

  while (!rtems_test_parallel_stop_job(&ctx->base)) {
    _SMP_lock_Acquire(&lock, &lock_context);
    _SMP_lock_Release(&lock, &lock_context);
    ++counter;
  }

  _SMP_lock_Destroy(&lock);

  ctx->local_counter[active_workers - 1][test][worker_index] = counter;
}

static void test_4_fini(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers
)
{
  test_context *ctx = (test_context *) base;

  test_fini(
    ctx,
    "Ticket Lock",
    false,
    "local counter",
    4,
    active_workers
  );
}

static void test_5_body(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers,
  size_t worker_index
)
{
  test_context *ctx = (test_context *) base;
  size_t test = 5;
  unsigned long counter = 0;
#if defined(RTEMS_PROFILING)
  SMP_lock_Stats stats;
#endif
  SMP_MCS_lock_Control lock;
  SMP_MCS_lock_Context lock_context;

  _SMP_lock_Stats_initialize(&stats, "local");
  _SMP_MCS_lock_Initialize(&lock);

  while (!rtems_test_parallel_stop_job(&ctx->base)) {
    _SMP_MCS_lock_Acquire(&lock, &lock_context, &stats);
    _SMP_MCS_lock_Release(&lock, &lock_context);
    ++counter;
  }

  _SMP_MCS_lock_Destroy(&lock);
  _SMP_lock_Stats_destroy(&stats);

  ctx->local_counter[active_workers - 1][test][worker_index] = counter;
}

static void test_5_fini(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers
)
{
  test_context *ctx = (test_context *) base;

  test_fini(
    ctx,
    "MCS Lock",
    false,
    "local counter",
    5,
    active_workers
  );
}

static void test_6_body(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers,
  size_t worker_index
)
{
  test_context *ctx = (test_context *) base;
  size_t test = 6;
  unsigned long counter = 0;
  SMP_lock_Control lock;
  SMP_lock_Context lock_context;

  _SMP_lock_Initialize(&lock, "local");

  while (!rtems_test_parallel_stop_job(&ctx->base)) {
    _SMP_lock_Acquire(&lock, &lock_context);

    /* The counter value is not interesting, only the access to it */
    ++ctx->counter[test];

    _SMP_lock_Release(&lock, &lock_context);
    ++counter;
  }

  _SMP_lock_Destroy(&lock);

  ctx->local_counter[active_workers - 1][test][worker_index] = counter;
}

static void test_6_fini(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers
)
{
  test_context *ctx = (test_context *) base;

  test_fini(
    ctx,
    "Ticket Lock",
    false,
    "global counter",
    6,
    active_workers
  );
}

static void test_7_body(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers,
  size_t worker_index
)
{
  test_context *ctx = (test_context *) base;
  size_t test = 7;
  unsigned long counter = 0;
#if defined(RTEMS_PROFILING)
  SMP_lock_Stats stats;
#endif
  SMP_MCS_lock_Control lock;
  SMP_MCS_lock_Context lock_context;

  _SMP_lock_Stats_initialize(&stats, "local");
  _SMP_MCS_lock_Initialize(&lock);

  while (!rtems_test_parallel_stop_job(&ctx->base)) {
    _SMP_MCS_lock_Acquire(&lock, &lock_context, &stats);

    /* The counter value is not interesting, only the access to it */
    ++ctx->counter[test];

    _SMP_MCS_lock_Release(&lock, &lock_context);
    ++counter;
  }

  _SMP_MCS_lock_Destroy(&lock);
  _SMP_lock_Stats_destroy(&stats);

  ctx->local_counter[active_workers - 1][test][worker_index] = counter;
}

static void test_7_fini(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers
)
{
  test_context *ctx = (test_context *) base;

  test_fini(
    ctx,
    "MCS Lock",
    false,
    "global counter",
    7,
    active_workers
  );
}

static void busy_section(void)
{
  int i;

  for (i = 0; i < 101; ++i) {
    RTEMS_COMPILER_MEMORY_BARRIER();
  }
}

static void test_8_body(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers,
  size_t worker_index
)
{
  test_context *ctx = (test_context *) base;
  size_t test = 8;
  unsigned long counter = 0;
  SMP_lock_Context lock_context;

  while (!rtems_test_parallel_stop_job(&ctx->base)) {
    _SMP_lock_Acquire(&ctx->lock, &lock_context);
    busy_section();
    _SMP_lock_Release(&ctx->lock, &lock_context);
    ++counter;
  }

  ctx->local_counter[active_workers - 1][test][worker_index] = counter;
}

static void test_8_fini(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers
)
{
  test_context *ctx = (test_context *) base;

  test_fini(
    ctx,
    "Ticket Lock",
    true,
    "busy loop",
    8,
    active_workers
  );
}

static void test_9_body(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers,
  size_t worker_index
)
{
  test_context *ctx = (test_context *) base;
  size_t test = 9;
  unsigned long counter = 0;
  SMP_MCS_lock_Context lock_context;

  while (!rtems_test_parallel_stop_job(&ctx->base)) {
    _SMP_MCS_lock_Acquire(&ctx->mcs_lock, &lock_context, &ctx->mcs_stats);
    busy_section();
    _SMP_MCS_lock_Release(&ctx->mcs_lock, &lock_context);
    ++counter;
  }

  ctx->local_counter[active_workers - 1][test][worker_index] = counter;
}

static void test_9_fini(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers
)
{
  test_context *ctx = (test_context *) base;

  test_fini(
    ctx,
    "MCS Lock",
    true,
    "busy loop",
    9,
    active_workers
  );
}

static void test_10_body(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers,
  size_t worker_index
)
{
  test_context *ctx = (test_context *) base;
  size_t test = 10;
  unsigned long counter = 0;
  unsigned long seq;

  if (rtems_test_parallel_is_master_worker(worker_index)) {
    while (!rtems_test_parallel_stop_job(&ctx->base)) {
      seq = _SMP_sequence_lock_Write_begin(&ctx->seq_lock);

      ctx->a = counter;
      ctx->b = counter;

      _SMP_sequence_lock_Write_end(&ctx->seq_lock, seq);

      ++counter;
    }
  } else {
    while (!rtems_test_parallel_stop_job(&ctx->base)) {
      unsigned long a;
      unsigned long b;

      do {
        seq = _SMP_sequence_lock_Read_begin(&ctx->seq_lock);

        a = ctx->a;
        b = ctx->b;

      } while (_SMP_sequence_lock_Read_retry(&ctx->seq_lock, seq));

      ++counter;
      rtems_test_assert(a == b);
    }
  }

  ctx->local_counter[active_workers - 1][test][worker_index] = counter;
}

static void test_10_fini(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers
)
{
  test_context *ctx = (test_context *) base;

  test_fini(
    ctx,
    "Sequence Lock",
    true,
    "two global counter",
    10,
    active_workers
  );
}

static void test_11_body(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers,
  size_t worker_index
)
{
  test_context *ctx = (test_context *) base;
  size_t test = 11;
  unsigned long counter = 0;

  while (!rtems_test_parallel_stop_job(&ctx->base)) {
    while (_Atomic_Exchange_uint(&ctx->flag, 1, ATOMIC_ORDER_ACQUIRE) != 0) {
      /* Wait */
    }

    _Atomic_Store_uint(&ctx->flag, 0, ATOMIC_ORDER_RELEASE);
    ++counter;
  }

  ctx->local_counter[active_workers - 1][test][worker_index] = counter;
}

static void test_11_fini(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers
)
{
  test_context *ctx = (test_context *) base;

  test_fini(
    ctx,
    "TAS Lock",
    true,
    "local counter",
    11,
    active_workers
  );
}

static void test_12_body(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers,
  size_t worker_index
)
{
  test_context *ctx = (test_context *) base;
  size_t test = 12;
  unsigned long counter = 0;

  while (!rtems_test_parallel_stop_job(&ctx->base)) {
    while (_Atomic_Exchange_uint(&ctx->flag, 1, ATOMIC_ORDER_ACQUIRE) != 0) {
      while (_Atomic_Load_uint(&ctx->flag, ATOMIC_ORDER_RELAXED) != 0) {
        /* Wait */
      }
    }

    _Atomic_Store_uint(&ctx->flag, 0, ATOMIC_ORDER_RELEASE);
    ++counter;
  }

  ctx->local_counter[active_workers - 1][test][worker_index] = counter;
}

static void test_12_fini(
  rtems_test_parallel_context *base,
  void *arg,
  size_t active_workers
)
{
  test_context *ctx = (test_context *) base;

  test_fini(
    ctx,
    "TTAS Lock",
    true,
    "local counter",
    12,
    active_workers
  );
}

static const rtems_test_parallel_job test_jobs[TEST_COUNT] = {
  {
    .init = test_init,
    .body = test_0_body,
    .fini = test_0_fini,
    .cascade = true
  }, {
    .init = test_init,
    .body = test_1_body,
    .fini = test_1_fini,
    .cascade = true
  }, {
    .init = test_init,
    .body = test_2_body,
    .fini = test_2_fini,
    .cascade = false
  }, {
    .init = test_init,
    .body = test_3_body,
    .fini = test_3_fini,
    .cascade = false
  }, {
    .init = test_init,
    .body = test_4_body,
    .fini = test_4_fini,
    .cascade = true
  }, {
    .init = test_init,
    .body = test_5_body,
    .fini = test_5_fini,
    .cascade = true
  }, {
    .init = test_init,
    .body = test_6_body,
    .fini = test_6_fini,
    .cascade = false
  }, {
    .init = test_init,
    .body = test_7_body,
    .fini = test_7_fini,
    .cascade = false
  }, {
    .init = test_init,
    .body = test_8_body,
    .fini = test_8_fini,
    .cascade = false
  }, {
    .init = test_init,
    .body = test_9_body,
    .fini = test_9_fini,
    .cascade = false
  }, {
    .init = test_init,
    .body = test_10_body,
    .fini = test_10_fini,
    .cascade = false
  }, {
    .init = test_init,
    .body = test_11_body,
    .fini = test_11_fini,
    .cascade = true
  }, {
    .init = test_init,
    .body = test_12_body,
    .fini = test_12_fini,
    .cascade = true
  }
};

static void test(void)
{
  test_context *ctx = &test_instance;

  printf("*** BEGIN OF JSON DATA ***\n[\n  ");
  ctx->test_sep = "";
  rtems_test_parallel(&ctx->base, NULL, &test_jobs[0], TEST_COUNT);
  printf("\n]\n*** END OF JSON DATA ***\n");
}

static void Init(rtems_task_argument arg)
{
  TEST_BEGIN();

  test();

  TEST_END();
  rtems_test_exit(0);
}

#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER

#define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT

#define CONFIGURE_MAXIMUM_TASKS CPU_COUNT

#define CONFIGURE_MAXIMUM_SEMAPHORES 1

#define CONFIGURE_MAXIMUM_TIMERS 1

#define CONFIGURE_INIT_TASK_PRIORITY TASK_PRIORITY
#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_DEFAULT_ATTRIBUTES

#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION

#define CONFIGURE_RTEMS_INIT_TASKS_TABLE

#define CONFIGURE_INIT

#include <rtems/confdefs.h>