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 <mingo@xxxxxxxxxx> > Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx> > Signed-off-by: Gabriele Monaco <gmonaco@xxxxxxxxxx> > --- ... > +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 > +}; > +