File indexing completed on 2025-05-11 08:24:43
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
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>