Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:43

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (c) 2014 embedded brains GmbH & Co. KG
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #ifdef HAVE_CONFIG_H
0029 #include "config.h"
0030 #endif
0031 
0032 #include "tmacros.h"
0033 
0034 #include <stdlib.h>
0035 #include <stdio.h>
0036 #include <inttypes.h>
0037 
0038 #include <rtems.h>
0039 #include <rtems/counter.h>
0040 #include <rtems/score/smpbarrier.h>
0041 #include <rtems/score/smplock.h>
0042 
0043 const char rtems_test_name[] = "SMPLOAD 1";
0044 
0045 #define CPU_COUNT 32
0046 
0047 #define MAX_INHERIT_OBTAIN_COUNT CPU_COUNT
0048 
0049 #define SEM_WORKER_COUNT (3 * CPU_COUNT)
0050 
0051 #define INIT_PRIO 1
0052 
0053 #define INHERIT_RELEASE_PRIO_HIGH (INIT_PRIO + 1)
0054 
0055 #define INHERIT_OBTAIN_PRIO_BASE (INHERIT_RELEASE_PRIO_HIGH + 1)
0056 
0057 #define INHERIT_RELEASE_PRIO_LOW (INHERIT_OBTAIN_PRIO_BASE + MAX_INHERIT_OBTAIN_COUNT)
0058 
0059 #define LOAD_PRIO (INHERIT_RELEASE_PRIO_LOW + 1)
0060 
0061 #define SEM_WORKER_CEILING_PRIO (LOAD_PRIO + 1)
0062 
0063 #define SEM_WORKER_PRIO_BASE (SEM_WORKER_CEILING_PRIO + 1)
0064 
0065 typedef struct {
0066   rtems_id main_task_id;
0067   rtems_id inherit_release_task_id;
0068   rtems_id inherit_main_obtain_task_id;
0069   rtems_id sem_worker_sem_prio_inherit;
0070   rtems_id sem_worker_sem_prio_ceiling;
0071   rtems_id inherit_sem;
0072   rtems_counter_ticks inherit_obtain_delay;
0073   SMP_barrier_Control inherit_barrier;
0074   uint64_t inherit_obtain_counter[MAX_INHERIT_OBTAIN_COUNT];
0075   uint64_t inherit_release_counter;
0076   uint64_t sem_worker_counter[SEM_WORKER_COUNT];
0077 } test_context;
0078 
0079 static test_context test_instance = {
0080   .inherit_barrier = SMP_BARRIER_CONTROL_INITIALIZER
0081 };
0082 
0083 static uint32_t simple_random(uint32_t v)
0084 {
0085   v *= 1664525;
0086   v += 1013904223;
0087 
0088   return v;
0089 }
0090 
0091 static void inherit_obtain_task(rtems_task_argument arg)
0092 {
0093   test_context *ctx = &test_instance;
0094   rtems_status_code sc;
0095   SMP_barrier_State barrier_state = SMP_BARRIER_STATE_INITIALIZER;
0096   uint32_t cpu_count = rtems_scheduler_get_processor_maximum();
0097   rtems_counter_ticks delay = (cpu_count - 1 - arg) * ctx->inherit_obtain_delay;
0098 
0099   while (true) {
0100     _SMP_barrier_Wait(&ctx->inherit_barrier, &barrier_state, cpu_count);
0101 
0102     rtems_counter_delay_ticks(delay);
0103 
0104     sc = rtems_semaphore_obtain(ctx->inherit_sem, RTEMS_WAIT, 1);
0105     rtems_test_assert(sc == RTEMS_TIMEOUT);
0106 
0107     _SMP_barrier_Wait(&ctx->inherit_barrier, &barrier_state, cpu_count);
0108 
0109     ++ctx->inherit_obtain_counter[arg];
0110 
0111     if (arg == 0) {
0112       rtems_task_priority prio = INHERIT_RELEASE_PRIO_HIGH;
0113 
0114       sc = rtems_task_set_priority(ctx->inherit_release_task_id, prio, &prio);
0115       rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0116 
0117       sc = rtems_event_transient_send(ctx->inherit_release_task_id);
0118       rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0119 
0120       sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0121       rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0122     }
0123   }
0124 }
0125 
0126 static void inherit_release_task(rtems_task_argument arg)
0127 {
0128   test_context *ctx = &test_instance;
0129   rtems_status_code sc;
0130 
0131   sc = rtems_semaphore_obtain(
0132     ctx->inherit_sem,
0133     RTEMS_WAIT,
0134     RTEMS_NO_TIMEOUT
0135   );
0136   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0137 
0138   sc = rtems_event_transient_send(ctx->main_task_id);
0139   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0140 
0141   while (true) {
0142     rtems_task_priority prio = INHERIT_RELEASE_PRIO_LOW;
0143 
0144     sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0145     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0146 
0147     sc = rtems_semaphore_release(ctx->inherit_sem);
0148     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0149 
0150     ++ctx->inherit_release_counter;
0151 
0152     sc = rtems_semaphore_obtain(
0153       ctx->inherit_sem,
0154       RTEMS_WAIT,
0155       RTEMS_NO_TIMEOUT
0156     );
0157     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0158 
0159     sc = rtems_task_set_priority(RTEMS_SELF, prio, &prio);
0160     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0161 
0162     sc = rtems_event_transient_send(ctx->inherit_main_obtain_task_id);
0163     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0164   }
0165 }
0166 
0167 static void load_task(rtems_task_argument arg)
0168 {
0169   size_t data_size;
0170   volatile int *data;
0171   volatile int dummy;
0172   size_t n;
0173 
0174   data_size = rtems_cache_get_data_cache_size(0);
0175   if (data_size > 0) {
0176     data = malloc(data_size);
0177     rtems_test_assert(data != NULL);
0178   } else {
0179     data_size = sizeof(dummy);
0180     data = &dummy;
0181   }
0182 
0183   n = data_size / sizeof(*data);
0184   while (true) {
0185     size_t i;
0186 
0187     for (i = 0; i < n; ++i) {
0188       data[i] = i;
0189     }
0190   }
0191 }
0192 
0193 static void sem_worker_task(rtems_task_argument arg)
0194 {
0195   test_context *ctx = &test_instance;
0196   uint32_t v = arg;
0197 
0198   while (true) {
0199     rtems_status_code sc;
0200     rtems_id id;
0201 
0202     v = simple_random(v);
0203 
0204     if ((v & 0x80000000) != 0) {
0205       id = ctx->sem_worker_sem_prio_inherit;
0206     } else {
0207       id = ctx->sem_worker_sem_prio_ceiling;
0208     }
0209 
0210     sc = rtems_semaphore_obtain(id, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0211     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0212 
0213     sc = rtems_task_wake_after(1);
0214     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0215 
0216     sc = rtems_semaphore_release(id);
0217     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0218 
0219     ++ctx->sem_worker_counter[arg];
0220   }
0221 }
0222 
0223 static int cmp(const void *ap, const void *bp)
0224 {
0225   const rtems_counter_ticks *a = ap;
0226   const rtems_counter_ticks *b = bp;
0227 
0228   return *a - *b;
0229 }
0230 
0231 static void get_obtain_delay_estimate(test_context *ctx)
0232 {
0233   rtems_counter_ticks t[32];
0234   SMP_lock_Control lock;
0235   ISR_Level level;
0236   size_t n = RTEMS_ARRAY_SIZE(t);
0237   size_t i;
0238 
0239   _SMP_lock_Initialize(&lock, "test");
0240 
0241   _ISR_Local_disable(level);
0242 
0243   for (i = 0; i < n; ++i) {
0244     SMP_lock_Context lock_context;
0245     rtems_counter_ticks a;
0246     rtems_counter_ticks b;
0247 
0248     a = rtems_counter_read();
0249     _SMP_lock_ISR_disable_and_acquire(&lock, &lock_context);
0250     b = rtems_counter_read();
0251     _SMP_lock_Release_and_ISR_enable(&lock, &lock_context);
0252 
0253     t[i] = rtems_counter_difference(b, a);
0254   }
0255 
0256   _ISR_Local_enable(level);
0257 
0258   _SMP_lock_Destroy(&lock);
0259 
0260   qsort(&t[0], n, sizeof(t[0]), cmp);
0261 
0262   ctx->inherit_obtain_delay = t[n / 2];
0263 }
0264 
0265 static void test(void)
0266 {
0267   test_context *ctx = &test_instance;
0268   uint32_t i;
0269   rtems_status_code sc;
0270   rtems_id id;
0271 
0272   ctx->main_task_id = rtems_task_self();
0273 
0274   get_obtain_delay_estimate(ctx);
0275 
0276   sc = rtems_semaphore_create(
0277     rtems_build_name('S', 'E', 'M', 'I'),
0278     1,
0279     RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY,
0280     0,
0281     &ctx->sem_worker_sem_prio_inherit
0282   );
0283   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0284 
0285   sc = rtems_semaphore_create(
0286     rtems_build_name('S', 'E', 'M', 'C'),
0287     1,
0288     RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_PRIORITY_CEILING,
0289     SEM_WORKER_CEILING_PRIO,
0290     &ctx->sem_worker_sem_prio_ceiling
0291   );
0292   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0293 
0294   sc = rtems_semaphore_create(
0295     rtems_build_name('I', 'N', 'H', 'E'),
0296     1,
0297     RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY,
0298     0,
0299     &ctx->inherit_sem
0300   );
0301   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0302 
0303   for (i = 0; i < SEM_WORKER_COUNT; ++i) {
0304     sc = rtems_task_create(
0305       rtems_build_name('S', 'E', 'M', 'W'),
0306       SEM_WORKER_PRIO_BASE + i,
0307       RTEMS_MINIMUM_STACK_SIZE,
0308       RTEMS_DEFAULT_MODES,
0309       RTEMS_DEFAULT_ATTRIBUTES,
0310       &id
0311     );
0312     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0313 
0314     sc = rtems_task_start(id, sem_worker_task, i);
0315     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0316   }
0317 
0318   sc = rtems_task_create(
0319     rtems_build_name('L', 'O', 'A', 'D'),
0320     LOAD_PRIO,
0321     RTEMS_MINIMUM_STACK_SIZE,
0322     RTEMS_DEFAULT_MODES,
0323     RTEMS_DEFAULT_ATTRIBUTES,
0324     &id
0325   );
0326   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0327 
0328   sc = rtems_task_start(id, load_task, 0);
0329   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0330 
0331   sc = rtems_task_create(
0332     rtems_build_name('I', 'N', 'H', 'R'),
0333     INHERIT_RELEASE_PRIO_LOW,
0334     RTEMS_MINIMUM_STACK_SIZE,
0335     RTEMS_DEFAULT_MODES,
0336     RTEMS_DEFAULT_ATTRIBUTES,
0337     &id
0338   );
0339   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0340 
0341   ctx->inherit_release_task_id = id;
0342 
0343   sc = rtems_task_start(id, inherit_release_task, 0);
0344   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0345 
0346   sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0347   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0348 
0349   for (i = 0; i < rtems_scheduler_get_processor_maximum(); ++i) {
0350     sc = rtems_task_create(
0351       rtems_build_name('I', 'N', 'H', 'O'),
0352       INHERIT_OBTAIN_PRIO_BASE + i,
0353       RTEMS_MINIMUM_STACK_SIZE,
0354       RTEMS_DEFAULT_MODES,
0355       RTEMS_DEFAULT_ATTRIBUTES,
0356       &id
0357     );
0358     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0359 
0360     if (i == 0) {
0361       ctx->inherit_main_obtain_task_id = id;
0362     }
0363 
0364     sc = rtems_task_start(id, inherit_obtain_task, i);
0365     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0366   }
0367 
0368   sc = rtems_task_wake_after(30 * rtems_clock_get_ticks_per_second());
0369   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0370 
0371   for (i = 0; i < SEM_WORKER_COUNT; ++i) {
0372     printf(
0373       "semaphore worker count %2" PRIu32 ": %" PRIu64 "\n",
0374       i,
0375       ctx->sem_worker_counter[i]
0376     );
0377   }
0378 
0379   printf(
0380     "priority inheritance release count: %" PRIu64 "\n",
0381     ctx->inherit_release_counter
0382   );
0383 
0384   for (i = 0; i < rtems_scheduler_get_processor_maximum(); ++i) {
0385     printf(
0386       "priority inheritance obtain count %2" PRIu32 ": %" PRIu64 "\n",
0387       i,
0388       ctx->inherit_obtain_counter[i]
0389     );
0390   }
0391 }
0392 
0393 static void Init(rtems_task_argument arg)
0394 {
0395   TEST_BEGIN();
0396 
0397   test();
0398 
0399   TEST_END();
0400   rtems_test_exit(0);
0401 }
0402 
0403 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
0404 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
0405 
0406 #define CONFIGURE_MICROSECONDS_PER_TICK 1000
0407 
0408 #define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT
0409 
0410 #define CONFIGURE_MAXIMUM_TASKS \
0411   (1 + MAX_INHERIT_OBTAIN_COUNT + 1 + 1 + SEM_WORKER_COUNT)
0412 
0413 #define CONFIGURE_MAXIMUM_SEMAPHORES 3
0414 
0415 #define CONFIGURE_INIT_TASK_PRIORITY INIT_PRIO
0416 
0417 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
0418 
0419 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0420 
0421 #define CONFIGURE_INIT
0422 
0423 #include <rtems/confdefs.h>