Partitioned/clustered scheduling

Chris Johns chrisj at rtems.org
Tue Nov 19 21:22:14 UTC 2013


On 20/11/2013 12:39 am, Sebastian Huber wrote:
> Hello,
>
> we would like to implement partitioned/clustered scheduling for SMP
> RTEMS.  The reasons for this are highlighted in
>

What time frame are you looking at for this ?

> Björn B. Brandenburg, Scheduling and Locking in Multiprocessor Real-Time
> Operating Systems, 2011

http://www.cs.unc.edu/~bbb/diss/brandenburg-diss.pdf ?

> Partitioned/clustered scheduling means that the set of processors of a
> system can be partitioned into pairwise disjoint subsets.  Each subset
> of processors will be owned by one scheduler instance.

Nice.

>
> The following proposal covers the processor configuration, high-level
> scheduler implementation and RTEMS API changes.
>
> ==== Scheduler Configuration ====
>
> There are two options for the scheduler instance configuration
>
> # static configuration by means of global data structures, and
> # configuration at run-time via function calls.
>
> For a configuration at run-time the system must start with a default
> scheduler.
> The global constructors are called in this environment.  The order of
> global
> constructor invocation is unpredictable so it is difficult to create
> threads in
> this context since the run-time scheduler configuration may not exist yet.
> Since scheduler data structures are allocated from the workspace the
> configuration must take a later run-time setup of schedulers into
> account for
> the workspace size estimate.  In case the default scheduler is not
> appropriate
> it must be replaced which gives raise to some implementation difficulties.

I am not sure static constructors is a good example. If a user is 
wanting runtime configuration and is doing this inside static 
constructors they need to manage the dependences. A C++ programmer needs 
to know this.

> Since the processor availability is determined by hardware constraints
> it is
> unclear which benefits a run-time configuration has.  For now run-time
> configuration of scheduler instances will be not implemented.

It may not be clear at this point in time and concentrating on a static 
configuration may be ok however I would hope the design is such it could 
be possible if a suitable use case appears. Will this be possible ?

>
> The focus is now on static configuration.  Every scheduler needs a control
> context.  The scheduler API must provide a macro which creates a global
> scheduler instance specific data structure with a designator name as a
> mandatory parameter.  The scheduler instance creation macro may require
> additional scheduler specific configuration options.  For example a
> fixed-priority scheduler instance must know the maximum priority level to
> allocate the ready chain control table.
>
> Once the scheduler instances are configured it must be specified for each
> processor in the system which scheduler instance owns this processor.
>
> For each processor except the initialization processor a scheduler
> instance is
> optional so that other operating systems can run independent of this RTEMS
> system on this processor.

I am not sure I follow. You say a scheduler instance must be specified 
for each processor then you say for each processor a scheduler instance 
is optional.

What other operating systems are you referring to ?

>  It is a fatal error to omit a scheduler
> instance for
> the initialization processor.  The initialization processor is the
> processor
> which executes the boot_card() function.

Will RTEMS manage the starting of other cores ? At the moment this is 
not the way it works and it places an unneeded dependency on the boot 
monitor. I would like to see code in RTEMS to manage this and plan to 
add Zynq support to do this.

