[PATCH] Add Strong APA test 02
Richi Dubey
richidubey at gmail.com
Tue Jul 28 13:57:02 UTC 2020
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 <richidubey at 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.
> + *
> + * richidubey at 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
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.rtems.org/pipermail/devel/attachments/20200728/dd923eb1/attachment-0001.html>
More information about the devel
mailing list