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