From nobody Mon Oct 6 01:26:43 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F355B230D35 for ; Mon, 28 Jul 2025 20:49:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753735787; cv=none; b=LJAf0YbiwIXHZLutKtxLoOE8+cRK41lwWrbLZQM86tWW6ekGGHShh1no1Sh4Q5teRButFJKfMaZqjR9e546oNOjUvgjy3UjrR+Irq/W9mWhmL1BxnkMQAP2ckpJdp8Cbvg++NSPmF1SP3cUgAC+shZwpDzdB9LY2/5vymqpVnJU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753735787; c=relaxed/simple; bh=fa+oBSdbXiBeFKTWv7wlmZOfz7plss8MxuO4SWIzo5g=; h=Message-ID:Date:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=amMTHkeB16TgVclOKQpQiNQVBWNVKTd09rgrSnzZQGfdjtmCCBu4c5GkqDuv1leyXoK8oPFBR7DSZ+L9+J7DsT2Nj3IaLkks0sc549p4ltcPy9wjmWjtPtdRS6sEBeMwUVfoorkpV+BcSacAM4noPxmP4REak2n/CcRyyUnLBl0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=JAe9MXSM; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="JAe9MXSM" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AFE9BC4CEF7; Mon, 28 Jul 2025 20:49:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1753735786; bh=fa+oBSdbXiBeFKTWv7wlmZOfz7plss8MxuO4SWIzo5g=; h=Date:From:To:Cc:Subject:References:From; b=JAe9MXSMx95sfven+beFr1MQPiYiQR5FvkkX6+4abuQIkwEFoHNnp7fz7TWS6LdSs PnCuMjaXUqnCxrcXW3Sr5viMzLUwsVaKjHRBHaca7qeQL0RJviwSNiszUPHoQ7wz/l yYtg/NC1u1wNw0oix9TwUK4jgF91pI8sc1yrswkAr0Bjq2knnukxgBwAm93DzwRoqg fz4lUQsAyrNc0KkAZxuw3qW+sE5HuPNnI2nz/Jkn3svl5sVDJQxFZBDAR6xsGsZ5Id 93MPhm00d+OBeNOrF75FlZJZAa4LRIFOVmE/RilUx2UeK6mO/bU0F7jYk2jJFvyWOE 6KvDepgT1onxw== Received: from rostedt by gandalf with local (Exim 4.98.2) (envelope-from ) id 1ugUnH-000000042ym-2QUS; Mon, 28 Jul 2025 16:49:59 -0400 Message-ID: <20250728204959.425356272@kernel.org> User-Agent: quilt/0.68 Date: Mon, 28 Jul 2025 16:49:44 -0400 From: Steven Rostedt To: linux-kernel@vger.kernel.org Cc: Tomas Glozar , John Kacur , Ingo Molnar , Jonathan Corbet , Masami Hiramatsu , Juri Lelli , Clark Williams , Peter Zijlstra , Gabriele Monaco , Nam Cao Subject: [for-next][PATCH 10/11] rv: Add nrp and sssw per-task monitors References: <20250728204934.281385756@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Gabriele Monaco Add 2 per-task monitors as part of the sched model: * nrp: need-resched preempts Monitor to ensure preemption requires need resched. * sssw: set state sleep and wakeup Monitor to ensure sched_set_state to sleepable leads to sleeping and sleeping tasks require wakeup. Cc: Ingo Molnar Cc: Jonathan Corbet Cc: Masami Hiramatsu Cc: Tomas Glozar Cc: Juri Lelli Cc: Clark Williams Cc: John Kacur Cc: Peter Zijlstra Link: https://lore.kernel.org/20250728135022.255578-9-gmonaco@redhat.com Signed-off-by: Gabriele Monaco Acked-by: Nam Cao Tested-by: Nam Cao Signed-off-by: Steven Rostedt (Google) --- Documentation/trace/rv/monitor_sched.rst | 167 +++++++++++++++++++++ kernel/trace/rv/Kconfig | 2 + kernel/trace/rv/Makefile | 2 + kernel/trace/rv/monitors/nrp/Kconfig | 16 ++ kernel/trace/rv/monitors/nrp/nrp.c | 138 +++++++++++++++++ kernel/trace/rv/monitors/nrp/nrp.h | 75 +++++++++ kernel/trace/rv/monitors/nrp/nrp_trace.h | 15 ++ kernel/trace/rv/monitors/sched/Kconfig | 1 + kernel/trace/rv/monitors/sssw/Kconfig | 15 ++ kernel/trace/rv/monitors/sssw/sssw.c | 116 ++++++++++++++ kernel/trace/rv/monitors/sssw/sssw.h | 105 +++++++++++++ kernel/trace/rv/monitors/sssw/sssw_trace.h | 15 ++ kernel/trace/rv/rv_trace.h | 2 + tools/verification/models/sched/nrp.dot | 29 ++++ tools/verification/models/sched/sssw.dot | 30 ++++ 15 files changed, 728 insertions(+) create mode 100644 kernel/trace/rv/monitors/nrp/Kconfig create mode 100644 kernel/trace/rv/monitors/nrp/nrp.c create mode 100644 kernel/trace/rv/monitors/nrp/nrp.h create mode 100644 kernel/trace/rv/monitors/nrp/nrp_trace.h create mode 100644 kernel/trace/rv/monitors/sssw/Kconfig create mode 100644 kernel/trace/rv/monitors/sssw/sssw.c create mode 100644 kernel/trace/rv/monitors/sssw/sssw.h create mode 100644 kernel/trace/rv/monitors/sssw/sssw_trace.h create mode 100644 tools/verification/models/sched/nrp.dot create mode 100644 tools/verification/models/sched/sssw.dot diff --git a/Documentation/trace/rv/monitor_sched.rst b/Documentation/trace= /rv/monitor_sched.rst index 6c4c00216c07..11ef963cb578 100644 --- a/Documentation/trace/rv/monitor_sched.rst +++ b/Documentation/trace/rv/monitor_sched.rst @@ -174,6 +174,173 @@ running one, no real task switch occurs but interrupt= s are disabled nonetheless: | | irq_entry +---------------+ irq_enable =20 +Monitor nrp +----------- + +The need resched preempts (nrp) monitor ensures preemption requires +``need_resched``. Only kernel preemption is considered, since preemption +while returning to userspace, for this monitor, is indistinguishable from +``sched_switch_yield`` (described in the sssw monitor). +A kernel preemption is whenever ``__schedule`` is called with the preempti= on +flag set to true (e.g. from preempt_enable or exiting from interrupts). Th= is +type of preemption occurs after the need for ``rescheduling`` has been set. +This is not valid for the *lazy* variant of the flag, which causes only +userspace preemption. +A ``schedule_entry_preempt`` may involve a task switch or not, in the latt= er +case, a task goes through the scheduler from a preemption context but it is +picked as the next task to run. Since the scheduler runs, this clears the = need +to reschedule. The ``any_thread_running`` state does not imply the monitor= ed +task is not running as this monitor does not track the outcome of scheduli= ng. + +In theory, a preemption can only occur after the ``need_resched`` flag is = set. In +practice, however, it is possible to see a preemption where the flag is not +set. This can happen in one specific condition:: + + need_resched + preempt_schedule() + preempt_schedule_irq() + __schedule() + !need_resched + __schedule() + +In the situation above, standard preemption starts (e.g. from preempt_enab= le +when the flag is set), an interrupt occurs before scheduling and, on its e= xit +path, it schedules, which clears the ``need_resched`` flag. +When the preempted task runs again, the standard preemption started earlier +resumes, although the flag is no longer set. The monitor considers this a +``nested_preemption``, this allows another preemption without re-setting t= he +flag. This condition relaxes the monitor constraints and may catch false +negatives (i.e. no real ``nested_preemptions``) but makes the monitor more +robust and able to validate other scenarios. +For simplicity, the monitor starts in ``preempt_irq``, although no interru= pt +occurred, as the situation above is hard to pinpoint:: + + schedule_entry + irq_entry #=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D# + +-------------------------- H H + | H H + +-------------------------> H any_thread_running H + H H + +-------------------------> H H + | #=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D# + | schedule_entry | ^ + | schedule_entry_preempt | sched_need_resched | schedule_entry + | | schedule_entry_pree= mpt + | v | + | +----------------------+ | + | +--- | | | + | sched_need_resched | | rescheduling | -+ + | +--> | | + | +----------------------+ + | | irq_entry + | v + | +----------------------+ + | | | ---+ + | ---> | | | sched_need_res= ched + | | preempt_irq | | irq_entry + | | | <--+ + | | | <--+ + | +----------------------+ | + | | schedule_entry | sched_need_res= ched + | | schedule_entry_preempt | + | v | + | +-----------------------+ | + +-------------------------- | nested_preempt | --+ + +-----------------------+ + ^ irq_entry | + +-------------------+ + +Due to how the ``need_resched`` flag on the preemption count works on arm6= 4, +this monitor is unstable on that architecture, as it often records preempt= ion +when the flag is not set, even in presence of the workaround above. +For the time being, the monitor is disabled by default on arm64. + +Monitor sssw +------------ + +The set state sleep and wakeup (sssw) monitor ensures ``set_state`` to +sleepable leads to sleeping and sleeping tasks require wakeup. It includes= the +following types of switch: + +* ``switch_suspend``: + a task puts itself to sleep, this can happen only after explicitly setti= ng + the task to ``sleepable``. After a task is suspended, it needs to be wok= en up + (``waking`` state) before being switched in again. + Setting the task's state to ``sleepable`` can be reverted before switchi= ng if it + is woken up or set to ``runnable``. +* ``switch_blocking``: + 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 s= et + 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 limitati= on of + the model in SMP system and workarounds may slow down the system. +* ``switch_preempt``: + a task switch as a result of kernel preemption (``schedule_entry_preempt= `` in + the nrp model). +* ``switch_yield``: + a task explicitly calls the scheduler or is preempted while returning to + userspace. It can happen after a ``yield`` system call, from the idle ta= sk or + if the ``need_resched`` flag is set. By definition, a task cannot yield = while + ``sleepable`` as that would be a suspension. A special case of a yield o= ccurs + when a task in ``TASK_INTERRUPTIBLE`` calls the scheduler while a signal= is + pending. The task doesn't go through the usual blocking/waking and is set + back to runnable, the resulting switch (if there) looks like a yield to = the + ``signal_wakeup`` state and is followed by the signal delivery. From this + state, the monitor expects a signal even if it sees a wakeup event, alth= ough + not necessary, to rule out false negatives. + +This monitor doesn't include a running state, ``sleepable`` and ``runnable= `` +are only referring to the task's desired state, which could be scheduled o= ut +(e.g. due to preemption). However, it does include the event +``sched_switch_in`` to represent when a task is allowed to become running.= This +can be triggered also by preemption, but cannot occur after the task got to +``sleeping`` before a ``wakeup`` occurs:: + + +----------------------------------------------------------------------= ----+ + | = | + | = | + | switch_suspend | = | + | switch_blocking | = | + v v = | + +----------+ #=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D# set_state_runnable | + | | H H wakeup = | + | | H H switch_in = | + | | H H switch_yield = | + | sleeping | H H switch_preempt = | + | | H H signal_deliver = | + | | switch_ H H ------+ = | + | | _blocking H runnable H | = | + | | <----------- H H <-----+ = | + +----------+ H H = | + | wakeup H H = | + +---------------------> H H = | + H H = | + +---------> H H = | + | #=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D# | + | | ^ = | + | | | set_state_runnable = | + | | | wakeup = | + | set_state_sleepable | +--------------------= ----+ + | v | | + | +--------------------------+ set_state_sleepab= le + | | | switch_in + | | | switch_preempt + signal_deliver | sleepable | signal_deliver + | | | ------+ + | | | | + | | | <-----+ + | +--------------------------+ + | | ^ + | switch_yield | set_state_sleepable + | v | + | +---------------+ | + +---------- | signal_wakeup | -+ + +---------------+ + ^ | switch_in + | | switch_preempt + | | switch_yield + +-----------+ wakeup + References ---------- =20 diff --git a/kernel/trace/rv/Kconfig b/kernel/trace/rv/Kconfig index b688b24081c8..59d0db898d4a 100644 --- a/kernel/trace/rv/Kconfig +++ b/kernel/trace/rv/Kconfig @@ -55,6 +55,8 @@ source "kernel/trace/rv/monitors/snroc/Kconfig" source "kernel/trace/rv/monitors/scpd/Kconfig" source "kernel/trace/rv/monitors/snep/Kconfig" source "kernel/trace/rv/monitors/sts/Kconfig" +source "kernel/trace/rv/monitors/nrp/Kconfig" +source "kernel/trace/rv/monitors/sssw/Kconfig" # Add new sched monitors here =20 source "kernel/trace/rv/monitors/rtapp/Kconfig" diff --git a/kernel/trace/rv/Makefile b/kernel/trace/rv/Makefile index 1939d3d7621c..2afac88539d3 100644 --- a/kernel/trace/rv/Makefile +++ b/kernel/trace/rv/Makefile @@ -14,6 +14,8 @@ obj-$(CONFIG_RV_MON_RTAPP) +=3D monitors/rtapp/rtapp.o obj-$(CONFIG_RV_MON_PAGEFAULT) +=3D monitors/pagefault/pagefault.o obj-$(CONFIG_RV_MON_SLEEP) +=3D monitors/sleep/sleep.o obj-$(CONFIG_RV_MON_STS) +=3D monitors/sts/sts.o +obj-$(CONFIG_RV_MON_NRP) +=3D monitors/nrp/nrp.o +obj-$(CONFIG_RV_MON_SSSW) +=3D monitors/sssw/sssw.o # Add new monitors here obj-$(CONFIG_RV_REACTORS) +=3D rv_reactors.o obj-$(CONFIG_RV_REACT_PRINTK) +=3D reactor_printk.o diff --git a/kernel/trace/rv/monitors/nrp/Kconfig b/kernel/trace/rv/monitor= s/nrp/Kconfig new file mode 100644 index 000000000000..f5ec08f65535 --- /dev/null +++ b/kernel/trace/rv/monitors/nrp/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +config RV_MON_NRP + depends on RV + depends on RV_MON_SCHED + default y if !ARM64 + select DA_MON_EVENTS_ID + bool "nrp monitor" + help + Monitor to ensure preemption requires need resched. + This monitor is part of the sched monitors collection. + + This monitor is unstable on arm64, say N unless you are testing it. + + For further information, see: + Documentation/trace/rv/monitor_sched.rst diff --git a/kernel/trace/rv/monitors/nrp/nrp.c b/kernel/trace/rv/monitors/= nrp/nrp.c new file mode 100644 index 000000000000..5a83b7171432 --- /dev/null +++ b/kernel/trace/rv/monitors/nrp/nrp.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include + +#define MODULE_NAME "nrp" + +#include +#include +#include +#include + +#include "nrp.h" + +static struct rv_monitor rv_nrp; +DECLARE_DA_MON_PER_TASK(nrp, unsigned char); + +#ifdef CONFIG_X86_LOCAL_APIC +#include + +static void handle_vector_irq_entry(void *data, int vector) +{ + da_handle_event_nrp(current, irq_entry_nrp); +} + +static void attach_vector_irq(void) +{ + rv_attach_trace_probe("nrp", local_timer_entry, handle_vector_irq_entry); + if (IS_ENABLED(CONFIG_IRQ_WORK)) + rv_attach_trace_probe("nrp", irq_work_entry, handle_vector_irq_entry); + if (IS_ENABLED(CONFIG_SMP)) { + rv_attach_trace_probe("nrp", reschedule_entry, handle_vector_irq_entry); + rv_attach_trace_probe("nrp", call_function_entry, handle_vector_irq_entr= y); + rv_attach_trace_probe("nrp", call_function_single_entry, handle_vector_i= rq_entry); + } +} + +static void detach_vector_irq(void) +{ + rv_detach_trace_probe("nrp", local_timer_entry, handle_vector_irq_entry); + if (IS_ENABLED(CONFIG_IRQ_WORK)) + rv_detach_trace_probe("nrp", irq_work_entry, handle_vector_irq_entry); + if (IS_ENABLED(CONFIG_SMP)) { + rv_detach_trace_probe("nrp", reschedule_entry, handle_vector_irq_entry); + rv_detach_trace_probe("nrp", call_function_entry, handle_vector_irq_entr= y); + rv_detach_trace_probe("nrp", call_function_single_entry, handle_vector_i= rq_entry); + } +} + +#else +/* We assume irq_entry tracepoints are sufficient on other architectures */ +static void attach_vector_irq(void) { } +static void detach_vector_irq(void) { } +#endif + +static void handle_irq_entry(void *data, int irq, struct irqaction *action) +{ + da_handle_event_nrp(current, irq_entry_nrp); +} + +static void handle_sched_need_resched(void *data, struct task_struct *tsk, + int cpu, int tif) +{ + /* + * Although need_resched leads to both the rescheduling and preempt_irq + * states, it is safer to start the monitor always in preempt_irq, + * which may not mirror the system state but makes the monitor simpler, + */ + if (tif =3D=3D TIF_NEED_RESCHED) + da_handle_start_event_nrp(tsk, sched_need_resched_nrp); +} + +static void handle_schedule_entry(void *data, bool preempt) +{ + if (preempt) + da_handle_event_nrp(current, schedule_entry_preempt_nrp); + else + da_handle_event_nrp(current, schedule_entry_nrp); +} + +static int enable_nrp(void) +{ + int retval; + + retval =3D da_monitor_init_nrp(); + if (retval) + return retval; + + rv_attach_trace_probe("nrp", irq_handler_entry, handle_irq_entry); + rv_attach_trace_probe("nrp", sched_set_need_resched_tp, handle_sched_need= _resched); + rv_attach_trace_probe("nrp", sched_entry_tp, handle_schedule_entry); + attach_vector_irq(); + + return 0; +} + +static void disable_nrp(void) +{ + rv_nrp.enabled =3D 0; + + rv_detach_trace_probe("nrp", irq_handler_entry, handle_irq_entry); + rv_detach_trace_probe("nrp", sched_set_need_resched_tp, handle_sched_need= _resched); + rv_detach_trace_probe("nrp", sched_entry_tp, handle_schedule_entry); + detach_vector_irq(); + + da_monitor_destroy_nrp(); +} + +static struct rv_monitor rv_nrp =3D { + .name =3D "nrp", + .description =3D "need resched preempts.", + .enable =3D enable_nrp, + .disable =3D disable_nrp, + .reset =3D da_monitor_reset_all_nrp, + .enabled =3D 0, +}; + +static int __init register_nrp(void) +{ + return rv_register_monitor(&rv_nrp, &rv_sched); +} + +static void __exit unregister_nrp(void) +{ + rv_unregister_monitor(&rv_nrp); +} + +module_init(register_nrp); +module_exit(unregister_nrp); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Gabriele Monaco "); +MODULE_DESCRIPTION("nrp: need resched preempts."); diff --git a/kernel/trace/rv/monitors/nrp/nrp.h b/kernel/trace/rv/monitors/= nrp/nrp.h new file mode 100644 index 000000000000..c9f12207cbf6 --- /dev/null +++ b/kernel/trace/rv/monitors/nrp/nrp.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Automatically generated C representation of nrp automaton + * For further information about this format, see kernel documentation: + * Documentation/trace/rv/deterministic_automata.rst + */ + +enum states_nrp { + preempt_irq_nrp =3D 0, + any_thread_running_nrp, + nested_preempt_nrp, + rescheduling_nrp, + state_max_nrp +}; + +#define INVALID_STATE state_max_nrp + +enum events_nrp { + irq_entry_nrp =3D 0, + sched_need_resched_nrp, + schedule_entry_nrp, + schedule_entry_preempt_nrp, + event_max_nrp +}; + +struct automaton_nrp { + char *state_names[state_max_nrp]; + char *event_names[event_max_nrp]; + unsigned char function[state_max_nrp][event_max_nrp]; + unsigned char initial_state; + bool final_states[state_max_nrp]; +}; + +static const struct automaton_nrp automaton_nrp =3D { + .state_names =3D { + "preempt_irq", + "any_thread_running", + "nested_preempt", + "rescheduling" + }, + .event_names =3D { + "irq_entry", + "sched_need_resched", + "schedule_entry", + "schedule_entry_preempt" + }, + .function =3D { + { + preempt_irq_nrp, + preempt_irq_nrp, + nested_preempt_nrp, + nested_preempt_nrp + }, + { + any_thread_running_nrp, + rescheduling_nrp, + any_thread_running_nrp, + INVALID_STATE + }, + { + nested_preempt_nrp, + preempt_irq_nrp, + any_thread_running_nrp, + any_thread_running_nrp + }, + { + preempt_irq_nrp, + rescheduling_nrp, + any_thread_running_nrp, + any_thread_running_nrp + }, + }, + .initial_state =3D preempt_irq_nrp, + .final_states =3D { 0, 1, 0, 0 }, +}; diff --git a/kernel/trace/rv/monitors/nrp/nrp_trace.h b/kernel/trace/rv/mon= itors/nrp/nrp_trace.h new file mode 100644 index 000000000000..2e13497de3b6 --- /dev/null +++ b/kernel/trace/rv/monitors/nrp/nrp_trace.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Snippet to be included in rv_trace.h + */ + +#ifdef CONFIG_RV_MON_NRP +DEFINE_EVENT(event_da_monitor_id, event_nrp, + TP_PROTO(int id, char *state, char *event, char *next_state, bool fi= nal_state), + TP_ARGS(id, state, event, next_state, final_state)); + +DEFINE_EVENT(error_da_monitor_id, error_nrp, + TP_PROTO(int id, char *state, char *event), + TP_ARGS(id, state, event)); +#endif /* CONFIG_RV_MON_NRP */ diff --git a/kernel/trace/rv/monitors/sched/Kconfig b/kernel/trace/rv/monit= ors/sched/Kconfig index ae3eb410abd7..aa16456da864 100644 --- a/kernel/trace/rv/monitors/sched/Kconfig +++ b/kernel/trace/rv/monitors/sched/Kconfig @@ -2,6 +2,7 @@ # config RV_MON_SCHED depends on RV + depends on RV_PER_TASK_MONITORS >=3D 3 bool "sched monitor" help Collection of monitors to check the scheduler behaves according to spec= ifications. diff --git a/kernel/trace/rv/monitors/sssw/Kconfig b/kernel/trace/rv/monito= rs/sssw/Kconfig new file mode 100644 index 000000000000..23b7eeb38bbf --- /dev/null +++ b/kernel/trace/rv/monitors/sssw/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +config RV_MON_SSSW + depends on RV + depends on RV_MON_SCHED + default y + select DA_MON_EVENTS_ID + bool "sssw monitor" + help + Monitor to ensure sched_set_state to sleepable leads to sleeping and + sleeping tasks require wakeup. + This monitor is part of the sched monitors collection. + + For further information, see: + Documentation/trace/rv/monitor_sched.rst diff --git a/kernel/trace/rv/monitors/sssw/sssw.c b/kernel/trace/rv/monitor= s/sssw/sssw.c new file mode 100644 index 000000000000..84b8d890d9d4 --- /dev/null +++ b/kernel/trace/rv/monitors/sssw/sssw.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include + +#define MODULE_NAME "sssw" + +#include +#include +#include +#include + +#include "sssw.h" + +static struct rv_monitor rv_sssw; +DECLARE_DA_MON_PER_TASK(sssw, unsigned char); + +static void handle_sched_set_state(void *data, struct task_struct *tsk, in= t state) +{ + if (state =3D=3D TASK_RUNNING) + da_handle_start_event_sssw(tsk, sched_set_state_runnable_sssw); + else + da_handle_event_sssw(tsk, sched_set_state_sleepable_sssw); +} + +static void handle_sched_switch(void *data, bool preempt, + struct task_struct *prev, + struct task_struct *next, + unsigned int prev_state) +{ + if (preempt) + da_handle_event_sssw(prev, sched_switch_preempt_sssw); + else if (prev_state =3D=3D TASK_RUNNING) + da_handle_event_sssw(prev, sched_switch_yield_sssw); + else if (prev_state =3D=3D TASK_RTLOCK_WAIT) + /* special case of sleeping task with racy conditions */ + da_handle_event_sssw(prev, sched_switch_blocking_sssw); + else + da_handle_event_sssw(prev, sched_switch_suspend_sssw); + da_handle_event_sssw(next, sched_switch_in_sssw); +} + +static void handle_sched_wakeup(void *data, struct task_struct *p) +{ + /* + * Wakeup can also lead to signal_wakeup although the system is + * actually runnable. The monitor can safely start with this event. + */ + da_handle_start_event_sssw(p, sched_wakeup_sssw); +} + +static void handle_signal_deliver(void *data, int sig, + struct kernel_siginfo *info, + struct k_sigaction *ka) +{ + da_handle_event_sssw(current, signal_deliver_sssw); +} + +static int enable_sssw(void) +{ + int retval; + + retval =3D da_monitor_init_sssw(); + if (retval) + return retval; + + rv_attach_trace_probe("sssw", sched_set_state_tp, handle_sched_set_state); + rv_attach_trace_probe("sssw", sched_switch, handle_sched_switch); + rv_attach_trace_probe("sssw", sched_wakeup, handle_sched_wakeup); + rv_attach_trace_probe("sssw", signal_deliver, handle_signal_deliver); + + return 0; +} + +static void disable_sssw(void) +{ + rv_sssw.enabled =3D 0; + + rv_detach_trace_probe("sssw", sched_set_state_tp, handle_sched_set_state); + rv_detach_trace_probe("sssw", sched_switch, handle_sched_switch); + rv_detach_trace_probe("sssw", sched_wakeup, handle_sched_wakeup); + rv_detach_trace_probe("sssw", signal_deliver, handle_signal_deliver); + + da_monitor_destroy_sssw(); +} + +static struct rv_monitor rv_sssw =3D { + .name =3D "sssw", + .description =3D "set state sleep and wakeup.", + .enable =3D enable_sssw, + .disable =3D disable_sssw, + .reset =3D da_monitor_reset_all_sssw, + .enabled =3D 0, +}; + +static int __init register_sssw(void) +{ + return rv_register_monitor(&rv_sssw, &rv_sched); +} + +static void __exit unregister_sssw(void) +{ + rv_unregister_monitor(&rv_sssw); +} + +module_init(register_sssw); +module_exit(unregister_sssw); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Gabriele Monaco "); +MODULE_DESCRIPTION("sssw: set state sleep and wakeup."); diff --git a/kernel/trace/rv/monitors/sssw/sssw.h b/kernel/trace/rv/monitor= s/sssw/sssw.h new file mode 100644 index 000000000000..243d54050c94 --- /dev/null +++ b/kernel/trace/rv/monitors/sssw/sssw.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Automatically generated C representation of sssw automaton + * For further information about this format, see kernel documentation: + * Documentation/trace/rv/deterministic_automata.rst + */ + +enum states_sssw { + runnable_sssw =3D 0, + signal_wakeup_sssw, + sleepable_sssw, + sleeping_sssw, + state_max_sssw +}; + +#define INVALID_STATE state_max_sssw + +enum events_sssw { + sched_set_state_runnable_sssw =3D 0, + sched_set_state_sleepable_sssw, + sched_switch_blocking_sssw, + sched_switch_in_sssw, + sched_switch_preempt_sssw, + sched_switch_suspend_sssw, + sched_switch_yield_sssw, + sched_wakeup_sssw, + signal_deliver_sssw, + event_max_sssw +}; + +struct automaton_sssw { + char *state_names[state_max_sssw]; + char *event_names[event_max_sssw]; + unsigned char function[state_max_sssw][event_max_sssw]; + unsigned char initial_state; + bool final_states[state_max_sssw]; +}; + +static const struct automaton_sssw automaton_sssw =3D { + .state_names =3D { + "runnable", + "signal_wakeup", + "sleepable", + "sleeping" + }, + .event_names =3D { + "sched_set_state_runnable", + "sched_set_state_sleepable", + "sched_switch_blocking", + "sched_switch_in", + "sched_switch_preempt", + "sched_switch_suspend", + "sched_switch_yield", + "sched_wakeup", + "signal_deliver" + }, + .function =3D { + { + runnable_sssw, + sleepable_sssw, + sleeping_sssw, + runnable_sssw, + runnable_sssw, + INVALID_STATE, + runnable_sssw, + runnable_sssw, + runnable_sssw + }, + { + INVALID_STATE, + sleepable_sssw, + INVALID_STATE, + signal_wakeup_sssw, + signal_wakeup_sssw, + INVALID_STATE, + signal_wakeup_sssw, + signal_wakeup_sssw, + runnable_sssw + }, + { + runnable_sssw, + sleepable_sssw, + sleeping_sssw, + sleepable_sssw, + sleepable_sssw, + sleeping_sssw, + signal_wakeup_sssw, + runnable_sssw, + sleepable_sssw + }, + { + INVALID_STATE, + INVALID_STATE, + INVALID_STATE, + INVALID_STATE, + INVALID_STATE, + INVALID_STATE, + INVALID_STATE, + runnable_sssw, + INVALID_STATE + }, + }, + .initial_state =3D runnable_sssw, + .final_states =3D { 1, 0, 0, 0 }, +}; diff --git a/kernel/trace/rv/monitors/sssw/sssw_trace.h b/kernel/trace/rv/m= onitors/sssw/sssw_trace.h new file mode 100644 index 000000000000..6c03cfc6960b --- /dev/null +++ b/kernel/trace/rv/monitors/sssw/sssw_trace.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Snippet to be included in rv_trace.h + */ + +#ifdef CONFIG_RV_MON_SSSW +DEFINE_EVENT(event_da_monitor_id, event_sssw, + TP_PROTO(int id, char *state, char *event, char *next_state, bool fi= nal_state), + TP_ARGS(id, state, event, next_state, final_state)); + +DEFINE_EVENT(error_da_monitor_id, error_sssw, + TP_PROTO(int id, char *state, char *event), + TP_ARGS(id, state, event)); +#endif /* CONFIG_RV_MON_SSSW */ diff --git a/kernel/trace/rv/rv_trace.h b/kernel/trace/rv/rv_trace.h index 97b2f7e07f27..e4e78d23b7b0 100644 --- a/kernel/trace/rv/rv_trace.h +++ b/kernel/trace/rv/rv_trace.h @@ -123,6 +123,8 @@ DECLARE_EVENT_CLASS(error_da_monitor_id, =20 #include #include +#include +#include // Add new monitors based on CONFIG_DA_MON_EVENTS_ID here =20 #endif /* CONFIG_DA_MON_EVENTS_ID */ diff --git a/tools/verification/models/sched/nrp.dot b/tools/verification/m= odels/sched/nrp.dot new file mode 100644 index 000000000000..77bb64669416 --- /dev/null +++ b/tools/verification/models/sched/nrp.dot @@ -0,0 +1,29 @@ +digraph state_automaton { + center =3D true; + size =3D "7,11"; + {node [shape =3D doublecircle] "any_thread_running"}; + {node [shape =3D circle] "any_thread_running"}; + {node [shape =3D circle] "nested_preempt"}; + {node [shape =3D plaintext, style=3Dinvis, label=3D""] "__init_preempt_ir= q"}; + {node [shape =3D circle] "preempt_irq"}; + {node [shape =3D circle] "rescheduling"}; + "__init_preempt_irq" -> "preempt_irq"; + "any_thread_running" [label =3D "any_thread_running", color =3D green3]; + "any_thread_running" -> "any_thread_running" [ label =3D "schedule_entry\= nirq_entry" ]; + "any_thread_running" -> "rescheduling" [ label =3D "sched_need_resched" ]; + "nested_preempt" [label =3D "nested_preempt"]; + "nested_preempt" -> "any_thread_running" [ label =3D "schedule_entry_pree= mpt\nschedule_entry" ]; + "nested_preempt" -> "nested_preempt" [ label =3D "irq_entry" ]; + "nested_preempt" -> "preempt_irq" [ label =3D "sched_need_resched" ]; + "preempt_irq" [label =3D "preempt_irq"]; + "preempt_irq" -> "nested_preempt" [ label =3D "schedule_entry_preempt\nsc= hedule_entry" ]; + "preempt_irq" -> "preempt_irq" [ label =3D "irq_entry\nsched_need_resched= " ]; + "rescheduling" [label =3D "rescheduling"]; + "rescheduling" -> "any_thread_running" [ label =3D "schedule_entry_preemp= t\nschedule_entry" ]; + "rescheduling" -> "preempt_irq" [ label =3D "irq_entry" ]; + "rescheduling" -> "rescheduling" [ label =3D "sched_need_resched" ]; + { rank =3D min ; + "__init_preempt_irq"; + "preempt_irq"; + } +} diff --git a/tools/verification/models/sched/sssw.dot b/tools/verification/= models/sched/sssw.dot new file mode 100644 index 000000000000..4994c3e876be --- /dev/null +++ b/tools/verification/models/sched/sssw.dot @@ -0,0 +1,30 @@ +digraph state_automaton { + center =3D true; + size =3D "7,11"; + {node [shape =3D plaintext, style=3Dinvis, label=3D""] "__init_runnable"}; + {node [shape =3D doublecircle] "runnable"}; + {node [shape =3D circle] "runnable"}; + {node [shape =3D circle] "signal_wakeup"}; + {node [shape =3D circle] "sleepable"}; + {node [shape =3D circle] "sleeping"}; + "__init_runnable" -> "runnable"; + "runnable" [label =3D "runnable", color =3D green3]; + "runnable" -> "runnable" [ label =3D "sched_set_state_runnable\nsched_wak= eup\nsched_switch_in\nsched_switch_yield\nsched_switch_preempt\nsignal_deli= ver" ]; + "runnable" -> "sleepable" [ label =3D "sched_set_state_sleepable" ]; + "runnable" -> "sleeping" [ label =3D "sched_switch_blocking" ]; + "signal_wakeup" [label =3D "signal_wakeup"]; + "signal_wakeup" -> "runnable" [ label =3D "signal_deliver" ]; + "signal_wakeup" -> "signal_wakeup" [ label =3D "sched_switch_in\nsched_sw= itch_preempt\nsched_switch_yield\nsched_wakeup" ]; + "signal_wakeup" -> "sleepable" [ label =3D "sched_set_state_sleepable" ]; + "sleepable" [label =3D "sleepable"]; + "sleepable" -> "runnable" [ label =3D "sched_set_state_runnable\nsched_wa= keup" ]; + "sleepable" -> "signal_wakeup" [ label =3D "sched_switch_yield" ]; + "sleepable" -> "sleepable" [ label =3D "sched_set_state_sleepable\nsched_= switch_in\nsched_switch_preempt\nsignal_deliver" ]; + "sleepable" -> "sleeping" [ label =3D "sched_switch_suspend\nsched_switch= _blocking" ]; + "sleeping" [label =3D "sleeping"]; + "sleeping" -> "runnable" [ label =3D "sched_wakeup" ]; + { rank =3D min ; + "__init_runnable"; + "runnable"; + } +} --=20 2.47.2