>
>   /**
>    * @brief Processor configuration.
>    *
>    * Use RTEMS_CPU_CONFIG_INIT() to initialize this structure.
>    */
>   typedef struct {
>     /**
>      * @brief Scheduler instance for this processor.
>      *
>      * It is possible to omit a scheduler instance for this processor by
> using
>      * the @c NULL pointer.  In this case RTEMS will not use this
> processor and
>      * other operating systems may claim it.
>      */
>     Scheduler_Control *scheduler;
>   } rtems_cpu_config;
>
>   /**
>    * @brief Processor configuration initializer.
>    *
>    * @param scheduler The reference to a scheduler instance or @c NULL.
>    *
>    * @see rtems_cpu_config.
>    */
>   #define RTEMS_CPU_CONFIG_INIT(scheduler) \
>     { ( scheduler ) }
>
> Scheduler and processor configuration example:
>
>   RTEMS_SCHED_DEFINE_FP_SMP(sched_fp0, 256);
>   RTEMS_SCHED_DEFINE_FP_SMP(sched_fp1, 64);
>   RTEMS_SCHED_DEFINE_EDF_SMP(sched_edf0);
>
>   const rtems_cpu_config rtems_cpu_config_table[] = {
>     RTEMS_CPU_CONFIG_INIT(RTEMS_SCHED_REF_FP_SMP(sched_fp0)),
>     RTEMS_CPU_CONFIG_INIT(RTEMS_SCHED_REF_FP_SMP(sched_fp1)),
>     RTEMS_CPU_CONFIG_INIT(RTEMS_SCHED_REF_FP_SMP(sched_fp1)),
>     RTEMS_CPU_CONFIG_INIT(RTEMS_SCHED_REF_FP_SMP(sched_fp1)),
>     RTEMS_CPU_CONFIG_INIT(NULL),
>     RTEMS_CPU_CONFIG_INIT(NULL),
>     RTEMS_CPU_CONFIG_INIT(RTEMS_SCHED_REF_EDF_SMP(sched_edf0)),
>     RTEMS_CPU_CONFIG_INIT(RTEMS_SCHED_REF_EDF_SMP(sched_edf0)
>   };
>
>   const size_t rtems_cpu_config_count =
>     RTEMS_ARRAY_SIZE(rtems_cpu_config_table);
>
> An alternative to the processor configuration table would be to specify
> in the
> scheduler instance which processors are owned by the instance.  This would
> require a static initialization of CPU sets which is difficult.  Also the
> schedulers have to be registered somewhere, so some sort of table is needed
> anyway.  Since a processor can be owned by at most one scheduler
> instance this
> configuration approach enables an additional error source which is
> avoided by
> the processor configuration table.

Is there support to add and remove processors and provide any form of 
dynamic control ?

Chris

>
> ==== Scheduler Implementation Changes ====
>
> Currently the scheduler operations have no control context and use global
> variables instead.  Thus the scheduler operations signatures must change
> to use
> a scheduler control context as the first parameter, e.g.
>
>   typedef struct Scheduler_Control Scheduler_Control;
>
>   typedef struct {
>     [...]
>     void ( *set_affinity )(
>       Scheduler_Control *self,
>       Thread_Control *thread,
>       size_t affinity_set_size,
>       const cpu_set_t *affinity_set
>     );
>     [...]
>   } Scheduler_Operations;
>
>   /**
>    * @brief General scheduler control.
>    */
>   struct Scheduler_Control {
>     /**
>      * @brief The scheduler operations.
>      */
>     Scheduler_Operations Operations;
>
>     /**
>      * @brief Size of the owned processor set in bytes.
>      */
>     size_t owned_cpu_set_size
>
>     /**
>      * @brief Reference to the owned processor set.
>      *
>      * A set bit means this processor is owned by this scheduler
> instance, an
>      * unset bit means the opposite.
>      */
>     cpu_set_t *owned_cpu_set;
>   };
>
> Single processor configurations benefit also from this change since it
> makes
> all dependencies explicit and easier to access (allows more efficient
> machine
> code).
>
> ==== RTEMS API Changes ====
>
> Each thread needs a processor affinity set in the RTEMS SMP
> configuration.  The
> rtems_task_create() function will use the processor affinity set of the
> executing thread to initialize the processor affinity set of the created
> task.  This enables backward compatibility for existing software.
>
> Two new functions should be added to alter and retrieve the processor
> affinity
> sets of threads.
>
>   /**
>    * @brief Sets the processor affinity set of a task.
>    *
>    * @param[in] task_id Identifier of the task.  Use @ref RTEMS_SELF to
> select
>    * the executing task.
>    * @param[in] affinity_set_size Size of the specified affinity set in
> bytes.
>    * This value must be positive.
>    * @param[in] affinity_set The processor affinity set for the task.  This
>    * pointer must not be @c NULL.  A set bit in the affinity set means
> that the
>    * task can execute on this processor and an unset bit means the
> opposite.
>    *
>    * @retval RTEMS_SUCCESSFUL Successful operation.
>    * @retval RTEMS_INVALID_ID Invalid task identifier.
>    * @retval RTEMS_INVALID_CPU_SET Invalid processor affinity set.
>    */
>   rtems_status_code rtems_task_set_affinity(
>     rtems_id task_id,
>     size_t affinity_set_size,
>     const cpu_set_t *affinity_set
>   );
>
>   /**
>    * @brief Gets the processor affinity set of a task.
>    *
>    * @param[in] task_id Identifier of the task.  Use @ref RTEMS_SELF to
> select
>    * the executing task.
>    * @param[in] affinity_set_size Size of the specified affinity set in
> bytes.
>    * This value must be positive.
>    * @param[out] affinity_set The processor affinity set of the task.  This
>    * pointer must not be @c NULL.  A set bit in the affinity set means
> that the
>    * task can execute on this processor and an unset bit means the
> opposite.
>    *
>    * @retval RTEMS_SUCCESSFUL Successful operation.
>    * @retval RTEMS_INVALID_ID Invalid task identifier.
>    * @retval RTEMS_INVALID_CPU_SET The affinity set is too small for the
>    * processor affinity set of the task.
>    */
>   rtems_status_code rtems_task_get_affinity(
>     rtems_id task_id,
>     size_t affinity_set_size,
>     cpu_set_t *affinity_set
>   );
>



More information about the devel mailing list