diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2021-09-28 14:38:27 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2021-09-29 08:01:06 +0200 |
commit | fc13d6933a0d9a6ec15c73e0f81920d82e20ce95 (patch) | |
tree | ed45c78001352a3085140e06f1193adbdf0264cf | |
parent | modules: Update rtems (diff) | |
download | rtems-central-fc13d6933a0d9a6ec15c73e0f81920d82e20ce95.tar.bz2 |
spec: Specify scheduler helping detail
-rw-r--r-- | spec/score/thread/req/suspended-helping.yml | 15 | ||||
-rw-r--r-- | spec/score/thread/val/smp.yml | 232 |
2 files changed, 217 insertions, 30 deletions
diff --git a/spec/score/thread/req/suspended-helping.yml b/spec/score/thread/req/suspended-helping.yml new file mode 100644 index 00000000..ab6de611 --- /dev/null +++ b/spec/score/thread/req/suspended-helping.yml @@ -0,0 +1,15 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: RTEMS_SMP +links: +- role: requirement-refinement + uid: ../if/group +functional-type: function +rationale: | + This is an performance optimization. +references: [] +requirement-type: functional +text: | + While a thread is suspended, the thread shall not reconsider help requests. +type: requirement diff --git a/spec/score/thread/val/smp.yml b/spec/score/thread/val/smp.yml index c88ef776..51bac130 100644 --- a/spec/score/thread/val/smp.yml +++ b/spec/score/thread/val/smp.yml @@ -8,24 +8,16 @@ test-actions: Create three worker threads and a mutex. Use the mutex and the worker to move to a helping scheduler. action-code: | - rtems_status_code sc; - Per_CPU_Control *cpu_self; - Thread_Control *executing; + Per_CPU_Control*cpu_self; + Thread_Control *executing; executing = _Thread_Get_executing(); - SetSelfPriority( PRIO_NORMAL ); ctx->counter = 0; - sc = rtems_scheduler_ident( TEST_SCHEDULER_A_NAME, &ctx->scheduler_a_id ); - T_rsc_success( sc ); - - sc = rtems_scheduler_ident( TEST_SCHEDULER_B_NAME, &ctx->scheduler_b_id ); - T_rsc_success( sc ); - ctx->mutex_id = CreateMutex(); ctx->worker_a_id = CreateTask( "WRKA", PRIO_NORMAL ); - SetScheduler( ctx->worker_a_id, ctx->scheduler_b_id, PRIO_NORMAL ); + SetScheduler( ctx->worker_a_id, SCHEDULER_B_ID, PRIO_NORMAL ); StartTask( ctx->worker_a_id, WorkerTask, ctx ); ctx->worker_b_id = CreateTask( "WRKB", PRIO_HIGH ); @@ -64,7 +56,7 @@ test-actions: shows that the pinning of the runner thread is maintained. code: | ctx->busy = false; - SetScheduler( ctx->worker_b_id, ctx->scheduler_b_id, PRIO_HIGH ); + SetScheduler( ctx->worker_b_id, SCHEDULER_B_ID, PRIO_HIGH ); SendEvents( ctx->worker_b_id, EVENT_LET_WORKER_C_COUNT ); T_eq_u32( rtems_scheduler_get_processor(), 1 ); @@ -110,33 +102,126 @@ test-actions: - brief: | Make sure the worker released the mutex. code: | - SetSelfScheduler( ctx->scheduler_b_id, PRIO_LOW ); - SetSelfScheduler( ctx->scheduler_a_id, PRIO_NORMAL ); + SetSelfScheduler( SCHEDULER_B_ID, PRIO_LOW ); + SetSelfScheduler( SCHEDULER_A_ID, PRIO_NORMAL ); + links: [] + - brief: | + Clean up all used resources. + code: | + DeleteTask( ctx->worker_a_id ); + DeleteTask( ctx->worker_b_id ); + DeleteTask( ctx->worker_c_id ); + DeleteMutex( ctx->mutex_id ); + links: [] + links: [] +- action-brief: | + Create three worker threads and a mutex. Use the mutex and the worker to + check that a suspended thread does not reconsider help requests. + action-code: | + T_scheduler_log_10 scheduler_log; + size_t index; + const T_scheduler_event *event; + + _SMP_barrier_Control_initialize( &ctx->barrier ); + _SMP_barrier_State_initialize( &ctx->barrier_state ); + + ctx->counter = 0; + ctx->mutex_id = CreateMutex(); + + ctx->worker_a_id = CreateTask( "WRKA", PRIO_NORMAL ); + SetScheduler( ctx->worker_a_id, SCHEDULER_B_ID, PRIO_NORMAL ); + StartTask( ctx->worker_a_id, WorkerTask, ctx ); + + ctx->worker_b_id = CreateTask( "WRKB", PRIO_HIGH ); + StartTask( ctx->worker_b_id, WorkerTask, ctx ); + + ctx->worker_c_id = CreateTask( "WRKC", PRIO_NORMAL ); + SetScheduler( ctx->worker_c_id, SCHEDULER_B_ID, PRIO_HIGH ); + StartTask( ctx->worker_c_id, WorkerTask, ctx ); + checks: + - brief: | + Let worker B help worker A through the mutex. Preempt worker A. Delay + the thread switch to worker A. + code: | + ctx->busy = true; + SendEvents( + ctx->worker_a_id, + EVENT_OBTAIN | EVENT_COUNT_EARLY | EVENT_BUSY | EVENT_COUNT + ); + WaitForCounter( ctx, 1 ); + + SendEvents( ctx->worker_b_id, EVENT_OBTAIN ); + SetPriority( ctx->worker_b_id, PRIO_LOW ); + SendEvents( ctx->worker_c_id, EVENT_SET_TASK_SWITCH_EXTENSION ); + + /* B0 */ + _SMP_barrier_Wait( &ctx->barrier, &ctx->barrier_state, 2 ); + links: [] + - brief: | + Suspend worker A and let it wait on its thread state lock. Check that + worker A did not reconsider help requests. + code: | + T_scheduler_record_10( &scheduler_log ); + T_scheduler_set_event_handler( SchedulerBlock, ctx ); + SuspendTask( ctx->worker_a_id ); + WaitForExecutionStop( ctx->worker_a_id ); + T_scheduler_record( NULL ); + T_eq_sz( scheduler_log.header.recorded, 2 ); + index = 0; + event = T_scheduler_next_any( &scheduler_log.header, &index ); + T_eq_int( event->operation, T_SCHEDULER_BLOCK ); + event = T_scheduler_next_any( &scheduler_log.header, &index ); + T_eq_int( event->operation, T_SCHEDULER_WITHDRAW_NODE ); + event = T_scheduler_next_any( &scheduler_log.header, &index ); + T_eq_ptr( event, &T_scheduler_event_null ); + SetTaskSwitchExtension( NULL ); + links: + - role: validation + uid: ../req/suspended-helping + - brief: | + Resume worker A. Check that worker A did reconsider help requests after + the thread dispatch. + code: | + T_scheduler_record_10( &scheduler_log ); + ResumeTask( ctx->worker_a_id ); + ctx->busy = false; + WaitForCounter( ctx, 2 ); + WaitForExecutionStop( ctx->worker_a_id ); + T_scheduler_record( NULL ); + T_eq_sz( scheduler_log.header.recorded, 5 ); + index = 0; + event = T_scheduler_next_any( &scheduler_log.header, &index ); + T_eq_int( event->operation, T_SCHEDULER_UNBLOCK ); + event = T_scheduler_next_any( &scheduler_log.header, &index ); + T_eq_int( event->operation, T_SCHEDULER_RECONSIDER_HELP_REQUEST ); + event = T_scheduler_next_any( &scheduler_log.header, &index ); + T_eq_int( event->operation, T_SCHEDULER_RECONSIDER_HELP_REQUEST ); + event = T_scheduler_next_any( &scheduler_log.header, &index ); + T_eq_int( event->operation, T_SCHEDULER_BLOCK ); + event = T_scheduler_next_any( &scheduler_log.header, &index ); + T_eq_int( event->operation, T_SCHEDULER_WITHDRAW_NODE ); + event = T_scheduler_next_any( &scheduler_log.header, &index ); + T_eq_ptr( event, &T_scheduler_event_null ); links: [] - brief: | Clean up all used resources. code: | + SendEvents( ctx->worker_a_id, EVENT_RELEASE | EVENT_COUNT ); + WaitForCounter( ctx, 3 ); + + SetPriority( ctx->worker_b_id, PRIO_HIGH ); + SendEvents( ctx->worker_b_id, EVENT_RELEASE ); + DeleteTask( ctx->worker_a_id ); DeleteTask( ctx->worker_b_id ); DeleteTask( ctx->worker_c_id ); DeleteMutex( ctx->mutex_id ); - RestoreRunnerPriority(); links: [] links: [] test-brief: | Tests SMP-specific thread behaviour. test-context: - brief: | - This member contains the scheduler A identifier. - description: null - member: | - rtems_id scheduler_a_id -- brief: | - This member contains the scheduler B identifier. - description: null - member: | - rtems_id scheduler_b_id -- brief: | This member contains the worker A identifier. description: null member: | @@ -166,16 +251,32 @@ test-context: description: null member: | volatile uint32_t counter +- brief: | + This member contains the barrier to synchronize the runner and the workers. + description: null + member: | + SMP_barrier_Control barrier +- brief: | + This member contains the barrier state for the runner processor. + description: null + member: | + SMP_barrier_State barrier_state test-context-support: null test-description: null test-header: null test-includes: - rtems.h +- rtems/test-scheduler.h +- rtems/score/smpbarrier.h - rtems/score/threadimpl.h test-local-includes: - ts-config.h - tx-support.h -test-setup: null +test-setup: + brief: null + code: | + SetSelfPriority( PRIO_NORMAL ); + description: null test-stop: null test-support: | typedef ${.:/test-context-type} Context; @@ -183,11 +284,37 @@ test-support: | typedef enum { EVENT_OBTAIN = RTEMS_EVENT_0, EVENT_RELEASE = RTEMS_EVENT_1, - EVENT_BUSY = RTEMS_EVENT_2, - EVENT_COUNT = RTEMS_EVENT_3, - EVENT_LET_WORKER_C_COUNT = RTEMS_EVENT_4 + EVENT_COUNT_EARLY = RTEMS_EVENT_2, + EVENT_BUSY = RTEMS_EVENT_3, + EVENT_COUNT = RTEMS_EVENT_4, + EVENT_LET_WORKER_C_COUNT = RTEMS_EVENT_5, + EVENT_SET_TASK_SWITCH_EXTENSION = RTEMS_EVENT_6 } Event; + static void TaskSwitchExtension( rtems_tcb *executing, rtems_tcb *heir ) + { + Context *ctx; + Thread_Control *thread; + + (void) executing; + (void) heir; + + ctx = T_fixture_context(); + thread = GetThread( ctx->worker_a_id ); + + if ( thread == heir ) { + SMP_barrier_State state; + + _SMP_barrier_State_initialize( &state ); + + /* B0 */ + _SMP_barrier_Wait( &ctx->barrier, &state, 2 ); + + /* B1 */ + _SMP_barrier_Wait( &ctx->barrier, &state, 2 ); + } + } + static void WorkerTask( rtems_task_argument arg ) { Context *ctx; @@ -207,6 +334,10 @@ test-support: | ReleaseMutex( ctx->mutex_id ); } + if ( ( events & EVENT_COUNT_EARLY ) != 0 ) { + ++ctx->counter; + } + if ( ( events & EVENT_BUSY ) != 0 ) { while ( ctx->busy ) { /* Do nothing */ @@ -227,6 +358,36 @@ test-support: | /* Wait */ } } + + if ( ( events & EVENT_SET_TASK_SWITCH_EXTENSION ) != 0 ) { + SetTaskSwitchExtension( TaskSwitchExtension ); + } + } + } + + static void SchedulerBlock( + void *arg, + const T_scheduler_event *event, + T_scheduler_when when + ) + { + Context *ctx; + + ctx = arg; + + if ( + when == T_SCHEDULER_BEFORE && + event->operation == T_SCHEDULER_BLOCK + ) { + Thread_Control *thread; + + T_scheduler_set_event_handler( NULL, NULL ); + + /* B1 */ + _SMP_barrier_Wait( &ctx->barrier, &ctx->barrier_state, 2 ); + + thread = GetThread( ctx->worker_a_id ); + TicketLockWaitForOthers( &thread->Join_queue.Queue.Lock, 1 ); } } @@ -245,6 +406,17 @@ test-support: | thread = arg; ResumeTask( thread->Object.id ); } + + static void WaitForCounter( const Context *ctx, uint32_t expected ) + { + while ( ctx->counter != expected ) { + /* Wait */ + } + } test-target: testsuites/validation/tc-score-smp-thread.c -test-teardown: null +test-teardown: + brief: null + code: | + RestoreRunnerPriority(); + description: null type: test-case |