Hi Gabriele,
On 04/04/25 10:45, Gabriele Monaco wrote:
> Add a per-task monitor for task switches as part of the sched model:
>
> * srs:
> Monitor to describe conditions for different types of task switch.
> This monitor enforces rules such as preempt after setting need
> for reschedule and suspend after setting a task to sleepable.
>
> This new monitor implies the previously introduced snroc (set non
> runnable on its own context), so replace that monitor with srs.
>
> Cc: Ingo Molnar <[email protected]>
> Cc: Peter Zijlstra <[email protected]>
> Signed-off-by: Gabriele Monaco <[email protected]>
> ---
...
> +Monitor srs
> +-----------
> +
> +The switch after resched or sleep (srs) monitor describes conditions for
> +different types of task switch. This is a complex model, below we are going
> to
Quite the ASCII art indeed. :-)
> +explain it step by step. Unfortunately splitting this into smaller monitor is
> +not trivial due to some shared events such as ``switch_in``::
Not splitting, but maybe providing several separate diagrams for the key
cases and transitions might help grasping the complete picture? Not
sure, just a thought.
In the below, set_{sleepable,runnable} corresponds to set_state_
{sleepable,runnable} in the code, does it? Not a big deal, but I was
confused at first.
Thanks,
Juri
> +
> + set_runnable
> + | wakeup +---+
> + | switch_vain | |
> + v | v
> wakeup
> + #================================================#
> set_runnable
> + switch_in H H
> <----------+
> + +------------------> H running H
> |
> + | H H
> -----+ |
> + | #================================================#
> | |
> + | | | | ^ ^
> | |
> + | | switch_yield need_resched | |
> | |
> + | | | need_resched_lazy | |
> | |
> + | set_sleepable v | | |
> | |
> + | | +-------------+ | | |
> | |
> + | +--------+----> | preempted | ---+- switch_in |
> | |
> + | | | +-------------+ | |
> | |
> + | switch_preempt | | | |
> | |
> + | switch_yield | need_resched | +- switch_vain
> | |
> + | | | v | |
> | |
> + | | | +-------------+ | |
> | |
> + | need_resched -+--------+----> | resched_out | | |
> | |
> + | | | | +-------------+ | |
> | |
> + | | | | | | |
> need_resched | |
> + | | | | switch_in | | wakeup
> | |
> + | | | | v v |
> set_runnable | |
> + | | | | +--------------------------+ -------+
> | |
> + | | | | | | |
> | |
> + | | +--------+----- | rescheduling | <------+
> | |
> + | | | | |
> | |
> + | | | +--------------------------+
> -----------+ | |
> + | | | | ^ wakeup
> | | |
> + | | | set_sleepable set_runnable
> | | |
> + | | | v |
> | | |
> + | | +------------------+----- +---------------------------+
> | | |
> + | | | | | |
> | | |
> + +--+--+---+------------------+----> | resched_sleepable | ---+
> | | |
> + | | | | | | | |
> | | |
> + | | | | +-------------+----> +---------------------------+ |
> | | |
> + | | | | | | | ^ | |
> | | |
> + | | | | | | switch_preempt | need_resched |
> | | |
> + | | | | | | | | set_sleepable |
> | | |
> + | | | | | | v +------+ |
> | | |
> + | | | | | | +---------------------------+
> --+------+---+-----+--+
> + | | | | | | | preempted_sleepable | |
> | | | |
> + | | | | | | +---------------------------+
> --+------+---+--+ | |
> + | | | | | | | ^ |
> | | | | |
> + | | | | | | switch_in switch_preempt |
> | | | | |
> + | | | | | | v | switch_vain
> | | | | |
> + | | | | | | +-------------------------+ |
> | | | | |
> + | | | | | +------> | | <--+
> | | | | |
> + | | | | | | sleepable |
> | | | | |
> + | | | | +- need_resched------- | |
> ----------+---+--+--+ |
> + | | | | need_resched_lazy +-------------------------+
> | | | |
> + | | | | | ^ |
> switch_block | | |
> + | | | | | | set_sleepable
> | | | |
> + | | | | switch_block | switch_vain
> +----------+ | | |
> + | | | | switch_suspend +------+ |
> | | |
> + | | | | v v
> | | |
> + | | | | switch_block +-----------------------------+
> switch_block | |
> + | | | +-switch_suspend--------> | sleeping |
> <-----------+ | |
> + | | | +-----------------------------+
> | |
> + | | | | wakeup
> | |
> + | | | v
> | |
> + | | +- need_resched ------------- +-------------+ wakeup
> | |
> + | | | waking |
> <------------------------------+ |
> + | +------------------------------- +-------------+
> |
> + |
> |
> + | +-----------------------+
> |
> + +----- switch_in -------- | resched_out_sleepable | <-- sched_need_resched
> --------------+
> + +-----------------------+
> +
> +Types of switches:
> +
> +* ``switch_in``:
> + a non running task is scheduled in, this leads to ``running`` if the task
> is
> + runnable and ``sleepable`` if the task was preempted before sleeping.
> +* ``switch_suspend``:
> + a task puts itself to sleep, this can happen only after explicitly setting
> + the task to ``sleepable``. After a task is suspended, it needs to be woken
> up
> + (``waking`` state) before being switched in again. The task can be set to
> + ``resched_sleepable`` via a ``need_resched`` but not preempted, in which
> case it
> + is equivalent to ``sleepable``.
> + Setting the task's state to ``sleepable`` can be reverted before switching
> if it
> + is woken up or set to runnable.
> +* ``switch_blocked``:
> + a special case of a ``switch_suspend`` where the task is waiting on a
> + sleeping RT lock (``PREEMPT_RT`` only), it is common to see wakeup and set
> + state events racing with each other and this leads the model to perceive
> this
> + type of switch when the task is not set to sleepable. This is a limitation
> of
> + the model in SMP system and workarounds may require to slow down the
> + scheduler.
> +* ``switch_yield``:
> + a task explicitly calls the scheduler, this looks like a preemption as the
> + task is still runnable but the ``need_resched`` flag is not set. It can
> + happen after a ``yield`` system call or from the idle task.
> +* ``switch_preempt``:
> + a task is ``preempted``, this can happen after the need for
> ``rescheduling``
> + has been set, also in its ``lazy`` flavour. ``need_resched`` can be set as
> a
> + flag to the task or in the per-core preemption count, either of them can
> + trigger a preemption.
> + The task was previously running and can be switched in directly, but it is
> + possible that a task is preempted after it sets itself as ``sleepable``
> + (``preempted_sleepable``), in this condition, once the task is switched
> back
> + in, it will not be ``running`` but continue its sleeping process in
> + ``sleepable``.
> +* ``switch_vain``:
> + a task goes through the scheduler but it is picked as the next task to run,
> + hence no real task switch occurs. Since we run the scheduler, this clears
> the
> + need to reschedule.
> +
...
> +enum events_srs {
> + sched_need_resched_srs = 0,
> + sched_need_resched_lazy_srs,
> + sched_set_state_runnable_srs,
> + sched_set_state_sleepable_srs,
> + sched_switch_blocking_srs,
> + sched_switch_in_srs,
> + sched_switch_preempt_srs,
> + sched_switch_suspend_srs,
> + sched_switch_vain_srs,
> + sched_switch_yield_srs,
> + sched_wakeup_srs,
> + event_max_srs
> +};
> +