From: Nam Cao <namcao@linutronix.de>
To: Gabriele Monaco <gmonaco@redhat.com>,
linux-kernel@vger.kernel.org,
Steven Rostedt <rostedt@goodmis.org>,
Jonathan Corbet <corbet@lwn.net>,
linux-trace-kernel@vger.kernel.org, linux-doc@vger.kernel.org
Cc: Gabriele Monaco <gmonaco@redhat.com>,
Tomas Glozar <tglozar@redhat.com>, Juri Lelli <jlelli@redhat.com>,
Clark Williams <williams@redhat.com>,
John Kacur <jkacur@redhat.com>
Subject: Re: [PATCH v2 13/20] Documentation/rv: Add documentation about hybrid automata
Date: Fri, 10 Oct 2025 15:46:15 +0200 [thread overview]
Message-ID: <87jz12yimw.fsf@yellow.woof> (raw)
In-Reply-To: <20250919140954.104920-14-gmonaco@redhat.com>
Gabriele Monaco <gmonaco@redhat.com> writes:
> Describe theory and implementation of hybrid automata in the dedicated
> page hybrid_automata.rst
> Include a section on how to integrate a hybrid automaton in
> monitor_synthesis.rst
> Also remove a hanging $ in deterministic_automata.rst
>
> Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
> ---
> .../trace/rv/deterministic_automata.rst | 2 +-
> Documentation/trace/rv/hybrid_automata.rst | 340 ++++++++++++++++++
> Documentation/trace/rv/index.rst | 1 +
> Documentation/trace/rv/monitor_synthesis.rst | 107 ++++++
> 4 files changed, 449 insertions(+), 1 deletion(-)
> create mode 100644 Documentation/trace/rv/hybrid_automata.rst
>
> diff --git a/Documentation/trace/rv/deterministic_automata.rst b/Documentation/trace/rv/deterministic_automata.rst
> index d0638f95a455..7a1c2b20ec72 100644
> --- a/Documentation/trace/rv/deterministic_automata.rst
> +++ b/Documentation/trace/rv/deterministic_automata.rst
> @@ -11,7 +11,7 @@ where:
> - *E* is the finite set of events;
> - x\ :subscript:`0` is the initial state;
> - X\ :subscript:`m` (subset of *X*) is the set of marked (or final) states.
> -- *f* : *X* x *E* -> *X* $ is the transition function. It defines the state
> +- *f* : *X* x *E* -> *X* is the transition function. It defines the state
> transition in the occurrence of an event from *E* in the state *X*. In the
> special case of deterministic automata, the occurrence of the event in *E*
> in a state in *X* has a deterministic next state from *X*.
> diff --git a/Documentation/trace/rv/hybrid_automata.rst b/Documentation/trace/rv/hybrid_automata.rst
> new file mode 100644
> index 000000000000..ea701114c54d
> --- /dev/null
> +++ b/Documentation/trace/rv/hybrid_automata.rst
> @@ -0,0 +1,340 @@
> +Hybrid Automata
> +===============
> +
> +Hybrid automata are an extension of deterministic automata, there are several
> +definitions of hybrid automata in the literature. The adaptation implemented
> +here is formally denoted by G and defined as a 7-tuple:
> +
> + *G* = { *X*, *E*, *V*, *f*, x\ :subscript:`0`, X\ :subscript:`m`, *i* }
> +
> +- *X* is the set of states;
> +- *E* is the finite set of events;
> +- *V* is the finite set of environment variables;
> +- x\ :subscript:`0` is the initial state;
> +- X\ :subscript:`m` (subset of *X*) is the set of marked (or final) states.
> +- *f* : *X* x *E* x *C(V)* -> *X* is the transition function.
> + It defines the state transition in the occurrence of an event from *E* in the
> + state *X*. Unlike deterministic automata, the transition function also
> + includes guards from the set of all possible constraints (defined as *C(V)*).
> + Guards can be true or false with the valuation of *V* when the event occurs,
> + and the transition is possible only when constraints are true. Similarly to
> + deterministic automata, the occurrence of the event in *E* in a state in *X*
> + has a deterministic next state from *X*, if the guard is true.
> +- *i* : *X* -> *C'(V)* is the invariant assignment function, this is a
> + constraint assigned to each state in *X*, every state in *X* must be left
> + before the invariant turns to false. We can omit the representation of
> + invariants whose value is true regardless of the valuation of *V*.
This brings back bad memories from university..
> +
> +The set of all possible constraints *C(V)* is defined according to the
> +following grammar:
> +
> + g = v < c | v > c | v <= c | v >= c | v == c | v != c | g && g | true
> +
> +With v a variable in *V* and c a numerical value.
> +
> +We define the special case of hybrid automata whose variables grow with uniform
> +rates as timed automata. In this case, the variables are called clocks.
> +As the name implies, timed automata can be used to describe real time.
> +Additionally, clocks support another type of guard which always evaluates to true:
> +
> + reset(v)
> +
> +The reset constraint is used to set the value of a clock to 0.
> +
> +The set of invariant constraints *C'(V)* is a subset of *C(V)* including only
> +constraint of the form:
> +
> + g = v < c | true
> +
> +This simplifies the implementation as a clock expiration is a necessary and
> +sufficient condition for the violation of invariants while still allowing more
> +complex constraints to be specified as guards.
> +
> +It is important to note that any valid hybrid automaton is a valid
> +deterministic automaton with additional guards and invariants. Those can only
> +further constrain what transitions are valid but it is not possible to define
> +transition functions starting from the same state in *X* and the same event in
> +*E* but ending up in different states in *X* based on the valuation of *V*.
Perhaps remove the double "valid". Usually people use the phrase "any
valid A is a valid B" to say that B is a superset of A, but it is
opposite here.
> +
> +Examples
> +--------
> +
> +Wip as hybrid automaton
> +~~~~~~~~~~~~~~~~~~~~~~~
> +
> +The 'wip' (wakeup in preemptive) example introduced as a deterministic automaton
> +can also be described as:
> +
> +- *X* = { ``any_thread_running`` }
> +- *E* = { ``sched_waking`` }
> +- *V* = { ``preemptive`` }
> +- x\ :subscript:`0` = ``any_thread_running``
> +- X\ :subscript:`m` = {``any_thread_running``}
> +- *f* =
> + - *f*\ (``any_thread_running``, ``sched_waking``, ``preemptive==0``) = ``any_thread_running``
> +- *i* =
> + - *i*\ (``any_thread_running``) = ``true``
> +
> +Which can be represented graphically as::
> +
> + |
> + |
> + v
> + #====================# sched_waking;preemptive==0
> + H H ------------------------------+
> + H any_thread_running H |
> + H H <-----------------------------+
> + #====================#
> +
> +In this example, by using the preemptive state of the system as an environment
> +variable, we can assert this constraint on ``sched_waking`` without requiring
> +preemption events (as we would in a deterministic automaton), which can be
> +useful in case those events are not available or not reliable on the system.
> +
> +Since all the invariants in *i* are true, we can omit them from the representation.
> +
> +Stall model with guards (iteration 1)
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +As a sample timed automaton we can define 'stall' as:
> +
> +- *X* = { ``dequeued``, ``enqueued``, ``running``}
> +- *E* = { ``enqueue``, ``dequeue``, ``switch_in``}
> +- *V* = { ``clk`` }
> +- x\ :subscript:`0` = ``dequeue``
> +- X\ :subscript:`m` = {``dequeue``}
> +- *f* =
> + - *f*\ (``enqueued``, ``switch_in``, ``clk < threshold``) = ``running``
> + - *f*\ (``running``, ``dequeue``) = ``dequeued``
> + - *f*\ (``dequeued``, ``enqueue``, ``reset(clk)``) = ``enqueued``
> +- *i* = *omitted as all true*
> +
> +Graphically represented as::
> +
> + |
> + |
> + v
> + #============================#
> + H dequeued H <+
> + #============================# |
> + | |
> + | enqueue; reset(clk) |
> + v |
> + +----------------------------+ |
> + | enqueued | | dequeue
> + +----------------------------+ |
> + | |
> + | switch_in; clk < threshold |
> + v |
> + +----------------------------+ |
> + | running | -+
> + +----------------------------+
> +
> +This model imposes that the time between when a task is enqueued (it becomes
> +runnable) and when the task gets to run must be lower than a certain threshold.
> +A failure in this model means that the task is starving.
> +One problem in using guards on the edges in this case is that the model will
> +not report a failure until the ``switch_in`` event occurs. This means that,
> +according to the model, it is valid for the task never to run.
> +
> +Stall model with invariants (iteration 2)
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +The first iteration isn't exactly what was intended, we can change the model as:
> +
> +- *X* = { ``dequeued``, ``enqueued``, ``running``}
> +- *E* = { ``enqueue``, ``dequeue``, ``switch_in``}
> +- *V* = { ``clk`` }
> +- x\ :subscript:`0` = ``dequeue``
> +- X\ :subscript:`m` = {``dequeue``}
> +- *f* =
> + - *f*\ (``enqueued``, ``switch_in``) = ``running``
> + - *f*\ (``running``, ``dequeue``) = ``dequeued``
> + - *f*\ (``dequeued``, ``enqueue``, ``reset(clk)``) = ``enqueued``
> +- *i* =
> + - *i*\ (``enqueued``) = ``clk < threshold``
> +
> +Graphically::
> +
> + |
> + |
> + v
> + #=========================#
> + H dequeued H <+
> + #=========================# |
> + | |
> + | enqueue; reset(clk) |
> + v |
> + +-------------------------+ |
> + | enqueued | |
> + | clk < threshold | | dequeue
> + +-------------------------+ |
> + | |
> + | switch_in |
> + v |
> + +-------------------------+ |
> + | running | -+
> + +-------------------------+
> +
> +In this case, we moved the guard as an invariant to the ``enqueued`` state,
> +this means we not only forbid the occurrence of ``switch_in`` when ``clk`` is
> +past the threshold but also mark as invalid in case we are *still* in
> +``enqueued`` after the threshold. This model is effectively in an invalid state
> +as soon as a task is starving, rather than when the starving task finally runs.
> +
> +Hybrid Automaton in C
> +---------------------
> +
> +The definition of hybrid automata in C is heavily based on the deterministic
> +automata one. Specifically, we add the set of environment variables and the
> +constraints (both guards on transitions and invariants on states) as follows.
> +This is a combination of both iterations of the stall example::
> +
> + /* enum representation of X (set of states) to be used as index */
> + enum states {
> + dequeued = 0,
I think you already removed this " = 0" in an earlier patch?
> + enqueued,
> + running,
> + state_max
> + };
> +
> + #define INVALID_STATE state_max
> +
> + /* enum representation of E (set of events) to be used as index */
> + enum events {
> + dequeue = 0,
> + enqueue,
> + switch_in,
> + event_max
> + };
> +
> + /* enum representation of V (set of environment variables) to be used as index */
> + enum envs {
> + clk = 0,
> + env_max,
> + env_max_stored = env_max
> + };
> +
> + struct automaton {
> + char *state_names[state_max]; // X: the set of states
> + char *event_names[event_max]; // E: the finite set of events
> + char *env_names[env_max]; // V: the finite set of env vars
> + unsigned char function[state_max][event_max]; // f: transition function
> + unsigned char initial_state; // x_0: the initial state
> + bool final_states[state_max]; // X_m: the set of marked states
> + };
> +
> + struct automaton aut = {
> + .state_names = {
> + "dequeued",
> + "enqueued",
> + "running"
> + },
> + .event_names = {
> + "dequeue",
> + "enqueue",
> + "switch_in"
> + },
> + .env_names = {
> + "clk"
> + },
> + .function = {
> + { INVALID_STATE, enqueued, INVALID_STATE },
> + { INVALID_STATE, INVALID_STATE, running },
> + { dequeued, INVALID_STATE, INVALID_STATE },
> + },
> + .initial_state = dequeued,
> + .final_states = { 1, 0, 0 },
> + };
> +
> + static bool verify_constraint(enum states curr_state, enum events event,
> + enum states next_state)
> + {
> + bool res = true;
> +
> + /* Validate guards as part of f */
> + if (curr_state == enqueued && event == sched_switch_in)
> + res = get_env(clk) < threshold;
> + else if (curr_state == dequeued && event == sched_wakeup)
> + reset_env(clk);
> +
> + /* Validate invariants in i */
> + if (next_state == curr_state || !res)
^^^^
indentation error ;)
> + return res;
> + if (next_state == enqueued)
> + ha_start_timer_jiffy(ha_mon, clk, threshold_jiffies);
> + else if (curr_state == enqueued)
> + res = !ha_cancel_timer(ha_mon);
> + return res;
> + }
> +
> +The function ``verify_constraint``, here reported as simplified, checks guards,
> +performs resets and starts timers to validate invariants according to
> +specification.
> +Due to the complex nature of environment variables, the user needs to provide
> +functions to get and reset environment variables, although we provide some
> +helpers for common types (e.g. clocks with ns or jiffy granularity).
Is there theoretical reason that functions to get/set variables cannot
be generated? Or you just do not have time for it yet?
> +Since invariants are only defined as clock expirations (e.g. *clk <
> +threshold*), the callback for timers armed when entering the state is in fact a
> +failure in the model and triggers a reaction. Leaving the state stops the timer
> +and checks for its expiration, in case the callback was late.
"callback for timers armed when entering the state is in fact a failure
in the model and triggers a reaction." - I have problem parsing this
sentence. How can "callback for timers" be armed? Or do you mean arming
timers while entering a state is a failure in the model? What is it a failure?
> +It is important to note that timers introduce overhead, if the monitor has
> +several instances (e.g. all tasks) this can become an issue.
> +If the monitor is guaranteed to *eventually* leave the state and the incurred
> +delay to wait for the next event is acceptable, guards can be use to lower the
> +monitor's overhead.
How about having some sort of a "background task" which periodically
verifies the invariants?
> +For instance in the stall example, if we are only interested in reporting
> +stalled tasks, rather than reacting as soon as a task is stalled, and
> +``switch_in`` is eventually going to occur, we can use the first iteration.
> +
> +Graphviz .dot format
> +--------------------
> +
> +Also the Graphviz representation of hybrid automata is an extension of the
> +deterministic automata one. Specifically, guards can be provided in the event
> +name separated by ``;``::
> +
> + "state_start" -> "state_dest" [ label = "sched_waking;preemptible==0;reset(clk)" ];
> +
> +Invariant can be specified in the state label (not the node name!) separated by ``\n``::
> +
> + "enqueued" [label = "enqueued\nclk < threshold_jiffies"];
> +
> +Constraints can be specified as valid C comparisons and allow spaces, the first
> +element of the comparison must be the clock while the second is a numerical or
> +parametrised value. Guards allow comparisons to be combined with boolean
> +operations (``&&`` and ``||``), resets must be separated from other constraints.
> +
> +This is the full example of the last version of the 'stall' model in DOT::
> +
> + digraph state_automaton {
> + {node [shape = circle] "enqueued"};
> + {node [shape = plaintext, style=invis, label=""] "__init_dequeued"};
> + {node [shape = doublecircle] "dequeued"};
> + {node [shape = circle] "running"};
> + "__init_dequeued" -> "dequeued";
> + "enqueued" [label = "enqueued\nclk < threshold_jiffies"];
> + "running" [label = "running"];
> + "dequeued" [label = "dequeued"];
> + "enqueued" -> "running" [ label = "switch_in" ];
> + "running" -> "dequeued" [ label = "dequeue" ];
> + "dequeued" -> "enqueued" [ label = "enqueue;reset(clk)" ];
> + { rank = min ;
> + "__init_dequeued";
> + "dequeued";
> + }
Btw, the last block (rank = min) doesn't seem to serve any purpose. But
the last time I checked months ago, the parser explodes if it is
removed, not sure if it still does now. But this is another reason that
I would like a rewrite.
Nam
next prev parent reply other threads:[~2025-10-10 13:46 UTC|newest]
Thread overview: 57+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-19 14:09 [PATCH v2 00/20] rv: Add Hybrid Automata monitor type, per-object and deadline monitors Gabriele Monaco
2025-09-19 14:09 ` [PATCH v2 01/20] rv: Refactor da_monitor to minimise macros Gabriele Monaco
2025-10-02 8:45 ` Nam Cao
2025-09-19 14:09 ` [PATCH v2 02/20] rv: Cleanup da_monitor after refactor Gabriele Monaco
2025-10-02 8:49 ` Nam Cao
2025-09-19 14:09 ` [PATCH v2 03/20] rv: Unify DA event handling functions across monitor types Gabriele Monaco
2025-10-02 9:14 ` Nam Cao
2025-10-02 11:30 ` Gabriele Monaco
2025-09-19 14:09 ` [PATCH v2 04/20] Documentation/rv: Adapt documentation after da_monitor refactoring Gabriele Monaco
2025-10-02 9:26 ` Nam Cao
2025-09-19 14:09 ` [PATCH v2 05/20] verification/rvgen: Adapt dot2k and templates after refactoring da_monitor.h Gabriele Monaco
2025-10-02 9:34 ` Nam Cao
2025-09-19 14:09 ` [PATCH v2 06/20] verification/rvgen: Annotate DA functions with types Gabriele Monaco
2025-10-02 9:39 ` Nam Cao
2025-09-19 14:09 ` [PATCH v2 07/20] verification/dot2c: Remove __buff_to_string() and cleanup Gabriele Monaco
2025-09-19 14:09 ` [PATCH v2 08/20] verification/dot2c: Remove superfluous enum assignment and add last comma Gabriele Monaco
2025-10-02 9:40 ` Nam Cao
2025-09-19 14:09 ` [PATCH v2 09/20] verification/rvgen: Remove unused variable declaration from containers Gabriele Monaco
2025-09-19 14:09 ` [PATCH v2 10/20] rv: Add Hybrid Automata monitor type Gabriele Monaco
2025-10-17 8:44 ` Nam Cao
2025-10-17 9:48 ` Gabriele Monaco
2025-10-17 13:05 ` Nam Cao
2025-10-17 15:22 ` Gabriele Monaco
2025-10-20 13:43 ` Nam Cao
2025-09-19 14:09 ` [PATCH v2 11/20] verification/rvgen: Allow spaces in and events strings Gabriele Monaco
2025-10-02 11:03 ` Nam Cao
2025-10-02 11:17 ` Gabriele Monaco
2025-10-06 13:20 ` Nam Cao
2025-10-06 15:22 ` Gabriele Monaco
2025-09-19 14:09 ` [PATCH v2 12/20] verification/rvgen: Add support for Hybrid Automata Gabriele Monaco
2025-10-17 9:37 ` Nam Cao
2025-10-17 9:53 ` Gabriele Monaco
2025-09-19 14:09 ` [PATCH v2 13/20] Documentation/rv: Add documentation about hybrid automata Gabriele Monaco
2025-10-10 13:46 ` Nam Cao [this message]
2025-10-13 8:33 ` Gabriele Monaco
2025-09-19 14:09 ` [PATCH v2 14/20] rv: Add sample hybrid monitors stall Gabriele Monaco
2025-10-10 14:23 ` Nam Cao
2025-10-13 9:01 ` Gabriele Monaco
2025-09-19 14:09 ` [PATCH v2 15/20] rv: Convert the opid monitor to a hybrid automaton Gabriele Monaco
2025-10-10 14:29 ` Nam Cao
2025-10-13 14:14 ` Gabriele Monaco
2025-09-19 14:09 ` [PATCH v2 16/20] sched: Export hidden tracepoints to modules Gabriele Monaco
2025-09-19 15:37 ` Steven Rostedt
2025-09-19 17:07 ` Gabriele Monaco
2025-09-19 14:09 ` [PATCH v2 17/20] sched: Add deadline tracepoints Gabriele Monaco
2025-09-19 14:09 ` [PATCH v2 18/20] rv: Add support for per-object monitors in DA/HA Gabriele Monaco
2025-10-21 11:55 ` Nam Cao
2025-10-21 15:54 ` Gabriele Monaco
2025-10-23 12:36 ` Nam Cao
2025-10-24 9:20 ` Gabriele Monaco
2025-09-19 14:09 ` [PATCH v2 19/20] verification/rvgen: Add support for per-obj monitors Gabriele Monaco
2025-10-21 12:00 ` Nam Cao
2025-09-19 14:09 ` [PATCH v2 20/20] rv: Add deadline monitors Gabriele Monaco
2025-10-10 15:04 ` Nam Cao
2025-10-13 7:30 ` Gabriele Monaco
2025-10-21 12:05 ` [PATCH v2 00/20] rv: Add Hybrid Automata monitor type, per-object and " Nam Cao
2025-10-21 15:45 ` Gabriele Monaco
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87jz12yimw.fsf@yellow.woof \
--to=namcao@linutronix.de \
--cc=corbet@lwn.net \
--cc=gmonaco@redhat.com \
--cc=jkacur@redhat.com \
--cc=jlelli@redhat.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=rostedt@goodmis.org \
--cc=tglozar@redhat.com \
--cc=williams@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.