score: Add and use _Thread_Do_dispatch()

The _Thread_Dispatch() function is quite complex and the time to set up
and tear down the stack frame is significant.  Split this function into
two parts.  The complex part is now in _Thread_Do_dispatch().  Call
_Thread_Do_dispatch() in _Thread_Enable_dispatch() only if necessary.
This increases the average case performance.

Simplify _Thread_Handler() for SMP configurations.

Update #2273.
This commit is contained in:
Sebastian Huber
2015-03-05 11:36:19 +01:00
parent 6157743d67
commit 222dc77583
4 changed files with 123 additions and 84 deletions
@@ -193,25 +193,39 @@ RTEMS_INLINE_ROUTINE void _Thread_Dispatch_initialization( void )
#endif /* RTEMS_SMP */
/**
* @brief Dispatch thread.
* @brief Performs a thread dispatch if necessary.
*
* This routine is responsible for transferring control of the
* processor from the executing thread to the heir thread. Once the
* heir is running an attempt is made to dispatch any ASRs.
* As part of this process, it is responsible for the following actions:
* + saving the context of the executing thread
* + restoring the context of the heir thread
* + dispatching any signals for the resulting executing thread
* ALTERNATE ENTRY POINTS:
* void _Thread_Enable_dispatch();
* This routine is responsible for transferring control of the processor from
* the executing thread to the heir thread. Once the heir is running an
* attempt is made to run the pending post-switch thread actions.
*
* - INTERRUPT LATENCY:
* + dispatch thread
* + no dispatch thread
* As part of this process, it is responsible for the following actions
* - update timing information of the executing thread,
* - save the context of the executing thread,
* - invokation of the thread switch user extensions,
* - restore the context of the heir thread, and
* - run of pending post-switch thread actions of the resulting executing
* thread.
*
* On entry the thread dispatch level must be equal to zero.
*/
void _Thread_Dispatch( void );
/**
* @brief Performs a thread dispatch on the current processor.
*
* On entry the thread dispatch disable level must be equal to one and
* interrupts must be disabled.
*
* This function assumes that a thread dispatch is necessary.
*
* @param[in] cpu_self The current processor.
* @param[in] level The previous interrupt level.
*
* @see _Thread_Dispatch().
*/
void _Thread_Do_dispatch( Per_CPU_Control *cpu_self, ISR_Level level );
/**
* This routine prevents dispatching.
*/
@@ -228,8 +242,33 @@ RTEMS_INLINE_ROUTINE void _Thread_Disable_dispatch( void )
RTEMS_INLINE_ROUTINE void _Thread_Enable_dispatch_body( void )
{
if ( _Thread_Dispatch_decrement_disable_level() == 0 )
_Thread_Dispatch();
Per_CPU_Control *cpu_self;
uint32_t disable_level;
cpu_self = _Per_CPU_Get();
#if defined( RTEMS_SMP )
_Giant_Release( cpu_self );
#endif
disable_level = cpu_self->thread_dispatch_disable_level;
if ( disable_level == 1 ) {
ISR_Level level;
_ISR_Disable_without_giant( level );
if ( cpu_self->dispatch_necessary ) {
_Thread_Do_dispatch( cpu_self, level );
} else {
cpu_self->thread_dispatch_disable_level = 0;
_Profiling_Thread_dispatch_enable( cpu_self, 0 );
}
_ISR_Enable_without_giant( level );
} else {
cpu_self->thread_dispatch_disable_level = disable_level - 1;
}
}
/**
+34 -30
View File
@@ -60,40 +60,15 @@ static void _Thread_Run_post_switch_actions( Thread_Control *executing )
_Thread_Action_release_and_ISR_enable( cpu_self, level );
}
void _Thread_Dispatch( void )
void _Thread_Do_dispatch( Per_CPU_Control *cpu_self, ISR_Level level )
{
Per_CPU_Control *cpu_self;
Thread_Control *executing;
ISR_Level level;
Thread_Control *executing;
#if defined( RTEMS_SMP )
/*
* On SMP the complete context switch must be atomic with respect to one
* processor. See also _Thread_Handler() since _Context_switch() may branch
* to this function.
*/
_ISR_Disable_without_giant( level );
#endif
_Assert( cpu_self->thread_dispatch_disable_level == 1 );
cpu_self = _Per_CPU_Get();
_Assert( cpu_self->thread_dispatch_disable_level == 0 );
_Profiling_Thread_dispatch_disable( cpu_self, 0 );
cpu_self->thread_dispatch_disable_level = 1;
/*
* Now determine if we need to perform a dispatch on the current CPU.
*/
executing = cpu_self->executing;
#if !defined( RTEMS_SMP )
_ISR_Disable( level );
#endif
#if defined( RTEMS_SMP )
if ( cpu_self->dispatch_necessary ) {
#else
while ( cpu_self->dispatch_necessary ) {
#endif
do {
Thread_Control *heir = _Thread_Get_heir_and_make_it_executing( cpu_self );
/*
@@ -115,6 +90,11 @@ void _Thread_Dispatch( void )
if ( heir->budget_algorithm == THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE )
heir->cpu_time_budget = rtems_configuration_get_ticks_per_timeslice();
/*
* On SMP the complete context switch must be atomic with respect to one
* processor. See also _Thread_Handler() since _Context_switch() may branch
* to this function.
*/
#if !defined( RTEMS_SMP )
_ISR_Enable( level );
#endif
@@ -158,7 +138,13 @@ void _Thread_Dispatch( void )
#if !defined( RTEMS_SMP )
_ISR_Disable( level );
#endif
}
} while (
#if defined( RTEMS_SMP )
false
#else
cpu_self->dispatch_necessary
#endif
);
post_switch:
_Assert( cpu_self->thread_dispatch_disable_level == 1 );
@@ -169,3 +155,21 @@ post_switch:
_Thread_Run_post_switch_actions( executing );
}
void _Thread_Dispatch( void )
{
ISR_Level level;
Per_CPU_Control *cpu_self;
_ISR_Disable_without_giant( level );
cpu_self = _Per_CPU_Get();
if ( cpu_self->dispatch_necessary ) {
_Profiling_Thread_dispatch_disable( cpu_self, 0 );
cpu_self->thread_dispatch_disable_level = 1;
_Thread_Do_dispatch( cpu_self, level );
} else {
_ISR_Enable_without_giant( level );
}
}
+30 -38
View File
@@ -26,9 +26,9 @@
void _Thread_Handler( void )
{
Thread_Control *executing = _Thread_Executing;
ISR_Level level;
Thread_Control *executing = _Thread_Executing;
ISR_Level level;
Per_CPU_Control *cpu_self;
/*
* Some CPUs need to tinker with the call frame or registers when the
@@ -37,15 +37,20 @@ void _Thread_Handler( void )
*/
_Context_Initialization_at_thread_begin();
#if !defined(RTEMS_SMP)
/*
* have to put level into a register for those cpu's that use
* inline asm here
*/
level = executing->Start.isr_level;
_ISR_Set_level( level );
#if defined(RTEMS_SMP)
/* On SMP we enter _Thread_Handler() with interrupts disabled */
_Assert( _ISR_Get_level() != 0 );
_Thread_Debug_set_real_processor( executing, _Per_CPU_Get() );
#endif
/*
* have to put level into a register for those cpu's that use
* inline asm here
*/
level = executing->Start.isr_level;
_ISR_Set_level( level );
/*
* Initialize the floating point context because we do not come
* through _Thread_Dispatch on our first invocation. So the normal
@@ -60,38 +65,25 @@ void _Thread_Handler( void )
*/
_User_extensions_Thread_begin( executing );
/*
* Do not use the level of the thread control block, since it has a
* different format.
*/
_ISR_Disable_without_giant( level );
/*
* At this point, the dispatch disable level BETTER be 1.
*/
#if defined(RTEMS_SMP)
{
/*
* On SMP we enter _Thread_Handler() with interrupts disabled and
* _Thread_Dispatch() obtained the per-CPU lock for us. We have to
* release it here and set the desired interrupt level of the thread.
*/
Per_CPU_Control *cpu_self = _Per_CPU_Get();
cpu_self = _Per_CPU_Get();
_Assert( cpu_self->thread_dispatch_disable_level == 1 );
_Assert( cpu_self->thread_dispatch_disable_level == 1 );
_Assert( _ISR_Get_level() != 0 );
_Thread_Debug_set_real_processor( executing, cpu_self );
cpu_self->thread_dispatch_disable_level = 0;
_Profiling_Thread_dispatch_enable( cpu_self, 0 );
level = executing->Start.isr_level;
_ISR_Set_level( level);
/*
* The thread dispatch level changed from one to zero. Make sure we lose
* no thread dispatch necessary update.
*/
_Thread_Dispatch();
}
#else
_Thread_Enable_dispatch();
#endif
/*
* Make sure we lose no thread dispatch necessary update and execute the
* post-switch actions. As a side-effect change the thread dispatch level
* from one to zero. Do not use _Thread_Enable_dispatch() since there is no
* valid thread dispatch necessary indicator in this context.
*/
_Thread_Do_dispatch( cpu_self, level );
/*
* RTEMS supports multiple APIs and each API can define a different
+4
View File
@@ -99,6 +99,10 @@ static void set_thread_dispatch_necessary( bool dispatch_necessary )
_Thread_Dispatch_necessary = dispatch_necessary;
if ( !dispatch_necessary ) {
_Thread_Heir = _Thread_Executing;
}
#if defined( PREVENT_SMP_ASSERT_FAILURES )
_ISR_Enable_without_giant( level );
#endif