Re: [RFC PATCH 9/9] rv: Add srs per-task monitor

Gabriele Monaco
2025-04-11T06:12:32Z

On Thu, 2025-04-10 at 10:53 +0200, Juri Lelli wrote:
> 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@redhat.com>
> > Cc: Peter Zijlstra <peterz@infradead.org>
> > Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
> > ---
>
> ...
>
> > +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.

I tried to do that but then dropped the idea because it was hard to
maintain, not that this one is much easier though..
I might re-consider it!

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

Yeah, I'm trying to keep the names short for the model not to explode
horizontally, but it seems I'm losing on clarity so probably better
finding other solutions.

Thanks,
Gabriele

>
> 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
> > +};
> > +
>