Partitioned/clustered scheduling

Sebastian Huber sebastian.huber at embedded-brains.de
Wed Nov 20 08:42:17 UTC 2013


On 2013-11-19 18:36, Gedare Bloom wrote:
> On Tue, Nov 19, 2013 at 8:39 AM, Sebastian Huber
[...]
>> >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);
>> >
> This looks good to me. I guess the user must define the table. We
> should offer some logical/safe defaults, especially for
> single-processor.

Yes, the user must provide this table.  I am not sure how to do the 
single-processor configuration.

One option might be to use something like this:

#ifndef RTEMS_SMP
#define RTEMS_SCHED_DEFINE_FP(name, prio_count)
   static Scheduler_FP_Control name = {
	...
   };
   void _Scheduler_Block(Thread_Control *thread)
   {
     _Scheduler_FP_Block(&name, thread);
   }
   ...

This would remove the function pointer overhead on single-processor configurations.

>
>> >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.
>> >
>> >==== 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;
>> >  };
>> >
> For uniprocessor we don't need the owned processor set fields?

Yes.

>
>> >Single processor configurations benefit also from this change since it makes
>> >all dependencies explicit and easier to access (allows more efficient
>> >machine
>> >code).
>> >
> Good. This should eliminate the _Scheduler variable that is the
> uniprocessor global scheduler handle? I never liked it.
>
>> >==== 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.
>> >
> Good. What will be the default affinity of the init task?

This is a good question.  I think it should use the affinity set of the 
scheduler of the initialization processor.

>
>> >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
>> >  );
>> >
> These classic API set/get affinity functions seem reasonable. They
> mimic existing affinity interfaces nicely. Now users should do
> rtems_task_create(), rtems_task_set_affinity(), rtems_task_start() in
> order to specify the affinity of their tasks, correct?

Yes, after reading it again, should we use the naming of the Linux man page

http://man7.org/linux/man-pages/man3/pthread_setaffinity_np.3.html

affinity_set_size -> cpusetsize
affinity_set -> cpuset

?

-- 
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