Hi, This is the required test case based on the paper ( https://people.mpi-sws.org/~bbb/papers/pdf/rtss14f.pdf) that tests if the Strong APA scheduler is working as intended. I have checked and this compiles with no warnings/errors.
Thanks. Richi. On Tue, Jul 28, 2020 at 7:23 PM Richi Dubey <richidu...@gmail.com> wrote: > --- > testsuites/smptests/smpstrongapa02/init.c | 358 ++++++++++++++++++ > .../smpstrongapa02/smpstrongapa02.doc | 26 ++ > .../smpstrongapa02/smpstrongapa02.scn | 2 + > 3 files changed, 386 insertions(+) > create mode 100644 testsuites/smptests/smpstrongapa02/init.c > create mode 100644 testsuites/smptests/smpstrongapa02/smpstrongapa02.doc > create mode 100644 testsuites/smptests/smpstrongapa02/smpstrongapa02.scn > > diff --git a/testsuites/smptests/smpstrongapa02/init.c > b/testsuites/smptests/smpstrongapa02/init.c > new file mode 100644 > index 0000000000..e00317d7b2 > --- /dev/null > +++ b/testsuites/smptests/smpstrongapa02/init.c > @@ -0,0 +1,358 @@ > +/* > + * Copyright (c) 2020 Richi Dubey > + * All rights reserved. > + * > + * richidu...@gmail.com > + * > + * The license and distribution terms for this file may be > + * found in the file LICENSE in this distribution or at > + * http://www.rtems.org/license/LICENSE. > + */ > +#ifdef HAVE_CONFIG_H > +#include "config.h" > +#endif > + > +#include <tmacros.h> > + > +#include <rtems.h> > + > +const char rtems_test_name[] = "SMPSTRONGAPA 2"; > + > +#define CPU_COUNT 3 > + > +#define TASK_COUNT 4 > + > +#define P(i) (UINT32_C(2) + i) > + > +#define ALL ((UINT32_C(1) << CPU_COUNT) - 1) > + > +#define A(cpu0, cpu1, cpu2) ((cpu2 << 2) | (cpu1 << 1) | cpu0) > + > +typedef enum { > + T0, > + T1, > + T2, > + T3, > + IDLE > +} task_index; > + > +typedef struct { > + enum { > + KIND_RESET, > + KIND_SET_PRIORITY, > + KIND_SET_AFFINITY, > + KIND_BLOCK, > + KIND_UNBLOCK > + } kind; > + > + task_index index; > + > + struct { > + rtems_task_priority priority; > + uint32_t cpu_set; > + } data; > + > + uint8_t expected_cpu_allocations[CPU_COUNT]; > +} test_action; > + > +typedef struct { > + rtems_id timer_id; > + rtems_id master_id; > + rtems_id task_ids[TASK_COUNT]; > + size_t action_index; > +} test_context; > + > +#define RESET \ > + { \ > + KIND_RESET, \ > + 0, \ > + { 0 }, \ > + { IDLE, IDLE, IDLE} \ > + } > + > +#define SET_PRIORITY(index, prio, cpu0, cpu1, cpu2) \ > + { \ > + KIND_SET_PRIORITY, \ > + index, \ > + { .priority = prio }, \ > + { cpu0, cpu1, cpu2 } \ > + } > + > +#define SET_AFFINITY(index, aff, cpu0, cpu1, cpu2) \ > + { \ > + KIND_SET_AFFINITY, \ > + index, \ > + { .cpu_set = aff }, \ > + { cpu0, cpu1, cpu2 } \ > + } > + > +#define BLOCK(index, cpu0, cpu1, cpu2) \ > + { \ > + KIND_BLOCK, \ > + index, \ > + { 0 }, \ > + { cpu0, cpu1, cpu2 } \ > + } > + > +#define UNBLOCK(index, cpu0, cpu1, cpu2) \ > + { \ > + KIND_UNBLOCK, \ > + index, \ > + { 0 }, \ > + { cpu0, cpu1, cpu2 } \ > + } > + > +static const test_action test_actions[] = { > + RESET, > + UNBLOCK( T0, T0, IDLE, IDLE), > + UNBLOCK( T1, T0, T1, IDLE), > + UNBLOCK( T2, T0, T1, T2), > + UNBLOCK( T3, T0, T1, T2), > + SET_PRIORITY( T0, P(0), T0, T1, T2), > + SET_PRIORITY( T1, P(1), T0, T1, T2), > + SET_PRIORITY( T3, P(3), T0, T1, T2), > + /* > + * Introduce Task 2 intially with lowest priority to imitate late > arrival > + */ > + SET_PRIORITY( T2, P(4), T0, T1, T3), > + SET_AFFINITY( T0, ALL, T0, T1, T3), > + SET_AFFINITY( T1, A(0, 1, 1), T0, T1, T3), > + SET_AFFINITY( T2, A(1, 0, 0), T0, T1, T3), > + SET_AFFINITY( T3, A(0, 1, 1), T0, T1, T3), > + /* > + * Show that higher priority task gets dislodged from its processor > + */ > + SET_PRIORITY( T2, P(2), T2, T0, T1), > + RESET > +}; > + > +static test_context test_instance; > + > +static void set_priority(rtems_id id, rtems_task_priority prio) > +{ > + rtems_status_code sc; > + > + sc = rtems_task_set_priority(id, prio, &prio); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > +} > + > +static void set_affinity(rtems_id id, uint32_t cpu_set_32) > +{ > + rtems_status_code sc; > + cpu_set_t cpu_set; > + size_t i; > + > + CPU_ZERO(&cpu_set); > + > + for (i = 0; i < CPU_COUNT; ++i) { > + if ((cpu_set_32 & (UINT32_C(1) << i)) != 0) { > + CPU_SET(i, &cpu_set); > + } > + } > + > + sc = rtems_task_set_affinity(id, sizeof(cpu_set), &cpu_set); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > +} > + > +static void reset(test_context *ctx) > +{ > + rtems_status_code sc; > + size_t i; > + > + for (i = CPU_COUNT; i < TASK_COUNT; ++i) { > + set_priority(ctx->task_ids[i], P(i)); > + set_affinity(ctx->task_ids[i], ALL); > + > + sc = rtems_task_suspend(ctx->task_ids[i]); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL || sc == > RTEMS_ALREADY_SUSPENDED); > + } > + > + for (i = 0; i < CPU_COUNT; ++i) { > + set_priority(ctx->task_ids[i], P(i)); > + > + sc = rtems_task_resume(ctx->task_ids[i]); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL || sc == > RTEMS_INCORRECT_STATE); > + } > + > + /* Order the idle threads explicitly */ > + for (i = 0; i < CPU_COUNT; ++i) { > + const Per_CPU_Control *c; > + const Thread_Control *h; > + > + c = _Per_CPU_Get_by_index(CPU_COUNT - 1 - i); > + h = c->heir; > + > + sc = rtems_task_suspend(h->Object.id); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + } > +} > + > +static void check_cpu_allocations(test_context *ctx, const test_action > *action) > +{ > + size_t i; > + > + for (i = 0; i < CPU_COUNT; ++i) { > + task_index e; > + const Per_CPU_Control *c; > + const Thread_Control *h; > + > + e = action->expected_cpu_allocations[i]; > + c = _Per_CPU_Get_by_index(i); > + h = c->heir; > + > + if (e != IDLE) { > + rtems_test_assert(h->Object.id == ctx->task_ids[e]); > + } else { > + rtems_test_assert(h->is_idle); > + } > + } > +} > + > +/* > + * Use a timer to execute the actions, since it runs with thread > dispatching > + * disabled. This is necessary to check the expected processor > allocations. > + */ > +static void timer(rtems_id id, void *arg) > +{ > + test_context *ctx; > + rtems_status_code sc; > + size_t i; > + > + ctx = arg; > + i = ctx->action_index; > + > + if (i == 0) { > + sc = rtems_task_suspend(ctx->master_id); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + } > + > + if (i < RTEMS_ARRAY_SIZE(test_actions)) { > + const test_action *action = &test_actions[i]; > + rtems_id task; > + > + ctx->action_index = i + 1; > + > + task = ctx->task_ids[action->index]; > + > + switch (action->kind) { > + case KIND_SET_PRIORITY: > + set_priority(task, action->data.priority); > + break; > + case KIND_SET_AFFINITY: > + set_affinity(task, action->data.cpu_set); > + break; > + case KIND_BLOCK: > + sc = rtems_task_suspend(task); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + break; > + case KIND_UNBLOCK: > + sc = rtems_task_resume(task); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + break; > + default: > + rtems_test_assert(action->kind == KIND_RESET); > + reset(ctx); > + break; > + } > + > + check_cpu_allocations(ctx, action); > + > + sc = rtems_timer_reset(id); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + } else { > + sc = rtems_task_resume(ctx->master_id); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + sc = rtems_event_transient_send(ctx->master_id); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + } > +} > + > +static void do_nothing_task(rtems_task_argument arg) > +{ > + (void) arg; > + > + while (true) { > + /* Do nothing */ > + } > +} > + > +static void test(void) > +{ > + test_context *ctx; > + rtems_status_code sc; > + size_t i; > + > + ctx = &test_instance; > + > + ctx->master_id = rtems_task_self(); > + > + for (i = 0; i < TASK_COUNT; ++i) { > + sc = rtems_task_create( > + rtems_build_name(' ', ' ', 'T', '0' + i), > + P(i), > + RTEMS_MINIMUM_STACK_SIZE, > + RTEMS_DEFAULT_MODES, > + RTEMS_DEFAULT_ATTRIBUTES, > + &ctx->task_ids[i] > + ); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + sc = rtems_task_start(ctx->task_ids[i], do_nothing_task, 0); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + } > + > + sc = rtems_timer_create( > + rtems_build_name('A', 'C', 'T', 'N'), > + &ctx->timer_id > + ); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + sc = rtems_timer_fire_after(ctx->timer_id, 1, timer, ctx); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + > + for (i = 0; i < TASK_COUNT; ++i) { > + sc = rtems_task_delete(ctx->task_ids[i]); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > + } > + > + sc = rtems_timer_delete(ctx->timer_id); > + rtems_test_assert(sc == RTEMS_SUCCESSFUL); > +} > + > +static void Init(rtems_task_argument arg) > +{ > + TEST_BEGIN(); > + > + if (rtems_scheduler_get_processor_maximum() == CPU_COUNT) { > + test(); > + } else { > + puts("warning: wrong processor count to run the test"); > + } > + > + TEST_END(); > + rtems_test_exit(0); > +} > + > +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 > + > +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER > +#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER > + > +#define CONFIGURE_MAXIMUM_TASKS (1 + TASK_COUNT) > +#define CONFIGURE_MAXIMUM_TIMERS 1 > + > +#define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT > + > +#define CONFIGURE_SCHEDULER_STRONG_APA > + > +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION > + > +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE > + > +#define CONFIGURE_INIT > + > +#include <rtems/confdefs.h> > diff --git a/testsuites/smptests/smpstrongapa02/smpstrongapa02.doc > b/testsuites/smptests/smpstrongapa02/smpstrongapa02.doc > new file mode 100644 > index 0000000000..c593e1474a > --- /dev/null > +++ b/testsuites/smptests/smpstrongapa02/smpstrongapa02.doc > @@ -0,0 +1,26 @@ > +This file describes the directives and concepts tested by this test set. > + > +test set name: smpstrongapa02 > + > +directives: > + > + - _Scheduler_strong_APA_Get_highest_ready() > + - _Scheduler_strong_APA_Get_lowest_ready() > + - _Scheduler_strong_APA_Set_affinity() > + etc > + > +concepts: > + > + A testsuite that would only execute efficiently > + (task finish within the deadline if the task set is schedulable) > + on the Strong APA scheduler but not on the SMP EDF Scheduler or > + any other SMP scheduler not supporting the dislodging of tasks > + based on affinity as described by Bradenburg et. al in : > + > + Cerqueira, Felipe & Gujarati, Arpan & Brandenburg, Bjorn. (2015). > + Linux's Processor Affinity API, Refined: Shifting Real-Time Tasks > + Towards Higher Schedulability. > + Proceedings - Real-Time Systems Symposium. 2015. 249-259. > + 10.1109/RTSS.2014.29 > + > + > diff --git a/testsuites/smptests/smpstrongapa02/smpstrongapa02.scn > b/testsuites/smptests/smpstrongapa02/smpstrongapa02.scn > new file mode 100644 > index 0000000000..f88b160cad > --- /dev/null > +++ b/testsuites/smptests/smpstrongapa02/smpstrongapa02.scn > @@ -0,0 +1,2 @@ > +*** BEGIN OF TEST SMPSTRONGAPA 2 *** > +*** END OF TEST SMPSTRONGAPA 2 *** > -- > 2.17.1 > >
_______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel