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 <stdio.h>
0035 #include <math.h>
0036 #include <inttypes.h>
0037
0038 const char rtems_test_name[] = "SMPMIGRATION 1";
0039
0040 #define CPU_COUNT 2
0041
0042 #define RUNNER_COUNT (CPU_COUNT + 1)
0043
0044 #define PRIO_STOP 2
0045
0046 #define PRIO_HIGH 3
0047
0048 #define PRIO_NORMAL 4
0049
0050
0051
0052 typedef struct {
0053 uint32_t counter;
0054 uint32_t unused_space_for_cache_line_alignment[7];
0055 } cache_aligned_counter;
0056
0057 typedef struct {
0058 cache_aligned_counter tokens_per_cpu[CPU_COUNT];
0059 volatile cache_aligned_counter cycles_per_cpu[CPU_COUNT];
0060 } test_counters;
0061
0062 typedef struct {
0063 test_counters counters[RUNNER_COUNT];
0064 volatile rtems_task_argument token;
0065 rtems_id runner_ids[RUNNER_COUNT];
0066 } test_context;
0067
0068 CPU_STRUCTURE_ALIGNMENT static test_context ctx_instance;
0069
0070 static void change_prio(rtems_id task, rtems_task_priority prio)
0071 {
0072 rtems_status_code sc;
0073 rtems_task_priority unused;
0074
0075 sc = rtems_task_set_priority(task, prio, &unused);
0076 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0077 }
0078
0079 static void runner(rtems_task_argument self)
0080 {
0081 test_context *ctx = &ctx_instance;
0082 rtems_task_argument next = (self + 1) % RUNNER_COUNT;
0083 rtems_id next_runner = ctx->runner_ids[next];
0084 test_counters *counters = &ctx->counters[self];
0085 test_counters *next_counters = &ctx->counters[next];
0086
0087 while (true) {
0088 uint32_t current_cpu = rtems_scheduler_get_processor();
0089
0090 ++counters->cycles_per_cpu[current_cpu].counter;
0091
0092 if (ctx->token == self) {
0093 uint32_t other_cpu = (current_cpu + 1) % CPU_COUNT;
0094 uint32_t snapshot;
0095
0096 ++counters->tokens_per_cpu[current_cpu].counter;
0097
0098 change_prio(next_runner, PRIO_HIGH);
0099
0100 snapshot = next_counters->cycles_per_cpu[other_cpu].counter;
0101 while (next_counters->cycles_per_cpu[other_cpu].counter == snapshot) {
0102
0103 }
0104
0105 ctx->token = next;
0106
0107 change_prio(RTEMS_SELF, PRIO_NORMAL);
0108 }
0109 }
0110 }
0111
0112 static void stopper(rtems_task_argument arg)
0113 {
0114 (void) arg;
0115
0116 while (true) {
0117
0118 }
0119 }
0120
0121 static uint32_t abs_delta(uint32_t a, uint32_t b)
0122 {
0123 return a > b ? a - b : b - a;
0124 }
0125
0126 static void test(void)
0127 {
0128 test_context *ctx = &ctx_instance;
0129 rtems_status_code sc;
0130 rtems_task_argument runner_index;
0131 rtems_id stopper_id;
0132 uint32_t expected_tokens;
0133 uint32_t total_delta;
0134 uint64_t total_cycles;
0135 uint32_t average_cycles;
0136
0137 sc = rtems_task_create(
0138 rtems_build_name('S', 'T', 'O', 'P'),
0139 PRIO_STOP,
0140 RTEMS_MINIMUM_STACK_SIZE,
0141 RTEMS_DEFAULT_MODES,
0142 RTEMS_DEFAULT_ATTRIBUTES,
0143 &stopper_id
0144 );
0145 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0146
0147 for (runner_index = 0; runner_index < RUNNER_COUNT; ++runner_index) {
0148 sc = rtems_task_create(
0149 rtems_build_name('R', 'U', 'N', (char) ('0' + runner_index)),
0150 PRIO_HIGH + runner_index,
0151 RTEMS_MINIMUM_STACK_SIZE,
0152 RTEMS_DEFAULT_MODES,
0153 RTEMS_DEFAULT_ATTRIBUTES,
0154 &ctx->runner_ids[runner_index]
0155 );
0156 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0157 }
0158
0159 for (runner_index = 0; runner_index < RUNNER_COUNT; ++runner_index) {
0160 sc = rtems_task_start(ctx->runner_ids[runner_index], runner, runner_index);
0161 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0162 }
0163
0164 sc = rtems_task_wake_after(10 * rtems_clock_get_ticks_per_second());
0165 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0166
0167 sc = rtems_task_start(stopper_id, stopper, 0);
0168 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0169
0170 for (runner_index = 0; runner_index < RUNNER_COUNT; ++runner_index) {
0171 sc = rtems_task_delete(ctx->runner_ids[runner_index]);
0172 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0173 }
0174
0175 total_cycles = 0;
0176 for (runner_index = 0; runner_index < RUNNER_COUNT; ++runner_index) {
0177 const test_counters *counters = &ctx->counters[runner_index];
0178 size_t cpu;
0179
0180 for (cpu = 0; cpu < CPU_COUNT; ++cpu) {
0181 total_cycles += counters->cycles_per_cpu[cpu].counter;
0182 }
0183 }
0184 average_cycles = (uint32_t) (total_cycles / (RUNNER_COUNT * CPU_COUNT));
0185
0186 printf(
0187 "total cycles %" PRIu64 "\n"
0188 "average cycles %" PRIu32 "\n",
0189 total_cycles,
0190 average_cycles
0191 );
0192
0193 for (runner_index = 0; runner_index < RUNNER_COUNT; ++runner_index) {
0194 const test_counters *counters = &ctx->counters[runner_index];
0195 size_t cpu;
0196
0197 printf("runner %" PRIuPTR "\n", runner_index);
0198
0199 for (cpu = 0; cpu < CPU_COUNT; ++cpu) {
0200 uint32_t tokens = counters->tokens_per_cpu[cpu].counter;
0201 uint32_t cycles = counters->cycles_per_cpu[cpu].counter;
0202 double cycle_deviation = ((double) cycles - average_cycles)
0203 / average_cycles;
0204
0205 printf(
0206 "\tcpu %zu tokens %" PRIu32 "\n"
0207 "\tcpu %zu cycles %" PRIu32 "\n"
0208 "\tcpu %zu cycle deviation %f\n",
0209 cpu,
0210 tokens,
0211 cpu,
0212 cycles,
0213 cpu,
0214 cycle_deviation
0215 );
0216 }
0217 }
0218
0219 expected_tokens = ctx->counters[0].tokens_per_cpu[0].counter;
0220 total_delta = 0;
0221 for (runner_index = 0; runner_index < RUNNER_COUNT; ++runner_index) {
0222 test_counters *counters = &ctx->counters[runner_index];
0223 size_t cpu;
0224
0225 for (cpu = 0; cpu < CPU_COUNT; ++cpu) {
0226 uint32_t tokens = counters->tokens_per_cpu[cpu].counter;
0227 uint32_t delta = abs_delta(tokens, expected_tokens);
0228
0229 rtems_test_assert(delta <= 1);
0230
0231 total_delta += delta;
0232 }
0233 }
0234
0235 rtems_test_assert(total_delta <= (RUNNER_COUNT * CPU_COUNT - 1));
0236 }
0237
0238 static void Init(rtems_task_argument arg)
0239 {
0240 rtems_print_printer_fprintf_putc(&rtems_test_printer);
0241 TEST_BEGIN();
0242
0243 if (rtems_scheduler_get_processor_maximum() >= 2) {
0244 test();
0245 }
0246
0247 TEST_END();
0248 rtems_test_exit(0);
0249 }
0250
0251 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
0252 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
0253
0254 #define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT
0255
0256 #define CONFIGURE_MAXIMUM_TASKS (2 + RUNNER_COUNT)
0257
0258 #define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
0259
0260 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
0261
0262 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0263
0264 #define CONFIGURE_INIT
0265
0266 #include <rtems/confdefs.h>