File indexing completed on 2025-05-11 08:24:42
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
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039 #ifdef HAVE_CONFIG_H
0040 #include "config.h"
0041 #endif
0042
0043 #include <rtems.h>
0044 #include <bsp/irq.h>
0045 #include <rtems/captureimpl.h>
0046 #include "tmacros.h"
0047
0048 const char rtems_test_name[] = "SMPCAPTURE 2";
0049
0050 #define MAX_CPUS 4
0051 #define TASKS_PER_CPU 5
0052 #define ITERATIONS 3
0053 #define TASK_PRIO 30
0054 #define CLOCK_TICKS 100
0055
0056 typedef struct {
0057 rtems_id id;
0058 rtems_id task_sem;
0059 rtems_id prev_sem;
0060 } per_cpu_task_data;
0061
0062 typedef struct {
0063 bool found;
0064 const char *info;
0065 rtems_option options;
0066 rtems_interrupt_handler handler;
0067 void *arg;
0068 } clock_interrupt_handler;
0069
0070 static rtems_id finished_sem;
0071 static per_cpu_task_data task_data[ TASKS_PER_CPU * TASKS_PER_CPU ];
0072 static rtems_interrupt_handler org_clock_handler;
0073
0074 typedef enum {
0075 enter_add_number,
0076 exit_add_number,
0077 clock_tick
0078 } cap_rec_type;
0079
0080
0081
0082
0083
0084 typedef struct {
0085 uint32_t a;
0086 uint32_t b;
0087 } RTEMS_PACKED enter_add_number_record;
0088
0089 typedef struct {
0090 uint32_t res;
0091 } RTEMS_PACKED exit_add_number_record;
0092
0093 typedef struct {
0094 void *arg;
0095 } RTEMS_PACKED clock_tick_record;
0096
0097
0098
0099
0100 #define PNAME(n) \
0101 (char) (n >> 24) & 0xff, (char) (n >> 16) & 0xff, \
0102 (char) (n >> 8) & 0xff, (char) (n >> 0) & 0xff
0103
0104
0105
0106
0107 static uint32_t add_number(uint32_t a, uint32_t b)
0108 {
0109 return a + b;
0110 }
0111
0112
0113
0114
0115
0116 static uint32_t add_number_wrapper(uint32_t a, uint32_t b)
0117 {
0118 rtems_capture_record_lock_context lock;
0119 enter_add_number_record enter_rec;
0120 exit_add_number_record exit_rec;
0121 cap_rec_type id;
0122 uint32_t res;
0123 void* rec;
0124
0125 id = enter_add_number;
0126 enter_rec.a = a;
0127 enter_rec.b = b;
0128
0129 rec = rtems_capture_record_open(_Thread_Get_executing(),
0130 RTEMS_CAPTURE_TIMESTAMP,
0131 sizeof(id) + sizeof(enter_rec),
0132 &lock);
0133 rtems_test_assert(rec != NULL);
0134 rec = rtems_capture_record_append(rec, &id, sizeof(id));
0135 rtems_test_assert(rec != NULL);
0136 rec = rtems_capture_record_append(rec, &enter_rec, sizeof(enter_rec));
0137 rtems_test_assert(rec != NULL);
0138 rtems_capture_record_close(&lock);
0139
0140 res = add_number(a, b);
0141
0142 id = exit_add_number;
0143 exit_rec.res = res;
0144
0145 rec = rtems_capture_record_open(_Thread_Get_executing(),
0146 RTEMS_CAPTURE_TIMESTAMP,
0147 sizeof(id) + sizeof(exit_rec),
0148 &lock);
0149 rtems_test_assert(rec != NULL);
0150 rec = rtems_capture_record_append(rec, &id, sizeof(id));
0151 rtems_test_assert(rec != NULL);
0152 rec = rtems_capture_record_append(rec, &exit_rec, sizeof(exit_rec));
0153 rtems_test_assert(rec != NULL);
0154 rtems_capture_record_close(&lock);
0155
0156 return res;
0157 }
0158
0159
0160
0161
0162 static void task(rtems_task_argument arg)
0163 {
0164 rtems_status_code sc;
0165 uint32_t i;
0166
0167 for ( i = 0; i < ITERATIONS; i++ ) {
0168
0169
0170
0171
0172 sc = rtems_semaphore_obtain(task_data[arg].prev_sem, 0, 0);
0173 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0174
0175 add_number_wrapper(arg, i);
0176
0177
0178
0179
0180 sc = rtems_semaphore_release(task_data[arg].task_sem);
0181 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0182 }
0183
0184
0185 sc = rtems_semaphore_release(finished_sem);
0186 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0187 rtems_task_suspend(rtems_task_self());
0188 }
0189
0190 static void test(uint32_t cpu_count)
0191 {
0192 rtems_status_code sc;
0193 uint32_t t;
0194 uint32_t c;
0195 rtems_task_argument idx;
0196 cpu_set_t cpu_set;
0197
0198
0199 sc = rtems_semaphore_create(rtems_build_name('D', 'o', 'n', 'e'), 0,
0200 RTEMS_LOCAL |
0201 RTEMS_NO_INHERIT_PRIORITY |
0202 RTEMS_NO_PRIORITY_CEILING |
0203 RTEMS_FIFO, 0, &finished_sem);
0204
0205
0206
0207
0208
0209
0210 for ( c = 0; c < cpu_count; c++ ) {
0211 for ( t = 0; t < TASKS_PER_CPU; t++ ) {
0212 idx = c * TASKS_PER_CPU + t;
0213
0214 sc = rtems_task_create(rtems_build_name('T', 'A', '0' + c, '0' + t),
0215 TASK_PRIO,
0216 RTEMS_MINIMUM_STACK_SIZE,
0217 RTEMS_DEFAULT_MODES,
0218 RTEMS_DEFAULT_ATTRIBUTES,
0219 &task_data[idx].id);
0220 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0221
0222 sc = rtems_semaphore_create(rtems_build_name('S', 'E', '0' + c, '0' + t),
0223 0,
0224 RTEMS_LOCAL |
0225 RTEMS_SIMPLE_BINARY_SEMAPHORE |
0226 RTEMS_NO_INHERIT_PRIORITY |
0227 RTEMS_NO_PRIORITY_CEILING |
0228 RTEMS_FIFO, 0, &task_data[idx].task_sem);
0229 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0230
0231 task_data[(idx + 1) % (cpu_count * TASKS_PER_CPU)].prev_sem =
0232 task_data[idx].task_sem;
0233
0234 CPU_ZERO_S(sizeof(cpu_set_t), &cpu_set);
0235 CPU_SET_S(c, sizeof(cpu_set_t), &cpu_set);
0236
0237 sc = rtems_task_set_affinity(task_data[idx].id, sizeof(cpu_set_t),
0238 &cpu_set);
0239 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0240 }
0241 }
0242
0243
0244 for ( idx = 0; idx < cpu_count * TASKS_PER_CPU; idx++ ) {
0245 sc = rtems_task_start(task_data[idx].id, task, idx);
0246 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0247 }
0248
0249
0250 sc = rtems_semaphore_release(task_data[0].task_sem);
0251
0252
0253 for ( idx = 0; idx < cpu_count * TASKS_PER_CPU; idx++ ) {
0254 rtems_semaphore_obtain(finished_sem, 0, 0);
0255 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0256 }
0257
0258 }
0259
0260
0261 static void clock_tick_wrapper(void *arg)
0262 {
0263 rtems_capture_record_lock_context lock;
0264 cap_rec_type id = clock_tick;
0265 Thread_Control* tcb = _Thread_Get_executing();
0266 void* rec;
0267
0268 rec = rtems_capture_record_open(tcb,
0269 RTEMS_CAPTURE_TIMESTAMP,
0270 sizeof(id),
0271 &lock);
0272 rtems_test_assert(rec != NULL);
0273 rec = rtems_capture_record_append(rec, &id, sizeof(id));
0274 rtems_test_assert(rec != NULL);
0275 rtems_capture_record_close(&lock);
0276
0277 org_clock_handler(arg);
0278 }
0279
0280
0281
0282 static void locate_clock_interrupt_handler(
0283 void *arg, const char *info, rtems_option options,
0284 rtems_interrupt_handler handler, void *handler_arg)
0285 {
0286 clock_interrupt_handler *cih = (clock_interrupt_handler*)arg;
0287 if ( !strcmp(info, "clock") || !strcmp(info, "Clock") ) {
0288 cih->info = info;
0289 cih->options = options;
0290 cih->handler = handler;
0291 cih->arg = handler_arg;
0292 cih->found = true;
0293 }
0294 }
0295
0296 static void Init(rtems_task_argument arg)
0297 {
0298 rtems_status_code sc;
0299 uint32_t i;
0300 uint32_t cpu;
0301 uint32_t cpu_count;
0302 uint32_t enter_count;
0303 uint32_t exit_count;
0304 uint32_t clock_tick_count;
0305 uint32_t res_should_be;
0306 rtems_vector_number vec;
0307 size_t read;
0308 const void *recs;
0309 cap_rec_type id;
0310 rtems_capture_record rec;
0311 rtems_capture_record prev_rec;
0312 enter_add_number_record enter_rec;
0313 exit_add_number_record exit_rec;
0314 clock_interrupt_handler cih = {.found = 0};
0315
0316 #ifdef VERBOSE
0317 rtems_name name;
0318 #endif
0319
0320 TEST_BEGIN();
0321
0322
0323 cpu_count = rtems_scheduler_get_processor_maximum();
0324
0325 sc = rtems_capture_open(50000, NULL);
0326 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0327
0328 sc = rtems_capture_watch_global(true);
0329 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0330
0331 sc = rtems_capture_set_control(true);
0332 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0333
0334
0335 test(cpu_count);
0336
0337
0338 for ( vec = 0; vec < BSP_INTERRUPT_VECTOR_COUNT; vec++ ) {
0339 rtems_interrupt_handler_iterate(vec, locate_clock_interrupt_handler, &cih);
0340 if ( cih.found )
0341 break;
0342 }
0343
0344
0345
0346
0347 if ( cih.found ) {
0348 #ifdef VERBOSE
0349 printf("Found a clock handler\n");
0350 #endif
0351 org_clock_handler = cih.handler;
0352 rtems_interrupt_handler_install(vec, cih.info,
0353 cih.options | RTEMS_INTERRUPT_REPLACE, clock_tick_wrapper, cih.arg);
0354
0355 rtems_task_wake_after(CLOCK_TICKS);
0356 }
0357
0358
0359 sc = rtems_capture_set_control(false);
0360 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0361
0362 clock_tick_count = 0;
0363
0364
0365 for ( cpu = 0; cpu < cpu_count; cpu++ ) {
0366 sc = rtems_capture_read(cpu, &read, &recs);
0367 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0368 rtems_test_assert(recs != NULL);
0369
0370 memset(&rec, 0, sizeof(rec));
0371 prev_rec = rec;
0372 enter_count = 0;
0373 exit_count = 0;
0374 res_should_be = 0;
0375
0376 for ( i = 0; i < read; i++ ) {
0377
0378 recs = rtems_capture_record_extract(recs, &rec, sizeof(rec));
0379 rtems_test_assert(recs != NULL);
0380
0381
0382 rtems_test_assert(rec.time >= prev_rec.time);
0383
0384 if ((rec.events & RTEMS_CAPTURE_TIMESTAMP) != 0) {
0385 recs = rtems_capture_record_extract(recs, &id, sizeof(id));
0386 rtems_test_assert(recs != NULL);
0387
0388 switch (id) {
0389 case enter_add_number:
0390 rtems_test_assert(enter_count == exit_count);
0391 enter_count++;
0392 recs = rtems_capture_record_extract(recs,
0393 &enter_rec,
0394 sizeof(enter_rec));
0395 rtems_test_assert(recs != NULL);
0396 res_should_be = add_number(enter_rec.a, enter_rec.b);
0397 #ifdef VERBOSE
0398
0399 rtems_object_get_classic_name(rec.task_id, &name);
0400 printf("Time: %"PRIu64"us Task: %c%c%c%c => Add %"PRIu32" and %"PRIu32" is %"PRIu32"\n",
0401 rec.time / 1000, PNAME(name), enter_rec.a, enter_rec.b, res_should_be);
0402 #endif
0403 break;
0404 case exit_add_number:
0405 rtems_test_assert(enter_count == exit_count+1);
0406 exit_count++;
0407 recs = rtems_capture_record_extract(recs,
0408 &exit_rec,
0409 sizeof(exit_rec));
0410 rtems_test_assert(recs != NULL);
0411 #ifdef VERBOSE
0412
0413 rtems_object_get_classic_name(rec.task_id, &name);
0414 printf("Time: %"PRIu64"us Task: %c%c%c%c => Result is %"PRIu32"\n",
0415 rec.time / 1000, PNAME(name), exit_rec.res);
0416 #endif
0417
0418 rtems_test_assert(res_should_be == exit_rec.res);
0419 break;
0420 case clock_tick:
0421 clock_tick_count++;
0422 #ifdef VERBOSE
0423 rtems_object_get_classic_name(rec.task_id, &name);
0424 printf("Time: %"PRIu64"us Task: %c%c%c%c => Clock tick\n",
0425 rec.time/1000, PNAME(name));
0426 #endif
0427 break;
0428 default:
0429 rtems_test_assert(0);
0430 }
0431 }
0432
0433 prev_rec = rec;
0434 }
0435
0436 rtems_test_assert(enter_count == exit_count);
0437 rtems_test_assert(enter_count == TASKS_PER_CPU * ITERATIONS);
0438
0439 rtems_capture_release(cpu, read);
0440 }
0441
0442 TEST_END();
0443 rtems_test_exit(0);
0444 }
0445
0446 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
0447 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
0448
0449 #define CONFIGURE_SCHEDULER_PRIORITY_AFFINITY_SMP
0450
0451 #define CONFIGURE_MAXIMUM_PROCESSORS MAX_CPUS
0452 #define CONFIGURE_MAXIMUM_PROCESSORS MAX_CPUS
0453 #define CONFIGURE_MAXIMUM_SEMAPHORES MAX_CPUS * TASKS_PER_CPU + 1
0454 #define CONFIGURE_MAXIMUM_TASKS MAX_CPUS * TASKS_PER_CPU + 1
0455
0456 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0457 #define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1
0458 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
0459 #define CONFIGURE_INIT
0460
0461 #include <rtems/confdefs.h>