score: Add simple affinity support to EDF SMP

Update #3059.
This commit is contained in:
Sebastian Huber
2017-07-10 07:49:36 +02:00
parent d19dc071a2
commit 34487537ce
22 changed files with 1227 additions and 123 deletions
+2 -1
View File
@@ -992,7 +992,8 @@ extern rtems_initialization_tasks_table Initialization_tasks[];
#if !defined(CONFIGURE_SCHEDULER_CONTROLS)
/** Configure the context needed by the scheduler instance */
#define CONFIGURE_SCHEDULER_CONTEXT RTEMS_SCHEDULER_CONTEXT_EDF_SMP(dflt)
#define CONFIGURE_SCHEDULER_CONTEXT \
RTEMS_SCHEDULER_CONTEXT_EDF_SMP(dflt, CONFIGURE_MAXIMUM_PROCESSORS)
/** Configure the controls for this scheduler instance */
#define CONFIGURE_SCHEDULER_CONTROLS \
+6 -3
View File
@@ -99,12 +99,15 @@
#define RTEMS_SCHEDULER_CONTEXT_EDF_SMP_NAME( name ) \
RTEMS_SCHEDULER_CONTEXT_NAME( EDF_SMP_ ## name )
#define RTEMS_SCHEDULER_CONTEXT_EDF_SMP( name ) \
static Scheduler_EDF_SMP_Context RTEMS_SCHEDULER_CONTEXT_EDF_SMP_NAME( name )
#define RTEMS_SCHEDULER_CONTEXT_EDF_SMP( name, max_cpu_count ) \
static struct { \
Scheduler_EDF_SMP_Context Base; \
Scheduler_EDF_SMP_Ready_queue Ready[ ( max_cpu_count ) + 1 ]; \
} RTEMS_SCHEDULER_CONTEXT_EDF_SMP_NAME( name )
#define RTEMS_SCHEDULER_CONTROL_EDF_SMP( name, obj_name ) \
{ \
&RTEMS_SCHEDULER_CONTEXT_EDF_SMP_NAME( name ).Base.Base, \
&RTEMS_SCHEDULER_CONTEXT_EDF_SMP_NAME( name ).Base.Base.Base, \
SCHEDULER_EDF_SMP_ENTRY_POINTS, \
SCHEDULER_EDF_MAXIMUM_PRIORITY, \
( obj_name ) \
@@ -34,13 +34,63 @@ extern "C" {
*/
typedef struct {
Scheduler_SMP_Context Base;
RBTree_Control Ready;
} Scheduler_EDF_SMP_Context;
Scheduler_SMP_Node Base;
/**
* @brief Generation number to ensure FIFO/LIFO order for threads of the same
* priority across different ready queues.
*/
int64_t generation;
/**
* @brief The ready queue index depending on the processor affinity of the thread.
*
* The ready queue index zero is used for threads with a one-to-all thread
* processor affinity. Threads with a one-to-one processor affinity use the
* processor index plus one as the ready queue index.
*/
uint32_t ready_queue_index;
} Scheduler_EDF_SMP_Node;
typedef struct {
Scheduler_SMP_Node Base;
} Scheduler_EDF_SMP_Node;
/**
* @brief Chain node for Scheduler_SMP_Context::Affine_queues.
*/
Chain_Node Node;
/**
* @brief The ready threads of the corresponding affinity.
*/
RBTree_Control Queue;
/**
* @brief The scheduled thread of the corresponding processor.
*/
Scheduler_EDF_SMP_Node *scheduled;
} Scheduler_EDF_SMP_Ready_queue;
typedef struct {
Scheduler_SMP_Context Base;
/**
* @brief Current generation for FIFO/LIFO ordering.
*/
int64_t generations[ 2 ];
/**
* @brief Chain of ready queues with affine threads to determine the highest
* priority ready thread.
*/
Chain_Control Affine_queues;
/**
* @brief A table with ready queues.
*
* The index zero queue is used for threads with a one-to-all processor
* affinity. Index one corresponds to processor index zero, and so on.
*/
Scheduler_EDF_SMP_Ready_queue Ready[ RTEMS_ZERO_LENGTH_ARRAY ];
} Scheduler_EDF_SMP_Context;
#define SCHEDULER_EDF_SMP_ENTRY_POINTS \
{ \
@@ -62,8 +112,8 @@ typedef struct {
_Scheduler_EDF_Release_job, \
_Scheduler_EDF_Cancel_job, \
_Scheduler_default_Tick, \
_Scheduler_SMP_Start_idle \
SCHEDULER_OPERATION_DEFAULT_GET_SET_AFFINITY \
_Scheduler_EDF_SMP_Start_idle, \
_Scheduler_EDF_SMP_Set_affinity \
}
void _Scheduler_EDF_SMP_Initialize( const Scheduler_Control *scheduler );
@@ -128,6 +178,19 @@ void _Scheduler_EDF_SMP_Yield(
Scheduler_Node *node
);
void _Scheduler_EDF_SMP_Start_idle(
const Scheduler_Control *scheduler,
Thread_Control *idle,
struct Per_CPU_Control *cpu
);
bool _Scheduler_EDF_SMP_Set_affinity(
const Scheduler_Control *scheduler,
Thread_Control *thread,
Scheduler_Node *node,
const Processor_mask *affinity
);
/** @} */
#ifdef __cplusplus
@@ -7,7 +7,7 @@
*/
/*
* Copyright (c) 2013, 2016 embedded brains GmbH. All rights reserved.
* Copyright (c) 2013, 2017 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
@@ -317,6 +317,12 @@ typedef void ( *Scheduler_SMP_Update )(
Priority_Control new_priority
);
typedef void ( *Scheduler_SMP_Set_affinity )(
Scheduler_Context *context,
Scheduler_Node *node,
void *arg
);
typedef bool ( *Scheduler_SMP_Enqueue )(
Scheduler_Context *context,
Scheduler_Node *node_to_enqueue
@@ -329,6 +335,23 @@ typedef void ( *Scheduler_SMP_Allocate_processor )(
Per_CPU_Control *victim_cpu
);
typedef void ( *Scheduler_SMP_Register_idle )(
Scheduler_Context *context,
Scheduler_Node *idle,
Per_CPU_Control *cpu
);
static inline void _Scheduler_SMP_Do_nothing_register_idle(
Scheduler_Context *context,
Scheduler_Node *idle,
Per_CPU_Control *cpu
)
{
(void) context;
(void) idle;
(void) cpu;
}
static inline bool _Scheduler_SMP_Insert_priority_lifo_order(
const Chain_Node *to_insert,
const Chain_Node *next
@@ -903,6 +926,50 @@ static inline void _Scheduler_SMP_Schedule_highest_ready(
} while ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK );
}
static inline void _Scheduler_SMP_Preempt_and_schedule_highest_ready(
Scheduler_Context *context,
Scheduler_Node *victim,
Per_CPU_Control *victim_cpu,
Scheduler_SMP_Extract extract_from_ready,
Scheduler_SMP_Get_highest_ready get_highest_ready,
Scheduler_SMP_Move move_from_ready_to_scheduled,
Scheduler_SMP_Allocate_processor allocate_processor
)
{
Scheduler_Try_to_schedule_action action;
do {
Scheduler_Node *highest_ready = ( *get_highest_ready )( context, victim );
action = _Scheduler_Try_to_schedule_node(
context,
highest_ready,
NULL,
_Scheduler_SMP_Get_idle_thread
);
if ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE ) {
_Scheduler_SMP_Preempt(
context,
highest_ready,
victim,
allocate_processor
);
( *move_from_ready_to_scheduled )( context, highest_ready );
} else {
_Assert( action == SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK );
_Scheduler_SMP_Node_change_state(
highest_ready,
SCHEDULER_SMP_NODE_BLOCKED
);
( *extract_from_ready )( context, highest_ready );
}
} while ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK );
}
/**
* @brief Blocks a thread.
*
@@ -1274,11 +1341,34 @@ static inline void _Scheduler_SMP_Withdraw_node(
}
}
static inline void _Scheduler_SMP_Do_start_idle(
Scheduler_Context *context,
Thread_Control *idle,
Per_CPU_Control *cpu,
Scheduler_SMP_Register_idle register_idle
)
{
Scheduler_SMP_Context *self;
Scheduler_SMP_Node *node;
self = _Scheduler_SMP_Get_self( context );
node = _Scheduler_SMP_Thread_get_node( idle );
_Scheduler_Thread_change_state( idle, THREAD_SCHEDULER_SCHEDULED );
node->state = SCHEDULER_SMP_NODE_SCHEDULED;
_Thread_Set_CPU( idle, cpu );
( *register_idle )( context, &node->Base, cpu );
_Chain_Append_unprotected( &self->Scheduled, &node->Base.Node.Chain );
_Scheduler_SMP_Release_idle_thread( &self->Base, idle );
}
static inline void _Scheduler_SMP_Add_processor(
Scheduler_Context *context,
Thread_Control *idle,
Scheduler_SMP_Has_ready has_ready,
Scheduler_SMP_Enqueue enqueue_scheduled_fifo
Scheduler_Context *context,
Thread_Control *idle,
Scheduler_SMP_Has_ready has_ready,
Scheduler_SMP_Enqueue enqueue_scheduled_fifo,
Scheduler_SMP_Register_idle register_idle
)
{
Scheduler_SMP_Context *self;
@@ -1289,6 +1379,7 @@ static inline void _Scheduler_SMP_Add_processor(
_Scheduler_SMP_Release_idle_thread( &self->Base, idle );
node = _Thread_Scheduler_get_home_node( idle );
_Scheduler_SMP_Node_change_state( node, SCHEDULER_SMP_NODE_SCHEDULED );
( *register_idle )( context, node, _Thread_Get_CPU( idle ) );
if ( ( *has_ready )( &self->Base ) ) {
( *enqueue_scheduled_fifo )( &self->Base, node );
@@ -1355,6 +1446,45 @@ static inline Thread_Control *_Scheduler_SMP_Remove_processor(
return idle;
}
static inline void _Scheduler_SMP_Set_affinity(
Scheduler_Context *context,
Thread_Control *thread,
Scheduler_Node *node,
void *arg,
Scheduler_SMP_Set_affinity set_affinity,
Scheduler_SMP_Extract extract_from_ready,
Scheduler_SMP_Get_highest_ready get_highest_ready,
Scheduler_SMP_Move move_from_ready_to_scheduled,
Scheduler_SMP_Enqueue enqueue_fifo,
Scheduler_SMP_Allocate_processor allocate_processor
)
{
Scheduler_SMP_Node_state node_state;
node_state = _Scheduler_SMP_Node_state( node );
if ( node_state == SCHEDULER_SMP_NODE_SCHEDULED ) {
_Scheduler_SMP_Extract_from_scheduled( node );
_Scheduler_SMP_Preempt_and_schedule_highest_ready(
context,
node,
_Thread_Get_CPU( thread ),
extract_from_ready,
get_highest_ready,
move_from_ready_to_scheduled,
allocate_processor
);
( *set_affinity )( context, node, arg );
( *enqueue_fifo )( context, node );
} else if ( node_state == SCHEDULER_SMP_NODE_READY ) {
( *extract_from_ready )( context, node );
( *set_affinity )( context, node, arg );
( *enqueue_fifo )( context, node );
} else {
( *set_affinity )( context, node, arg );
}
}
/** @} */
#ifdef __cplusplus
File diff suppressed because it is too large Load Diff
@@ -579,7 +579,8 @@ void _Scheduler_priority_affinity_SMP_Add_processor(
context,
idle,
_Scheduler_priority_SMP_Has_ready,
_Scheduler_priority_affinity_SMP_Enqueue_scheduled_fifo
_Scheduler_priority_affinity_SMP_Enqueue_scheduled_fifo,
_Scheduler_SMP_Do_nothing_register_idle
);
}
+2 -1
View File
@@ -323,7 +323,8 @@ void _Scheduler_priority_SMP_Add_processor(
context,
idle,
_Scheduler_priority_SMP_Has_ready,
_Scheduler_priority_SMP_Enqueue_scheduled_fifo
_Scheduler_priority_SMP_Enqueue_scheduled_fifo,
_Scheduler_SMP_Do_nothing_register_idle
);
}
+2 -1
View File
@@ -398,7 +398,8 @@ void _Scheduler_simple_SMP_Add_processor(
context,
idle,
_Scheduler_simple_SMP_Has_ready,
_Scheduler_simple_SMP_Enqueue_scheduled_fifo
_Scheduler_simple_SMP_Enqueue_scheduled_fifo,
_Scheduler_SMP_Do_nothing_register_idle
);
}
+8 -14
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2016 embedded brains GmbH.
* Copyright (c) 2013, 2017 embedded brains GmbH.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -18,18 +18,12 @@ void _Scheduler_SMP_Start_idle(
Per_CPU_Control *cpu
)
{
Scheduler_Context *context;
Scheduler_SMP_Context *self;
Scheduler_SMP_Node *node;
Scheduler_Context *context = _Scheduler_Get_context( scheduler );
context = _Scheduler_Get_context( scheduler );
self = _Scheduler_SMP_Get_self( context );
node = _Scheduler_SMP_Thread_get_node( idle );
_Scheduler_Thread_change_state( idle, THREAD_SCHEDULER_SCHEDULED );
node->state = SCHEDULER_SMP_NODE_SCHEDULED;
_Thread_Set_CPU( idle, cpu );
_Chain_Append_unprotected( &self->Scheduled, &node->Base.Node.Chain );
_Scheduler_SMP_Release_idle_thread( &self->Base, idle );
_Scheduler_SMP_Do_start_idle(
context,
idle,
cpu,
_Scheduler_SMP_Do_nothing_register_idle
);
}
+2 -1
View File
@@ -457,7 +457,8 @@ void _Scheduler_strong_APA_Add_processor(
context,
idle,
_Scheduler_strong_APA_Has_ready,
_Scheduler_strong_APA_Enqueue_scheduled_fifo
_Scheduler_strong_APA_Enqueue_scheduled_fifo,
_Scheduler_SMP_Do_nothing_register_idle
);
}
+2
View File
@@ -36,6 +36,8 @@ _SUBDIRS += smpschedaffinity03
_SUBDIRS += smpschedaffinity04
_SUBDIRS += smpschedaffinity05
_SUBDIRS += smpschededf01
_SUBDIRS += smpschededf02
_SUBDIRS += smpschededf03
_SUBDIRS += smpschedsem01
_SUBDIRS += smpscheduler01
_SUBDIRS += smpscheduler02
+2
View File
@@ -91,6 +91,8 @@ smpschedaffinity03/Makefile
smpschedaffinity04/Makefile
smpschedaffinity05/Makefile
smpschededf01/Makefile
smpschededf02/Makefile
smpschededf03/Makefile
smpschedsem01/Makefile
smpscheduler01/Makefile
smpscheduler02/Makefile
+3 -1
View File
@@ -140,11 +140,13 @@ static void Init(rtems_task_argument arg)
#define CONFIGURE_MAXIMUM_TASKS 3
#define CONFIGURE_MAXIMUM_PERIODS 2
#define CONFIGURE_MAXIMUM_PROCESSORS 1
#define CONFIGURE_SCHEDULER_EDF_SMP
#include <rtems/scheduler.h>
RTEMS_SCHEDULER_CONTEXT_EDF_SMP(a);
RTEMS_SCHEDULER_CONTEXT_EDF_SMP(a, CONFIGURE_MAXIMUM_PROCESSORS);
#define CONFIGURE_SCHEDULER_CONTROLS \
RTEMS_SCHEDULER_CONTROL_EDF_SMP(a, rtems_build_name('E', 'D', 'F', ' '))
@@ -0,0 +1,19 @@
rtems_tests_PROGRAMS = smpschededf02
smpschededf02_SOURCES = init.c
dist_rtems_tests_DATA = smpschededf02.scn smpschededf02.doc
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(top_srcdir)/../automake/compile.am
include $(top_srcdir)/../automake/leaf.am
AM_CPPFLAGS += -I$(top_srcdir)/../support/include
LINK_OBJS = $(smpschededf02_OBJECTS)
LINK_LIBS = $(smpschededf02_LDLIBS)
smpschededf02$(EXEEXT): $(smpschededf02_OBJECTS) $(smpschededf02_DEPENDENCIES)
@rm -f smpschededf02$(EXEEXT)
$(make-exe)
include $(top_srcdir)/../automake/local.am
+383
View File
@@ -0,0 +1,383 @@
/*
* Copyright (c) 2016, 2017 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* 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[] = "SMPSCHEDEDF 2";
#define CPU_COUNT 2
#define TASK_COUNT 5
#define P(i) (UINT32_C(2) + i)
#define A(cpu0, cpu1) ((cpu1 << 1) | cpu0)
#define IDLE UINT8_C(255)
#define NAME rtems_build_name('E', 'D', 'F', ' ')
typedef struct {
enum {
KIND_RESET,
KIND_SET_PRIORITY,
KIND_SET_AFFINITY,
KIND_BLOCK,
KIND_UNBLOCK
} kind;
size_t 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 } \
}
#define SET_PRIORITY(index, prio, cpu0, cpu1) \
{ \
KIND_SET_PRIORITY, \
index, \
{ .priority = prio }, \
{ cpu0, cpu1 } \
}
#define SET_AFFINITY(index, aff, cpu0, cpu1) \
{ \
KIND_SET_AFFINITY, \
index, \
{ .cpu_set = aff }, \
{ cpu0, cpu1 } \
}
#define BLOCK(index, cpu0, cpu1) \
{ \
KIND_BLOCK, \
index, \
{ 0 }, \
{ cpu0, cpu1 } \
}
#define UNBLOCK(index, cpu0, cpu1) \
{ \
KIND_UNBLOCK, \
index, \
{ 0 }, \
{ cpu0, cpu1 } \
}
static const test_action test_actions[] = {
RESET,
UNBLOCK( 0, 0, IDLE),
UNBLOCK( 1, 0, 1),
UNBLOCK( 3, 0, 1),
SET_PRIORITY( 1, P(2), 0, 1),
SET_PRIORITY( 3, P(1), 0, 3),
BLOCK( 3, 0, 1),
SET_AFFINITY( 1, A(1, 1), 0, 1),
SET_AFFINITY( 1, A(1, 0), 1, 0),
SET_AFFINITY( 1, A(1, 1), 1, 0),
SET_AFFINITY( 1, A(1, 0), 1, 0),
SET_AFFINITY( 1, A(0, 1), 0, 1),
BLOCK( 0, IDLE, 1),
UNBLOCK( 0, 0, 1),
BLOCK( 1, 0, IDLE),
UNBLOCK( 1, 0, 1),
RESET,
/*
* Show that FIFO order is honoured across all threads of the same priority.
*/
SET_PRIORITY( 1, P(0), IDLE, IDLE),
SET_PRIORITY( 2, P(1), IDLE, IDLE),
SET_PRIORITY( 3, P(1), IDLE, IDLE),
SET_AFFINITY( 3, A(1, 0), IDLE, IDLE),
SET_PRIORITY( 4, P(1), IDLE, IDLE),
SET_AFFINITY( 4, A(1, 0), IDLE, IDLE),
UNBLOCK( 0, 0, IDLE),
UNBLOCK( 1, 0, 1),
UNBLOCK( 2, 0, 1),
UNBLOCK( 3, 0, 1),
UNBLOCK( 4, 0, 1),
BLOCK( 1, 0, 2),
BLOCK( 2, 3, 0),
BLOCK( 3, 4, 0),
RESET,
/*
* Schedule a high priority affine thread directly with a low priority affine
* thread in the corresponding ready queue. In this case we, remove the
* affine ready queue in _Scheduler_EDF_SMP_Allocate_processor().
*/
UNBLOCK( 0, 0, IDLE),
UNBLOCK( 1, 0, 1),
SET_PRIORITY( 1, P(2), 0, 1),
SET_AFFINITY( 3, A(0, 1), 0, 1),
UNBLOCK( 3, 0, 1),
SET_PRIORITY( 2, P(1), 0, 1),
SET_AFFINITY( 2, A(0, 1), 0, 1),
UNBLOCK( 2, 0, 2),
BLOCK( 1, 0, 2),
BLOCK( 2, 0, 3),
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 = 0; i < TASK_COUNT; ++i) {
set_priority(ctx->task_ids[i], P(i));
set_affinity(ctx->task_ids[i], A(1, 1));
}
for (i = CPU_COUNT; i < TASK_COUNT; ++i) {
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) {
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) {
size_t 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(
NAME,
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(NAME, &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_get_processor_count() == 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_CONSOLE_DRIVER
#define CONFIGURE_MAXIMUM_TASKS (1 + TASK_COUNT)
#define CONFIGURE_MAXIMUM_TIMERS 1
#define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT
#define CONFIGURE_SCHEDULER_EDF_SMP
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#define CONFIGURE_INIT
#include <rtems/confdefs.h>
@@ -0,0 +1,11 @@
This file describes the directives and concepts tested by this test set.
test set name: smpschededf02
directives:
TBD
concepts:
TBD
@@ -0,0 +1,19 @@
rtems_tests_PROGRAMS = smpschededf03
smpschededf03_SOURCES = init.c
dist_rtems_tests_DATA = smpschededf03.scn smpschededf03.doc
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(top_srcdir)/../automake/compile.am
include $(top_srcdir)/../automake/leaf.am
AM_CPPFLAGS += -I$(top_srcdir)/../support/include
LINK_OBJS = $(smpschededf03_OBJECTS)
LINK_LIBS = $(smpschededf03_LDLIBS)
smpschededf03$(EXEEXT): $(smpschededf03_OBJECTS) $(smpschededf03_DEPENDENCIES)
@rm -f smpschededf03$(EXEEXT)
$(make-exe)
include $(top_srcdir)/../automake/local.am
+160
View File
@@ -0,0 +1,160 @@
/*
* Copyright (c) 2017 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* 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[] = "SMPSCHEDEDF 3";
#define CPU_COUNT 32
#define TASK_COUNT (3 * CPU_COUNT)
typedef struct {
rtems_id task_ids[TASK_COUNT];
} test_context;
static test_context test_instance;
static void wait_task(rtems_task_argument arg)
{
(void) arg;
while (true) {
rtems_status_code sc;
sc = rtems_task_wake_after(1);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
}
}
static uint32_t simple_random(uint32_t v)
{
v *= 1664525;
v += 1013904223;
return v;
}
static void affinity_task(rtems_task_argument arg)
{
uint32_t v;
uint32_t n;
v = (uint32_t) arg;
n = rtems_get_processor_count();
while (true) {
rtems_status_code sc;
cpu_set_t set;
CPU_ZERO(&set);
CPU_SET((v >> 13) % n, &set);
v = simple_random(v);
sc = rtems_task_set_affinity(RTEMS_SELF, sizeof(set), &set);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
}
}
static void create_and_start_task(
test_context *ctx,
rtems_task_entry entry,
size_t i,
size_t j
)
{
rtems_status_code sc;
j = j * CPU_COUNT + i;
sc = rtems_task_create(
rtems_build_name('E', 'D', 'F', ' '),
i + 2,
RTEMS_MINIMUM_STACK_SIZE,
RTEMS_DEFAULT_MODES,
RTEMS_DEFAULT_ATTRIBUTES,
&ctx->task_ids[j]
);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_task_start(ctx->task_ids[j], entry, j);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
}
static void delete_task(
test_context *ctx,
size_t i,
size_t j
)
{
rtems_status_code sc;
j = j * CPU_COUNT + i;
sc = rtems_task_delete(ctx->task_ids[j]);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
}
static void test(test_context *ctx)
{
rtems_status_code sc;
size_t i;
for (i = 0; i < CPU_COUNT; ++i) {
create_and_start_task(ctx, wait_task, i, 0);
create_and_start_task(ctx, affinity_task, i, 1);
create_and_start_task(ctx, affinity_task, i, 2);
}
sc = rtems_task_wake_after(10 * rtems_clock_get_ticks_per_second());
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
for (i = 0; i < CPU_COUNT; ++i) {
delete_task(ctx, i, 0);
delete_task(ctx, i, 1);
delete_task(ctx, i, 2);
}
}
static void Init(rtems_task_argument arg)
{
TEST_BEGIN();
test(&test_instance);
TEST_END();
rtems_test_exit(0);
}
#define CONFIGURE_MICROSECONDS_PER_TICK 1000
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
#define CONFIGURE_MAXIMUM_TASKS (1 + TASK_COUNT)
#define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT
#define CONFIGURE_SCHEDULER_EDF_SMP
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#define CONFIGURE_INIT
#include <rtems/confdefs.h>
@@ -0,0 +1,12 @@
This file describes the directives and concepts tested by this test set.
test set name: smpschededf03
directives:
- EDF SMP scheduler operations.
concepts:
- Randomized test case to show some stability of simple thread processor
affinity support of the EDF SMP scheduler.
@@ -0,0 +1,2 @@
*** BEGIN OF TEST SMPSCHEDEDF 3 ***
*** END OF TEST SMPSCHEDEDF 3 ***
+1 -1
View File
@@ -32,7 +32,7 @@ const char rtems_test_name[] = "SMPSCHEDULER 7";
#include <rtems/scheduler.h>
RTEMS_SCHEDULER_CONTEXT_EDF_SMP(a);
RTEMS_SCHEDULER_CONTEXT_EDF_SMP(a, CONFIGURE_MAXIMUM_PROCESSORS);
#define CONFIGURE_SCHEDULER_CONTROLS \
RTEMS_SCHEDULER_CONTROL_EDF_SMP( a, rtems_build_name('T', 'E', 'S', 'T'))