Executing Thread Migrating Due to Affinity Change
Sebastian Huber
sebastian.huber at embedded-brains.de
Fri May 30 15:32:48 UTC 2014
On 05/30/2014 04:43 PM, Joel Sherrill wrote:
> On 5/30/2014 8:33 AM, Sebastian Huber wrote:
>> >On 05/29/2014 09:28 PM, Joel Sherrill wrote:
>>> >>Hi
>>> >>
>>> >>The priority affinity algorithm appears to be behaving as
>>> >>we expect from a decision making standpoint. However,
>>> >>Jennifer and I think that when a scheduled thread must
>>> >>be migrated to another core, we have a case for a new
>>> >>state in the Thread Life Cycle.
>> >I hope we can avoid this. Which problem do you want to address with
>> >this new state?
> We have some tests that are not behaving on grsim as we expect.
> I was wondering if migrating the executing thread to another core
> would result in some unexpected weirdness. Because of [1], we
> were in desk check and thinking mode to find the problem.
>
> [1] grsim+gdb on multi-core configurations results in an assert
> in RTEMS if you run with a breakpoint set. You don't have to
> continue -- just "tar remote :2222; load; b XXX; cont" and you
> get an assert. Daniel H. is looking into an example for us.
> But for now, we have no real visibility on leon3. We are in
> the process of switching to the realview on qemu to debug.
What are these for tests and which assertions fail? Some of the
smptests work only on real SMP machines.
>>> >>I am thinking that the thread needs to have a blocking state
>>> >>set, have its context saved and be taken out of the scheduled
>>> >>set. Then a life cycle state change handler van run as an
>>> >>extension to unblock it so it can be potentially scheduled to
>>> >>execute on another processor.
>> >The scheduler is not responsible for the thread context. This is
>> >_Thread_Dispatch(). A post-switch handler can only do actions for the
>> >executing thread. It would be extremely difficult to perform actions on
>> >behalf of another thread.
> I was thinking that. I couldn't see how it would even work reliably.
> Plus we are
> already technically blocking and unblocking the thread so it should be
> moving
> from scheduled to ready and back.
>> > We have to keep also fine grained locking
>> >into account. The _Thread_Dispatch() function is on the critical path
>> >for average and worst-case performance, so we should keep it as simple
>> >as possible.
> I agree.
>> >As I wrote already in another thread you can use something like this to
>> >allocate an exact processor for a thread:
> I suppose I should have posted the patch for review by now but I was hoping
> to have it completely working with tests when posted. Anyway, it is
> attached. The key is that I modified the priority SMP to let
> let get_lowest_scheduled() and get_highest_ready() both be passed in
> from higher levels.
>
> The selection of get_lowest_scheduled() and get_highest_ready()
> include the option of a filter thread. The filter thread is used
> as to check that the victim's CPU is in the potential heir's affinity
> set.
Looks good, apart from the extra NULL pointer check.
>
> I think the logic works out so that the normal calls to
> _Scheduler_SMP_Allocate_processor() have selected the
> correct thread/CPU.
>
> I don't see the extra logic in _Scheduler_SMP_Allocate_processor()
> having a negative impact. What do you see that I might be missing?
The current _Scheduler_SMP_Allocate_processor() tries to keep a thread
on its executing processor. The thread dispatch is asynchronous on
SMP. So for example if you block/unblock a thread extremely fast, then
this helps to avoid a thread migration. I think this optimization
conflicts with the affinity scheduler.
>> >static inline void _Scheduler_SMP_Allocate_processor_exact(
>> > Scheduler_SMP_Context *self,
>> > Thread_Control *scheduled,
>> > Thread_Control *victim
>> >)
>> >{
>> > Scheduler_SMP_Node *scheduled_node = _Scheduler_SMP_Node_get(
>> >scheduled );
>> > Per_CPU_Control *cpu_of_scheduled = _Thread_Get_CPU( scheduled );
>> > Per_CPU_Control *cpu_of_victim = _Thread_Get_CPU( victim );
>> > Per_CPU_Control *cpu_self = _Per_CPU_Get();
>> >
>> > _Scheduler_SMP_Node_change_state(
>> > scheduled_node,
>> > SCHEDULER_SMP_NODE_SCHEDULED
>> > );
>> >
>> > _Thread_Set_CPU( scheduled, cpu_of_victim );
>> > _Scheduler_SMP_Update_heir( cpu_self, cpu_of_victim, scheduled );
>> >}
>> >
>> >You can even use this function to do things like this:
>> >
>> >_Scheduler_SMP_Allocate_processor_exact(self, executing, other);
>> >_Scheduler_SMP_Allocate_processor_exact(self, other, executing);
>> >
>> >This works because the is executing indicator moved to the thread
>> >context and is maintained at the lowest context switch level. For
>> >proper migration the scheduler must ensure that,
>> >
>> >1. an heir thread other than the migrating thread exists on the source
>> >processor, and
>> >
>> >2. the migrating thread is the heir thread on the destination processor.
>> >
> Hmmm... If I am using the normal _Scheduler_SMP_Allocate_processor()
> aren't these ensured?
Yes, it is ensured, but you can probably not use this function for your
affinity scheduler due to the _Scheduler_SMP_Is_processor_owned_by_us(
self, cpu_of_scheduled ) check.
>
> -- Joel Sherrill, Ph.D. Director of Research & Development
> joel.sherrill at OARcorp.com On-Line Applications Research Ask me about
> RTEMS: a free RTOS Huntsville AL 35805 Support Available (256) 722-9985
>
> 0004-Add-SMP-Priority-Scheduler-with-Affinity.patch
>
>
> >From d83641f11d016a2cd73e2661326a5dc873ba0c3c Mon Sep 17 00:00:00 2001
> From: Joel Sherrill<joel.sherrill at oarcorp.com>
> Date: Mon, 19 May 2014 15:26:55 -0500
> Subject: [PATCH 4/4] Add SMP Priority Scheduler with Affinity
>
> Added Thread_Control * parameter to Scheduler_SMP_Get_highest_ready type
> so methods looking for the highest ready thread can filter by the processor
> on which the thread blocking resides. This allows affinity to be considered.
> Simple Priority SMP and Priority SMP ignore this parameter.
>
> This scheduler attempts to account for needed thread migrations.
>
> ==Side Effects of Adding This Scheduler==
>
> + Added get_lowest_scheduled to _Scheduler_SMP_Enqueue_ordered().
>
> + schedulerprioritysmpimpl.h is a new file with prototypes for methods
> which were formerly static in schedulerprioritysmp.c but now need to
> be public to be shared with this scheduler.
>
> NOTE:
> _Scheduler_SMP_Get_lowest_ready() appears to have a path which would
> allow it to return a NULL. Previously, _Scheduler_SMP_Enqueue_ordered()
> would have asserted on it. If it cannot return a NULL,
> _Scheduler_SMP_Get_lowest_ready() should have an assertions.
[...]
> @@ -448,6 +464,8 @@ static inline Thread_Control *_Scheduler_SMP_Get_lowest_scheduled(
> * scheduled nodes.
> * @param[in] move_from_scheduled_to_ready Function to move a node from the set
> * of scheduled nodes to the set of ready nodes.
> + * @param[in] get_lowest_scheduled Function to select the thread from the
> + * scheduled nodes to replace. It may not be possible to find one.
> */
> static inline void _Scheduler_SMP_Enqueue_ordered(
> Scheduler_Context *context,
> @@ -455,16 +473,28 @@ static inline void _Scheduler_SMP_Enqueue_ordered(
> Chain_Node_order order,
> Scheduler_SMP_Insert insert_ready,
> Scheduler_SMP_Insert insert_scheduled,
> - Scheduler_SMP_Move move_from_scheduled_to_ready
> + Scheduler_SMP_Move move_from_scheduled_to_ready,
> + Scheduler_SMP_Get_lowest_scheduled get_lowest_scheduled
> )
> {
> Scheduler_SMP_Context *self = _Scheduler_SMP_Get_self( context );
> Thread_Control *lowest_scheduled =
> - _Scheduler_SMP_Get_lowest_scheduled( self );
> -
> - _Assert( lowest_scheduled != NULL );
> + ( *get_lowest_scheduled )( context, thread, order );
>
> - if ( ( *order )( &thread->Object.Node, &lowest_scheduled->Object.Node ) ) {
> + /*
> + * get_lowest_scheduled can return a NULL if no scheduled threads
> + * should be removed from their processor based on the selection
> + * criteria. For example, this can occur when the affinity of the
> + * thread being enqueued schedules it against higher priority threads.
> + * A low priority thread with affinity can only consider the threads
> + * which are on the cores if has affinity for.
> + *
> + * The get_lowest_scheduled helper should assert on not returning NULL
> + * if that is not possible for that scheduler.
> + */
> +
> + if ( lowest_scheduled &&
> + ( *order )( &thread->Object.Node, &lowest_scheduled->Object.Node ) ) {
> Scheduler_SMP_Node *lowest_scheduled_node =
> _Scheduler_SMP_Node_get( lowest_scheduled );
>
I think its possible to avoid the extra NULL pointer check here, if you
use a special order function that returns false if the second parameter
is NULL. The problem is that this adds untestable code for the normal
SMP schedulers.
--
Sebastian Huber, embedded brains GmbH
Address : Dornierstr. 4, D-82178 Puchheim, Germany
Phone : +49 89 189 47 41-16
Fax : +49 89 189 47 41-09
E-Mail : sebastian.huber at embedded-brains.de
PGP : Public key available on request.
Diese Nachricht ist keine geschäftliche Mitteilung im Sinne des EHUG.
More information about the devel
mailing list