* [RFC PATCH 00/11] rv: Add scheduler specification monitors
@ 2025-02-06 8:09 Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 01/11] tracing: Fix DECLARE_TRACE_CONDITION Gabriele Monaco
` (11 more replies)
0 siblings, 12 replies; 23+ messages in thread
From: Gabriele Monaco @ 2025-02-06 8:09 UTC (permalink / raw)
To: linux-kernel, Steven Rostedt, Ingo Molnar, Peter Zijlstra,
linux-trace-kernel
Cc: Gabriele Monaco, Juri Lelli, John Kacur, Clark Williams
This patchset starts including adapted scheduler specifications from
Daniel's task model [1].
As the model is fairly complicated, it is split in several generators
and specifications. The tool used to create the model can output a
unified model, but that would be hardly readable (9k states).
RV allows monitors to run and react concurrently. Running the cumulative
model is equivalent to running single components using the same
reactors, with the advantage that it's easier to point out which
specification failed in case of error.
We allow this by introducing nested monitors, in short, the sysfs
monitor folder will contain a monitor named sched, which is nothing but
an empty container for other monitors. Controlling the sched monitor
(enable, disable, set reactors) controls all nested monitors.
The task model proposed by Daniel includes 12 generators and 33
specifications. The generators are good for documentation but are
usually implied in some specifications.
Not all monitors work out of the box, mainly because of those reasons:
* need to distinguish if preempt disable leads to schedule
* need to distinguish if irq disable comes from an actual irq
* assumptions not always true on SMP
The original task model was designed for PREEMPT_RT and this patchset is
only tested on an upstream kernel with full preemption enabled.
In patch 4-6 are included only some specifications that work without
further modifications. Ideally, we would adapt all specifications and
add them gradually to the sched monitor.
Patch 1 fixes a macro required for some tracepoints
This patch was already sent and reviewed in [2]
Patch 2 adds some additional tracepoints in the scheduler's code to
complete the model, the tracepoints were already defined in Daniel's
patches but, as far as I understand, were never submitted
Patch 3 adds the empty sched monitor container and the infrastructure
for nested monitors
Patch 4 adds 2 per-cpu monitors using the tracepoints defined in 2
Patch 5 adds a per-task monitor using the tracepoints defined in 2
Patch 6 adds 3 more per-cpu monitors using the tracepoints defined in 2
and preemptirq tracepoints
Patch 7 adjusts the rv tool to support nested monitors
Patch 8 adjusts the dot2k tool to support nested monitors
Patch 9 adds some documentation for the sched monitors, including
a description of the included specifications
Patch 10 adapts the rv tool to list also filtering by container
[1] - https://bristot.me/linux-task-model
[2] - https://lore.kernel.org/linux-trace-kernel/20250128111926.303093-1-gmonaco@redhat.com
To: Steven Rostedt <rostedt@goodmis.org>
To: Ingo Molnar <mingo@redhat.com>
To: Peter Zijlstra <peterz@infradead.org>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
Cc: Clark Williams <williams@redhat.com>
To: linux-trace-kernel@vger.kernel.org
Gabriele Monaco (11):
tracing: Fix DECLARE_TRACE_CONDITION
rv: Add license identifiers to monitor files
sched: Add sched tracepoints for RV task model
rv: Add option for nested monitors and include sched
rv: Add sco and tss per-cpu monitors
rv: Add snroc per-task monitor
rv: Add scpd, snep and sncid per-cpu monitors
tools/rv: Add support for nested monitors
verification/dot2k: Add support for nested monitors
Documentation/rv: Add docs for the sched monitors
tools/rv: Allow rv list to filter for container
Documentation/tools/rv/rv-mon-sched.rst | 69 +++++
Documentation/trace/rv/monitor_sched.rst | 171 ++++++++++++
include/linux/rv.h | 4 +-
include/linux/sched.h | 7 +
include/trace/define_trace.h | 7 +
include/trace/events/sched.h | 17 ++
kernel/sched/core.c | 21 +-
kernel/trace/rv/Kconfig | 7 +
kernel/trace/rv/Makefile | 7 +
kernel/trace/rv/monitors/sched/Kconfig | 18 ++
kernel/trace/rv/monitors/sched/sched.c | 38 +++
kernel/trace/rv/monitors/sched/sched.h | 3 +
kernel/trace/rv/monitors/sco/Kconfig | 13 +
kernel/trace/rv/monitors/sco/sco.c | 88 ++++++
kernel/trace/rv/monitors/sco/sco.h | 47 ++++
kernel/trace/rv/monitors/sco/sco_trace.h | 15 +
kernel/trace/rv/monitors/scpd/Kconfig | 14 +
kernel/trace/rv/monitors/scpd/scpd.c | 96 +++++++
kernel/trace/rv/monitors/scpd/scpd.h | 49 ++++
kernel/trace/rv/monitors/scpd/scpd_trace.h | 15 +
kernel/trace/rv/monitors/sncid/Kconfig | 14 +
kernel/trace/rv/monitors/sncid/sncid.c | 96 +++++++
kernel/trace/rv/monitors/sncid/sncid.h | 49 ++++
kernel/trace/rv/monitors/sncid/sncid_trace.h | 15 +
kernel/trace/rv/monitors/snep/Kconfig | 14 +
kernel/trace/rv/monitors/snep/snep.c | 96 +++++++
kernel/trace/rv/monitors/snep/snep.h | 49 ++++
kernel/trace/rv/monitors/snep/snep_trace.h | 15 +
kernel/trace/rv/monitors/snroc/Kconfig | 13 +
kernel/trace/rv/monitors/snroc/snroc.c | 87 ++++++
kernel/trace/rv/monitors/snroc/snroc.h | 47 ++++
kernel/trace/rv/monitors/snroc/snroc_trace.h | 15 +
kernel/trace/rv/monitors/tss/Kconfig | 13 +
kernel/trace/rv/monitors/tss/tss.c | 91 +++++++
kernel/trace/rv/monitors/tss/tss.h | 47 ++++
kernel/trace/rv/monitors/tss/tss_trace.h | 15 +
kernel/trace/rv/monitors/wip/Kconfig | 2 +
kernel/trace/rv/monitors/wip/wip.c | 2 +-
kernel/trace/rv/monitors/wip/wip.h | 1 +
kernel/trace/rv/monitors/wwnr/Kconfig | 2 +
kernel/trace/rv/monitors/wwnr/wwnr.c | 2 +-
kernel/trace/rv/monitors/wwnr/wwnr.h | 1 +
kernel/trace/rv/rv.c | 151 +++++++++--
kernel/trace/rv/rv.h | 4 +
kernel/trace/rv/rv_reactors.c | 28 +-
kernel/trace/rv/rv_trace.h | 6 +
tools/verification/dot2/dot2k | 27 +-
tools/verification/dot2/dot2k.py | 79 ++++--
.../verification/dot2/dot2k_templates/Kconfig | 3 +
.../verification/dot2/dot2k_templates/main.c | 4 +-
.../dot2/dot2k_templates/main_container.c | 38 +++
.../dot2/dot2k_templates/main_container.h | 3 +
tools/verification/models/sched/sco.dot | 18 ++
tools/verification/models/sched/scpd.dot | 18 ++
tools/verification/models/sched/sncid.dot | 18 ++
tools/verification/models/sched/snep.dot | 18 ++
tools/verification/models/sched/snroc.dot | 18 ++
tools/verification/models/sched/tss.dot | 18 ++
tools/verification/rv/include/in_kernel.h | 2 +-
tools/verification/rv/include/rv.h | 3 +-
tools/verification/rv/src/in_kernel.c | 256 ++++++++++++++----
tools/verification/rv/src/rv.c | 38 ++-
62 files changed, 2015 insertions(+), 127 deletions(-)
create mode 100644 Documentation/tools/rv/rv-mon-sched.rst
create mode 100644 Documentation/trace/rv/monitor_sched.rst
create mode 100644 kernel/trace/rv/monitors/sched/Kconfig
create mode 100644 kernel/trace/rv/monitors/sched/sched.c
create mode 100644 kernel/trace/rv/monitors/sched/sched.h
create mode 100644 kernel/trace/rv/monitors/sco/Kconfig
create mode 100644 kernel/trace/rv/monitors/sco/sco.c
create mode 100644 kernel/trace/rv/monitors/sco/sco.h
create mode 100644 kernel/trace/rv/monitors/sco/sco_trace.h
create mode 100644 kernel/trace/rv/monitors/scpd/Kconfig
create mode 100644 kernel/trace/rv/monitors/scpd/scpd.c
create mode 100644 kernel/trace/rv/monitors/scpd/scpd.h
create mode 100644 kernel/trace/rv/monitors/scpd/scpd_trace.h
create mode 100644 kernel/trace/rv/monitors/sncid/Kconfig
create mode 100644 kernel/trace/rv/monitors/sncid/sncid.c
create mode 100644 kernel/trace/rv/monitors/sncid/sncid.h
create mode 100644 kernel/trace/rv/monitors/sncid/sncid_trace.h
create mode 100644 kernel/trace/rv/monitors/snep/Kconfig
create mode 100644 kernel/trace/rv/monitors/snep/snep.c
create mode 100644 kernel/trace/rv/monitors/snep/snep.h
create mode 100644 kernel/trace/rv/monitors/snep/snep_trace.h
create mode 100644 kernel/trace/rv/monitors/snroc/Kconfig
create mode 100644 kernel/trace/rv/monitors/snroc/snroc.c
create mode 100644 kernel/trace/rv/monitors/snroc/snroc.h
create mode 100644 kernel/trace/rv/monitors/snroc/snroc_trace.h
create mode 100644 kernel/trace/rv/monitors/tss/Kconfig
create mode 100644 kernel/trace/rv/monitors/tss/tss.c
create mode 100644 kernel/trace/rv/monitors/tss/tss.h
create mode 100644 kernel/trace/rv/monitors/tss/tss_trace.h
create mode 100644 tools/verification/dot2/dot2k_templates/main_container.c
create mode 100644 tools/verification/dot2/dot2k_templates/main_container.h
create mode 100644 tools/verification/models/sched/sco.dot
create mode 100644 tools/verification/models/sched/scpd.dot
create mode 100644 tools/verification/models/sched/sncid.dot
create mode 100644 tools/verification/models/sched/snep.dot
create mode 100644 tools/verification/models/sched/snroc.dot
create mode 100644 tools/verification/models/sched/tss.dot
base-commit: 5c8c229261f14159b54b9a32f12e5fa89d88b905
--
2.48.1
^ permalink raw reply [flat|nested] 23+ messages in thread
* [RFC PATCH 01/11] tracing: Fix DECLARE_TRACE_CONDITION
2025-02-06 8:09 [RFC PATCH 00/11] rv: Add scheduler specification monitors Gabriele Monaco
@ 2025-02-06 8:09 ` Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 02/11] rv: Add license identifiers to monitor files Gabriele Monaco
` (10 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Gabriele Monaco @ 2025-02-06 8:09 UTC (permalink / raw)
To: linux-kernel, Steven Rostedt, Masami Hiramatsu,
linux-trace-kernel
Cc: Gabriele Monaco
Commit 287050d39026 ("tracing: Add TRACE_EVENT_CONDITIONAL()") adds
macros to define conditional trace events (TRACE_EVENT_CONDITIONAL) and
tracepoints (DECLARE_TRACE_CONDITION), but sets up functionality for
direct use only for the former.
Add preprocessor bits in define_trace.h to allow usage of
DECLARE_TRACE_CONDITION just like DECLARE_TRACE.
Fixes: 287050d39026 ("tracing: Add TRACE_EVENT_CONDITIONAL()")
Link: https://lore.kernel.org/linux-trace-kernel/20250128111926.303093-1-gmonaco@redhat.com
Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
include/trace/define_trace.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/include/trace/define_trace.h b/include/trace/define_trace.h
index e1c1079f8c8db..ed52d0506c69f 100644
--- a/include/trace/define_trace.h
+++ b/include/trace/define_trace.h
@@ -76,6 +76,10 @@
#define DECLARE_TRACE(name, proto, args) \
DEFINE_TRACE(name, PARAMS(proto), PARAMS(args))
+#undef DECLARE_TRACE_CONDITION
+#define DECLARE_TRACE_CONDITION(name, proto, args, cond) \
+ DEFINE_TRACE(name, PARAMS(proto), PARAMS(args))
+
/* If requested, create helpers for calling these tracepoints from Rust. */
#ifdef CREATE_RUST_TRACE_POINTS
#undef DEFINE_RUST_DO_TRACE
@@ -108,6 +112,8 @@
/* Make all open coded DECLARE_TRACE nops */
#undef DECLARE_TRACE
#define DECLARE_TRACE(name, proto, args)
+#undef DECLARE_TRACE_CONDITION
+#define DECLARE_TRACE_CONDITION(name, proto, args, cond)
#ifdef TRACEPOINTS_ENABLED
#include <trace/trace_events.h>
@@ -129,6 +135,7 @@
#undef DEFINE_EVENT_CONDITION
#undef TRACE_HEADER_MULTI_READ
#undef DECLARE_TRACE
+#undef DECLARE_TRACE_CONDITION
/* Only undef what we defined in this file */
#ifdef UNDEF_TRACE_INCLUDE_FILE
--
2.48.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC PATCH 02/11] rv: Add license identifiers to monitor files
2025-02-06 8:09 [RFC PATCH 00/11] rv: Add scheduler specification monitors Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 01/11] tracing: Fix DECLARE_TRACE_CONDITION Gabriele Monaco
@ 2025-02-06 8:09 ` Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 03/11] sched: Add sched tracepoints for RV task model Gabriele Monaco
` (9 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Gabriele Monaco @ 2025-02-06 8:09 UTC (permalink / raw)
To: linux-kernel, Steven Rostedt, linux-trace-kernel; +Cc: Gabriele Monaco
Some monitor files like the main header and the Kconfig are missing the
license identifier.
Add it to those and make sure the automatic generation script includes
the line in newly created monitors.
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
kernel/trace/rv/monitors/wip/Kconfig | 2 ++
kernel/trace/rv/monitors/wip/wip.h | 1 +
kernel/trace/rv/monitors/wwnr/Kconfig | 2 ++
kernel/trace/rv/monitors/wwnr/wwnr.h | 1 +
tools/verification/dot2/dot2k.py | 1 +
tools/verification/dot2/dot2k_templates/Kconfig | 2 ++
6 files changed, 9 insertions(+)
diff --git a/kernel/trace/rv/monitors/wip/Kconfig b/kernel/trace/rv/monitors/wip/Kconfig
index 3ef664b5cd903..e464b9294865b 100644
--- a/kernel/trace/rv/monitors/wip/Kconfig
+++ b/kernel/trace/rv/monitors/wip/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
config RV_MON_WIP
depends on RV
depends on PREEMPT_TRACER
diff --git a/kernel/trace/rv/monitors/wip/wip.h b/kernel/trace/rv/monitors/wip/wip.h
index 2e373f2c65ed7..c7193748bf369 100644
--- a/kernel/trace/rv/monitors/wip/wip.h
+++ b/kernel/trace/rv/monitors/wip/wip.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Automatically generated C representation of wip automaton
* For further information about this format, see kernel documentation:
diff --git a/kernel/trace/rv/monitors/wwnr/Kconfig b/kernel/trace/rv/monitors/wwnr/Kconfig
index ee741aa6d6b89..d3bfc20037db9 100644
--- a/kernel/trace/rv/monitors/wwnr/Kconfig
+++ b/kernel/trace/rv/monitors/wwnr/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
config RV_MON_WWNR
depends on RV
select DA_MON_EVENTS_ID
diff --git a/kernel/trace/rv/monitors/wwnr/wwnr.h b/kernel/trace/rv/monitors/wwnr/wwnr.h
index d0d9c4b8121b5..0a59d23edf610 100644
--- a/kernel/trace/rv/monitors/wwnr/wwnr.h
+++ b/kernel/trace/rv/monitors/wwnr/wwnr.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Automatically generated C representation of wwnr automaton
* For further information about this format, see kernel documentation:
diff --git a/tools/verification/dot2/dot2k.py b/tools/verification/dot2/dot2k.py
index 7547eb290b7df..153cc14bcca45 100644
--- a/tools/verification/dot2/dot2k.py
+++ b/tools/verification/dot2/dot2k.py
@@ -160,6 +160,7 @@ class dot2k(Dot2c):
def fill_model_h_header(self):
buff = []
+ buff.append("/* SPDX-License-Identifier: GPL-2.0 */")
buff.append("/*")
buff.append(" * Automatically generated C representation of %s automaton" % (self.name))
buff.append(" * For further information about this format, see kernel documentation:")
diff --git a/tools/verification/dot2/dot2k_templates/Kconfig b/tools/verification/dot2/dot2k_templates/Kconfig
index 90cdc1e9379e1..03100eda17075 100644
--- a/tools/verification/dot2/dot2k_templates/Kconfig
+++ b/tools/verification/dot2/dot2k_templates/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
config RV_MON_%%MODEL_NAME_UP%%
depends on RV
select %%MONITOR_CLASS_TYPE%%
--
2.48.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC PATCH 03/11] sched: Add sched tracepoints for RV task model
2025-02-06 8:09 [RFC PATCH 00/11] rv: Add scheduler specification monitors Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 01/11] tracing: Fix DECLARE_TRACE_CONDITION Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 02/11] rv: Add license identifiers to monitor files Gabriele Monaco
@ 2025-02-06 8:09 ` Gabriele Monaco
2025-02-06 8:19 ` Peter Zijlstra
2025-02-06 8:09 ` [RFC PATCH 04/11] rv: Add option for nested monitors and include sched Gabriele Monaco
` (8 subsequent siblings)
11 siblings, 1 reply; 23+ messages in thread
From: Gabriele Monaco @ 2025-02-06 8:09 UTC (permalink / raw)
To: linux-kernel, Steven Rostedt, Ingo Molnar, Peter Zijlstra,
Masami Hiramatsu, linux-trace-kernel
Cc: Gabriele Monaco
Add the following tracepoints:
* sched_entry(bool preempt, ip)
Called while entering __schedule
* sched_exit(bool is_switch, ip)
Called while exiting __schedule
* sched_set_need_resched(task)
Called when we set the need for reschedule
* sched_set_state(task, curr_state, state)
Called when a task changes its state (to and from running)
These tracepoints are useful to describe the Linux task model and are
adapted from the patches by Daniel Bristot de Oliveira
(https://bristot.me/linux-task-model/).
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
include/linux/rv.h | 2 +-
include/linux/sched.h | 7 +++++++
include/trace/events/sched.h | 17 +++++++++++++++++
kernel/sched/core.c | 21 ++++++++++++++++++++-
tools/verification/rv/include/rv.h | 2 +-
5 files changed, 46 insertions(+), 3 deletions(-)
diff --git a/include/linux/rv.h b/include/linux/rv.h
index 8883b41d88ec4..55d458be53a4c 100644
--- a/include/linux/rv.h
+++ b/include/linux/rv.h
@@ -7,7 +7,7 @@
#ifndef _LINUX_RV_H
#define _LINUX_RV_H
-#define MAX_DA_NAME_LEN 24
+#define MAX_DA_NAME_LEN 32
#ifdef CONFIG_RV
/*
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 9632e3318e0d6..af9fa18035c71 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -226,12 +226,14 @@ struct user_event_mm;
#define __set_current_state(state_value) \
do { \
debug_normal_state_change((state_value)); \
+ trace_set_current_state(state_value); \
WRITE_ONCE(current->__state, (state_value)); \
} while (0)
#define set_current_state(state_value) \
do { \
debug_normal_state_change((state_value)); \
+ trace_set_current_state(state_value); \
smp_store_mb(current->__state, (state_value)); \
} while (0)
@@ -247,6 +249,7 @@ struct user_event_mm;
\
raw_spin_lock_irqsave(¤t->pi_lock, flags); \
debug_special_state_change((state_value)); \
+ trace_set_current_state(state_value); \
WRITE_ONCE(current->__state, (state_value)); \
raw_spin_unlock_irqrestore(¤t->pi_lock, flags); \
} while (0)
@@ -282,6 +285,7 @@ struct user_event_mm;
raw_spin_lock(¤t->pi_lock); \
current->saved_state = current->__state; \
debug_rtlock_wait_set_state(); \
+ trace_set_current_state(TASK_RTLOCK_WAIT); \
WRITE_ONCE(current->__state, TASK_RTLOCK_WAIT); \
raw_spin_unlock(¤t->pi_lock); \
} while (0);
@@ -291,6 +295,7 @@ struct user_event_mm;
lockdep_assert_irqs_disabled(); \
raw_spin_lock(¤t->pi_lock); \
debug_rtlock_wait_restore_state(); \
+ trace_set_current_state(TASK_RUNNING); \
WRITE_ONCE(current->__state, current->saved_state); \
current->saved_state = TASK_RUNNING; \
raw_spin_unlock(¤t->pi_lock); \
@@ -327,6 +332,8 @@ extern void io_schedule_finish(int token);
extern long io_schedule_timeout(long timeout);
extern void io_schedule(void);
+extern void trace_set_current_state(int state_value);
+
/**
* struct prev_cputime - snapshot of system and user cputime
* @utime: time spent in user mode
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index 9ea4c404bd4ef..1ac0e23b0733d 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -824,6 +824,23 @@ DECLARE_TRACE(sched_compute_energy_tp,
unsigned long max_util, unsigned long busy_time),
TP_ARGS(p, dst_cpu, energy, max_util, busy_time));
+DECLARE_TRACE(sched_entry_tp,
+ TP_PROTO(bool preempt, unsigned long ip),
+ TP_ARGS(preempt, ip));
+
+DECLARE_TRACE(sched_exit_tp,
+ TP_PROTO(bool is_switch, unsigned long ip),
+ TP_ARGS(is_switch, ip));
+
+DECLARE_TRACE(sched_set_need_resched_tp,
+ TP_PROTO(struct task_struct *tsk),
+ TP_ARGS(tsk));
+
+DECLARE_TRACE_CONDITION(sched_set_state_tp,
+ TP_PROTO(struct task_struct *tsk, int curr_state, int state),
+ TP_ARGS(tsk, curr_state, state),
+ TP_CONDITION(!!curr_state != !!state));
+
#endif /* _TRACE_SCHED_H */
/* This part must be outside protection */
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 165c90ba64ea9..fb5f8aa61ef5d 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -491,6 +491,12 @@ sched_core_dequeue(struct rq *rq, struct task_struct *p, int flags) { }
#endif /* CONFIG_SCHED_CORE */
+void trace_set_current_state(int state_value)
+{
+ trace_sched_set_state_tp(current, current->__state, state_value);
+}
+EXPORT_SYMBOL(trace_set_current_state);
+
/*
* Serialization rules:
*
@@ -1103,6 +1109,8 @@ static void __resched_curr(struct rq *rq, int tif)
cpu = cpu_of(rq);
+ trace_sched_set_need_resched_tp(curr);
+
if (cpu == smp_processor_id()) {
set_ti_thread_flag(cti, tif);
if (tif == TIF_NEED_RESCHED)
@@ -5306,6 +5314,12 @@ asmlinkage __visible void schedule_tail(struct task_struct *prev)
*/
finish_task_switch(prev);
+ /*
+ * This is a special case: the newly created task has just
+ * switched the context for the fist time. It is returning from
+ * schedule for the first time in this path.
+ */
+ trace_sched_exit_tp(true, CALLER_ADDR0);
preempt_enable();
if (current->set_child_tid)
@@ -6649,12 +6663,15 @@ static void __sched notrace __schedule(int sched_mode)
* as a preemption by schedule_debug() and RCU.
*/
bool preempt = sched_mode > SM_NONE;
+ bool is_switch = false;
unsigned long *switch_count;
unsigned long prev_state;
struct rq_flags rf;
struct rq *rq;
int cpu;
+ trace_sched_entry_tp(preempt, CALLER_ADDR0);
+
cpu = smp_processor_id();
rq = cpu_rq(cpu);
prev = rq->curr;
@@ -6722,7 +6739,8 @@ static void __sched notrace __schedule(int sched_mode)
rq->last_seen_need_resched_ns = 0;
#endif
- if (likely(prev != next)) {
+ is_switch = prev != next;
+ if (likely(is_switch)) {
rq->nr_switches++;
/*
* RCU users of rcu_dereference(rq->curr) may not see
@@ -6767,6 +6785,7 @@ static void __sched notrace __schedule(int sched_mode)
__balance_callbacks(rq);
raw_spin_rq_unlock_irq(rq);
}
+ trace_sched_exit_tp(is_switch, CALLER_ADDR0);
}
void __noreturn do_task_dead(void)
diff --git a/tools/verification/rv/include/rv.h b/tools/verification/rv/include/rv.h
index 770fd6da36107..0cab1037a98f7 100644
--- a/tools/verification/rv/include/rv.h
+++ b/tools/verification/rv/include/rv.h
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#define MAX_DESCRIPTION 1024
-#define MAX_DA_NAME_LEN 24
+#define MAX_DA_NAME_LEN 32
struct monitor {
char name[MAX_DA_NAME_LEN];
--
2.48.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC PATCH 04/11] rv: Add option for nested monitors and include sched
2025-02-06 8:09 [RFC PATCH 00/11] rv: Add scheduler specification monitors Gabriele Monaco
` (2 preceding siblings ...)
2025-02-06 8:09 ` [RFC PATCH 03/11] sched: Add sched tracepoints for RV task model Gabriele Monaco
@ 2025-02-06 8:09 ` Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 05/11] rv: Add sco and tss per-cpu monitors Gabriele Monaco
` (7 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Gabriele Monaco @ 2025-02-06 8:09 UTC (permalink / raw)
To: linux-kernel, Steven Rostedt, linux-trace-kernel; +Cc: Gabriele Monaco
Monitors describing complex systems, such as the scheduler, can easily
grow to the point where they are just hard to understand because of the
many possible state transitions.
Often it is possible to break such descriptions into smaller monitors,
sharing some or all events. Enabling those smaller monitors concurrently
is, in fact, testing the system as if we had one single larger monitor.
Splitting models into multiple specification is not only easier to
understand, but gives some more clues when we see errors.
Add the possibility to create container monitors, whose only purpose is
to host other nested monitors. Enabling a container monitor enables all
nested ones, but it's still possible to enable nested monitors
independently.
Add the sched monitor as first container, for now empty.
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
include/linux/rv.h | 2 +-
kernel/trace/rv/Kconfig | 1 +
kernel/trace/rv/Makefile | 1 +
kernel/trace/rv/monitors/sched/Kconfig | 12 ++
kernel/trace/rv/monitors/sched/sched.c | 38 +++++++
kernel/trace/rv/monitors/sched/sched.h | 3 +
kernel/trace/rv/monitors/wip/wip.c | 2 +-
kernel/trace/rv/monitors/wwnr/wwnr.c | 2 +-
kernel/trace/rv/rv.c | 151 +++++++++++++++++++++----
kernel/trace/rv/rv.h | 4 +
kernel/trace/rv/rv_reactors.c | 28 ++++-
11 files changed, 215 insertions(+), 29 deletions(-)
create mode 100644 kernel/trace/rv/monitors/sched/Kconfig
create mode 100644 kernel/trace/rv/monitors/sched/sched.c
create mode 100644 kernel/trace/rv/monitors/sched/sched.h
diff --git a/include/linux/rv.h b/include/linux/rv.h
index 55d458be53a4c..3452b5e4b29e7 100644
--- a/include/linux/rv.h
+++ b/include/linux/rv.h
@@ -56,7 +56,7 @@ struct rv_monitor {
bool rv_monitoring_on(void);
int rv_unregister_monitor(struct rv_monitor *monitor);
-int rv_register_monitor(struct rv_monitor *monitor);
+int rv_register_monitor(struct rv_monitor *monitor, struct rv_monitor *parent);
int rv_get_task_monitor_slot(void);
void rv_put_task_monitor_slot(int slot);
diff --git a/kernel/trace/rv/Kconfig b/kernel/trace/rv/Kconfig
index 8226352a00626..84c98a5327f3e 100644
--- a/kernel/trace/rv/Kconfig
+++ b/kernel/trace/rv/Kconfig
@@ -27,6 +27,7 @@ menuconfig RV
source "kernel/trace/rv/monitors/wip/Kconfig"
source "kernel/trace/rv/monitors/wwnr/Kconfig"
+source "kernel/trace/rv/monitors/sched/Kconfig"
# Add new monitors here
config RV_REACTORS
diff --git a/kernel/trace/rv/Makefile b/kernel/trace/rv/Makefile
index 188b64668e1fa..1c784df03b9a7 100644
--- a/kernel/trace/rv/Makefile
+++ b/kernel/trace/rv/Makefile
@@ -5,6 +5,7 @@ ccflags-y += -I $(src) # needed for trace events
obj-$(CONFIG_RV) += rv.o
obj-$(CONFIG_RV_MON_WIP) += monitors/wip/wip.o
obj-$(CONFIG_RV_MON_WWNR) += monitors/wwnr/wwnr.o
+obj-$(CONFIG_RV_MON_SCHED) += monitors/sched/sched.o
# Add new monitors here
obj-$(CONFIG_RV_REACTORS) += rv_reactors.o
obj-$(CONFIG_RV_REACT_PRINTK) += reactor_printk.o
diff --git a/kernel/trace/rv/monitors/sched/Kconfig b/kernel/trace/rv/monitors/sched/Kconfig
new file mode 100644
index 0000000000000..36c371af53f6f
--- /dev/null
+++ b/kernel/trace/rv/monitors/sched/Kconfig
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+config RV_MON_SCHED
+ depends on RV
+ select DA_MON_EVENTS_IMPLICIT
+ bool "sched monitor"
+ help
+ Collection of monitors to check the scheduler behaves according to specifications.
+ Enable this to enable all scheduler specification supported by the current kernel.
+
+ For further information, see:
+ Documentation/trace/rv/monitor_sched.rst
diff --git a/kernel/trace/rv/monitors/sched/sched.c b/kernel/trace/rv/monitors/sched/sched.c
new file mode 100644
index 0000000000000..905e03c3c934d
--- /dev/null
+++ b/kernel/trace/rv/monitors/sched/sched.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/rv.h>
+
+#define MODULE_NAME "sched"
+
+#include "sched.h"
+
+struct rv_monitor rv_sched;
+
+struct rv_monitor rv_sched = {
+ .name = "sched",
+ .description = "container for several scheduler monitor specifications.",
+ .enable = NULL,
+ .disable = NULL,
+ .reset = NULL,
+ .enabled = 0,
+};
+
+static int __init register_sched(void)
+{
+ rv_register_monitor(&rv_sched, NULL);
+ return 0;
+}
+
+static void __exit unregister_sched(void)
+{
+ rv_unregister_monitor(&rv_sched);
+}
+
+module_init(register_sched);
+module_exit(unregister_sched);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>");
+MODULE_DESCRIPTION("sched: container for several scheduler monitor specifications.");
diff --git a/kernel/trace/rv/monitors/sched/sched.h b/kernel/trace/rv/monitors/sched/sched.h
new file mode 100644
index 0000000000000..ba148dd8d48b1
--- /dev/null
+++ b/kernel/trace/rv/monitors/sched/sched.h
@@ -0,0 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+extern struct rv_monitor rv_sched;
diff --git a/kernel/trace/rv/monitors/wip/wip.c b/kernel/trace/rv/monitors/wip/wip.c
index db7389157c87e..ed758fec8608f 100644
--- a/kernel/trace/rv/monitors/wip/wip.c
+++ b/kernel/trace/rv/monitors/wip/wip.c
@@ -71,7 +71,7 @@ static struct rv_monitor rv_wip = {
static int __init register_wip(void)
{
- rv_register_monitor(&rv_wip);
+ rv_register_monitor(&rv_wip, NULL);
return 0;
}
diff --git a/kernel/trace/rv/monitors/wwnr/wwnr.c b/kernel/trace/rv/monitors/wwnr/wwnr.c
index 3b16994a99845..172f31c4b0f34 100644
--- a/kernel/trace/rv/monitors/wwnr/wwnr.c
+++ b/kernel/trace/rv/monitors/wwnr/wwnr.c
@@ -70,7 +70,7 @@ static struct rv_monitor rv_wwnr = {
static int __init register_wwnr(void)
{
- rv_register_monitor(&rv_wwnr);
+ rv_register_monitor(&rv_wwnr, NULL);
return 0;
}
diff --git a/kernel/trace/rv/rv.c b/kernel/trace/rv/rv.c
index 8657fc8806e7c..6af56dabec1d5 100644
--- a/kernel/trace/rv/rv.c
+++ b/kernel/trace/rv/rv.c
@@ -162,7 +162,7 @@ struct dentry *get_monitors_root(void)
/*
* Interface for the monitor register.
*/
-static LIST_HEAD(rv_monitors_list);
+LIST_HEAD(rv_monitors_list);
static int task_monitor_count;
static bool task_monitor_slots[RV_PER_TASK_MONITORS];
@@ -206,6 +206,28 @@ void rv_put_task_monitor_slot(int slot)
task_monitor_slots[slot] = false;
}
+/*
+ * Monitors with a parent are nested,
+ * Monitors without a parent could be standalone or containers.
+ */
+bool rv_is_nested_monitor(struct rv_monitor_def *mdef)
+{
+ return mdef->parent != NULL;
+}
+
+/*
+ * We set our list to have nested monitors listed after their parent
+ * if a monitor has a child element its a container.
+ * This function would return false for empty containers but we should
+ * not allow them anyway.
+ */
+bool rv_is_container_monitor(struct rv_monitor_def *mdef)
+{
+ struct rv_monitor_def *next = list_next_entry(mdef, list);
+
+ return next->parent == mdef->monitor;
+}
+
/*
* This section collects the monitor/ files and folders.
*/
@@ -229,7 +251,8 @@ static int __rv_disable_monitor(struct rv_monitor_def *mdef, bool sync)
if (mdef->monitor->enabled) {
mdef->monitor->enabled = 0;
- mdef->monitor->disable();
+ if (mdef->monitor->disable)
+ mdef->monitor->disable();
/*
* Wait for the execution of all events to finish.
@@ -243,6 +266,60 @@ static int __rv_disable_monitor(struct rv_monitor_def *mdef, bool sync)
return 0;
}
+static void rv_disable_single(struct rv_monitor_def *mdef)
+{
+ __rv_disable_monitor(mdef, true);
+}
+
+static int rv_enable_single(struct rv_monitor_def *mdef)
+{
+ int retval;
+
+ lockdep_assert_held(&rv_interface_lock);
+
+ if (mdef->monitor->enabled)
+ return 0;
+
+ retval = mdef->monitor->enable();
+
+ if (!retval)
+ mdef->monitor->enabled = 1;
+
+ return retval;
+}
+
+static void rv_disable_container(struct rv_monitor_def *mdef)
+{
+ struct rv_monitor_def *p = mdef;
+ int enabled = 0;
+
+ list_for_each_entry_continue(p, &rv_monitors_list, list) {
+ if (p->parent != mdef->monitor)
+ break;
+ enabled += __rv_disable_monitor(p, false);
+ }
+ if (enabled)
+ tracepoint_synchronize_unregister();
+ mdef->monitor->enabled = 0;
+}
+
+static int rv_enable_container(struct rv_monitor_def *mdef)
+{
+ struct rv_monitor_def *p = mdef;
+ int retval = 0;
+
+ list_for_each_entry_continue(p, &rv_monitors_list, list) {
+ if (retval || p->parent != mdef->monitor)
+ break;
+ retval = rv_enable_single(p);
+ }
+ if (retval)
+ rv_disable_container(mdef);
+ else
+ mdef->monitor->enabled = 1;
+ return retval;
+}
+
/**
* rv_disable_monitor - disable a given runtime monitor
* @mdef: Pointer to the monitor definition structure.
@@ -251,7 +328,11 @@ static int __rv_disable_monitor(struct rv_monitor_def *mdef, bool sync)
*/
int rv_disable_monitor(struct rv_monitor_def *mdef)
{
- __rv_disable_monitor(mdef, true);
+ if (rv_is_container_monitor(mdef))
+ rv_disable_container(mdef);
+ else
+ rv_disable_single(mdef);
+
return 0;
}
@@ -265,15 +346,10 @@ int rv_enable_monitor(struct rv_monitor_def *mdef)
{
int retval;
- lockdep_assert_held(&rv_interface_lock);
-
- if (mdef->monitor->enabled)
- return 0;
-
- retval = mdef->monitor->enable();
-
- if (!retval)
- mdef->monitor->enabled = 1;
+ if (rv_is_container_monitor(mdef))
+ retval = rv_enable_container(mdef);
+ else
+ retval = rv_enable_single(mdef);
return retval;
}
@@ -336,9 +412,9 @@ static const struct file_operations interface_desc_fops = {
* the monitor dir, where the specific options of the monitor
* are exposed.
*/
-static int create_monitor_dir(struct rv_monitor_def *mdef)
+static int create_monitor_dir(struct rv_monitor_def *mdef, struct rv_monitor_def *parent)
{
- struct dentry *root = get_monitors_root();
+ struct dentry *root = parent ? parent->root_d : get_monitors_root();
const char *name = mdef->monitor->name;
struct dentry *tmp;
int retval;
@@ -377,7 +453,11 @@ static int monitors_show(struct seq_file *m, void *p)
{
struct rv_monitor_def *mon_def = p;
- seq_printf(m, "%s\n", mon_def->monitor->name);
+ if (mon_def->parent)
+ seq_printf(m, "%s:%s\n", mon_def->parent->name,
+ mon_def->monitor->name);
+ else
+ seq_printf(m, "%s\n", mon_def->monitor->name);
return 0;
}
@@ -514,7 +594,7 @@ static ssize_t enabled_monitors_write(struct file *filp, const char __user *user
struct rv_monitor_def *mdef;
int retval = -EINVAL;
bool enable = true;
- char *ptr;
+ char *ptr, *tmp;
int len;
if (count < 1 || count > MAX_RV_MONITOR_NAME_SIZE + 1)
@@ -541,6 +621,11 @@ static ssize_t enabled_monitors_write(struct file *filp, const char __user *user
retval = -EINVAL;
+ /* we support 1 nesting level, trim the parent */
+ tmp = strstr(ptr, ":");
+ if (tmp)
+ ptr = tmp+1;
+
list_for_each_entry(mdef, &rv_monitors_list, list) {
if (strcmp(ptr, mdef->monitor->name) != 0)
continue;
@@ -613,7 +698,7 @@ static void reset_all_monitors(void)
struct rv_monitor_def *mdef;
list_for_each_entry(mdef, &rv_monitors_list, list) {
- if (mdef->monitor->enabled)
+ if (mdef->monitor->enabled && mdef->monitor->reset)
mdef->monitor->reset();
}
}
@@ -688,15 +773,15 @@ static void destroy_monitor_dir(struct rv_monitor_def *mdef)
*
* Returns 0 if successful, error otherwise.
*/
-int rv_register_monitor(struct rv_monitor *monitor)
+int rv_register_monitor(struct rv_monitor *monitor, struct rv_monitor *parent)
{
- struct rv_monitor_def *r;
+ struct rv_monitor_def *r, *p = NULL;
int retval = 0;
if (strlen(monitor->name) >= MAX_RV_MONITOR_NAME_SIZE) {
pr_info("Monitor %s has a name longer than %d\n", monitor->name,
MAX_RV_MONITOR_NAME_SIZE);
- return -1;
+ return -EINVAL;
}
mutex_lock(&rv_interface_lock);
@@ -704,11 +789,26 @@ int rv_register_monitor(struct rv_monitor *monitor)
list_for_each_entry(r, &rv_monitors_list, list) {
if (strcmp(monitor->name, r->monitor->name) == 0) {
pr_info("Monitor %s is already registered\n", monitor->name);
- retval = -1;
+ retval = -EEXIST;
goto out_unlock;
}
}
+ if (parent) {
+ list_for_each_entry(r, &rv_monitors_list, list) {
+ if (strcmp(parent->name, r->monitor->name) == 0) {
+ p = r;
+ break;
+ }
+ }
+ }
+
+ if (p && rv_is_nested_monitor(p)) {
+ pr_info("Parent monitor %s is already nested, cannot nest further\n",
+ parent->name);
+ return -EINVAL;
+ }
+
r = kzalloc(sizeof(struct rv_monitor_def), GFP_KERNEL);
if (!r) {
retval = -ENOMEM;
@@ -716,14 +816,19 @@ int rv_register_monitor(struct rv_monitor *monitor)
}
r->monitor = monitor;
+ r->parent = parent;
- retval = create_monitor_dir(r);
+ retval = create_monitor_dir(r, p);
if (retval) {
kfree(r);
goto out_unlock;
}
- list_add_tail(&r->list, &rv_monitors_list);
+ /* keep children close to the parent for easier visualisation */
+ if (p)
+ list_add(&r->list, &p->list);
+ else
+ list_add_tail(&r->list, &rv_monitors_list);
out_unlock:
mutex_unlock(&rv_interface_lock);
diff --git a/kernel/trace/rv/rv.h b/kernel/trace/rv/rv.h
index db6cb0913dbd5..98fca0a1adbc7 100644
--- a/kernel/trace/rv/rv.h
+++ b/kernel/trace/rv/rv.h
@@ -21,6 +21,7 @@ struct rv_interface {
#define MAX_RV_REACTOR_NAME_SIZE 32
extern struct mutex rv_interface_lock;
+extern struct list_head rv_monitors_list;
#ifdef CONFIG_RV_REACTORS
struct rv_reactor_def {
@@ -34,6 +35,7 @@ struct rv_reactor_def {
struct rv_monitor_def {
struct list_head list;
struct rv_monitor *monitor;
+ struct rv_monitor *parent;
struct dentry *root_d;
#ifdef CONFIG_RV_REACTORS
struct rv_reactor_def *rdef;
@@ -45,6 +47,8 @@ struct rv_monitor_def {
struct dentry *get_monitors_root(void);
int rv_disable_monitor(struct rv_monitor_def *mdef);
int rv_enable_monitor(struct rv_monitor_def *mdef);
+bool rv_is_container_monitor(struct rv_monitor_def *mdef);
+bool rv_is_nested_monitor(struct rv_monitor_def *mdef);
#ifdef CONFIG_RV_REACTORS
int reactor_populate_monitor(struct rv_monitor_def *mdef);
diff --git a/kernel/trace/rv/rv_reactors.c b/kernel/trace/rv/rv_reactors.c
index 7b49cbe388d4c..9501ca886d837 100644
--- a/kernel/trace/rv/rv_reactors.c
+++ b/kernel/trace/rv/rv_reactors.c
@@ -158,8 +158,9 @@ static const struct seq_operations monitor_reactors_seq_ops = {
.show = monitor_reactor_show
};
-static void monitor_swap_reactors(struct rv_monitor_def *mdef, struct rv_reactor_def *rdef,
- bool reacting)
+static void monitor_swap_reactors_single(struct rv_monitor_def *mdef,
+ struct rv_reactor_def *rdef,
+ bool reacting, bool nested)
{
bool monitor_enabled;
@@ -179,10 +180,31 @@ static void monitor_swap_reactors(struct rv_monitor_def *mdef, struct rv_reactor
mdef->reacting = reacting;
mdef->monitor->react = rdef->reactor->react;
- if (monitor_enabled)
+ /* enable only once if iterating through a container */
+ if (monitor_enabled && !nested)
rv_enable_monitor(mdef);
}
+static void monitor_swap_reactors(struct rv_monitor_def *mdef,
+ struct rv_reactor_def *rdef, bool reacting)
+{
+ struct rv_monitor_def *p = mdef;
+
+ if (rv_is_container_monitor(mdef))
+ list_for_each_entry_continue(p, &rv_monitors_list, list) {
+ if (p->parent != mdef->monitor)
+ break;
+ monitor_swap_reactors_single(p, rdef, reacting, true);
+ }
+ /*
+ * This call enables and disables the monitor if they were active.
+ * In case of a container, we already disabled all and will enable all.
+ * All nested monitors are enabled also if they were off, we may refine
+ * this logic in the future.
+ */
+ monitor_swap_reactors_single(mdef, rdef, reacting, false);
+}
+
static ssize_t
monitor_reactors_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
--
2.48.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC PATCH 05/11] rv: Add sco and tss per-cpu monitors
2025-02-06 8:09 [RFC PATCH 00/11] rv: Add scheduler specification monitors Gabriele Monaco
` (3 preceding siblings ...)
2025-02-06 8:09 ` [RFC PATCH 04/11] rv: Add option for nested monitors and include sched Gabriele Monaco
@ 2025-02-06 8:09 ` Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 06/11] rv: Add snroc per-task monitor Gabriele Monaco
` (6 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Gabriele Monaco @ 2025-02-06 8:09 UTC (permalink / raw)
To: linux-kernel, Ingo Molnar, Peter Zijlstra, Steven Rostedt,
linux-trace-kernel
Cc: Gabriele Monaco, Juri Lelli, John Kacur, Clark Williams
Add 2 per-cpu monitors as part of the sched model:
* sco: scheduling context operations
Monitor to ensure sched_set_state happens only in thread context
* tss: task switch while scheduling
Monitor to ensure sched_switch happens only in scheduling context
To: Ingo Molnar <mingo@redhat.com>
To: Peter Zijlstra <peterz@infradead.org>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
Cc: Clark Williams <williams@redhat.com>
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
kernel/trace/rv/Kconfig | 2 +
kernel/trace/rv/Makefile | 2 +
kernel/trace/rv/monitors/sched/Kconfig | 2 +
kernel/trace/rv/monitors/sco/Kconfig | 13 ++++
kernel/trace/rv/monitors/sco/sco.c | 88 +++++++++++++++++++++++
kernel/trace/rv/monitors/sco/sco.h | 47 ++++++++++++
kernel/trace/rv/monitors/sco/sco_trace.h | 15 ++++
kernel/trace/rv/monitors/tss/Kconfig | 13 ++++
kernel/trace/rv/monitors/tss/tss.c | 91 ++++++++++++++++++++++++
kernel/trace/rv/monitors/tss/tss.h | 47 ++++++++++++
kernel/trace/rv/monitors/tss/tss_trace.h | 15 ++++
kernel/trace/rv/rv_trace.h | 2 +
tools/verification/models/sched/sco.dot | 18 +++++
tools/verification/models/sched/tss.dot | 18 +++++
14 files changed, 373 insertions(+)
create mode 100644 kernel/trace/rv/monitors/sco/Kconfig
create mode 100644 kernel/trace/rv/monitors/sco/sco.c
create mode 100644 kernel/trace/rv/monitors/sco/sco.h
create mode 100644 kernel/trace/rv/monitors/sco/sco_trace.h
create mode 100644 kernel/trace/rv/monitors/tss/Kconfig
create mode 100644 kernel/trace/rv/monitors/tss/tss.c
create mode 100644 kernel/trace/rv/monitors/tss/tss.h
create mode 100644 kernel/trace/rv/monitors/tss/tss_trace.h
create mode 100644 tools/verification/models/sched/sco.dot
create mode 100644 tools/verification/models/sched/tss.dot
diff --git a/kernel/trace/rv/Kconfig b/kernel/trace/rv/Kconfig
index 84c98a5327f3e..961ac1e487df1 100644
--- a/kernel/trace/rv/Kconfig
+++ b/kernel/trace/rv/Kconfig
@@ -28,6 +28,8 @@ menuconfig RV
source "kernel/trace/rv/monitors/wip/Kconfig"
source "kernel/trace/rv/monitors/wwnr/Kconfig"
source "kernel/trace/rv/monitors/sched/Kconfig"
+source "kernel/trace/rv/monitors/tss/Kconfig"
+source "kernel/trace/rv/monitors/sco/Kconfig"
# Add new monitors here
config RV_REACTORS
diff --git a/kernel/trace/rv/Makefile b/kernel/trace/rv/Makefile
index 1c784df03b9a7..ef2a084ff3102 100644
--- a/kernel/trace/rv/Makefile
+++ b/kernel/trace/rv/Makefile
@@ -6,6 +6,8 @@ obj-$(CONFIG_RV) += rv.o
obj-$(CONFIG_RV_MON_WIP) += monitors/wip/wip.o
obj-$(CONFIG_RV_MON_WWNR) += monitors/wwnr/wwnr.o
obj-$(CONFIG_RV_MON_SCHED) += monitors/sched/sched.o
+obj-$(CONFIG_RV_MON_TSS) += monitors/tss/tss.o
+obj-$(CONFIG_RV_MON_SCO) += monitors/sco/sco.o
# Add new monitors here
obj-$(CONFIG_RV_REACTORS) += rv_reactors.o
obj-$(CONFIG_RV_REACT_PRINTK) += reactor_printk.o
diff --git a/kernel/trace/rv/monitors/sched/Kconfig b/kernel/trace/rv/monitors/sched/Kconfig
index 36c371af53f6f..1eb368573124c 100644
--- a/kernel/trace/rv/monitors/sched/Kconfig
+++ b/kernel/trace/rv/monitors/sched/Kconfig
@@ -3,6 +3,8 @@
config RV_MON_SCHED
depends on RV
select DA_MON_EVENTS_IMPLICIT
+ select RV_MON_TSS
+ select RV_MON_SCO
bool "sched monitor"
help
Collection of monitors to check the scheduler behaves according to specifications.
diff --git a/kernel/trace/rv/monitors/sco/Kconfig b/kernel/trace/rv/monitors/sco/Kconfig
new file mode 100644
index 0000000000000..275f8b935151f
--- /dev/null
+++ b/kernel/trace/rv/monitors/sco/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+config RV_MON_SCO
+ depends on RV
+ depends on RV_MON_SCHED
+ select DA_MON_EVENTS_IMPLICIT
+ bool "sco monitor"
+ help
+ Monitor to ensure sched_set_state happens only in thread context.
+ 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/sco/sco.c b/kernel/trace/rv/monitors/sco/sco.c
new file mode 100644
index 0000000000000..e74476bc2c4ab
--- /dev/null
+++ b/kernel/trace/rv/monitors/sco/sco.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/ftrace.h>
+#include <linux/tracepoint.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/rv.h>
+#include <rv/instrumentation.h>
+#include <rv/da_monitor.h>
+
+#define MODULE_NAME "sco"
+
+#include <trace/events/sched.h>
+#include <rv_trace.h>
+#include <monitors/sched/sched.h>
+
+#include "sco.h"
+
+static struct rv_monitor rv_sco;
+DECLARE_DA_MON_PER_CPU(sco, unsigned char);
+
+static void handle_sched_set_state(void *data, struct task_struct *tsk, int curr_state, int state)
+{
+ da_handle_start_event_sco(sched_set_state_sco);
+}
+
+static void handle_schedule_entry(void *data, bool preempt, unsigned long ip)
+{
+ da_handle_event_sco(schedule_entry_sco);
+}
+
+static void handle_schedule_exit(void *data, bool is_switch, unsigned long ip)
+{
+ da_handle_start_event_sco(schedule_exit_sco);
+}
+
+static int enable_sco(void)
+{
+ int retval;
+
+ retval = da_monitor_init_sco();
+ if (retval)
+ return retval;
+
+ rv_attach_trace_probe("sco", sched_set_state_tp, handle_sched_set_state);
+ rv_attach_trace_probe("sco", sched_entry_tp, handle_schedule_entry);
+ rv_attach_trace_probe("sco", sched_exit_tp, handle_schedule_exit);
+
+ return 0;
+}
+
+static void disable_sco(void)
+{
+ rv_sco.enabled = 0;
+
+ rv_detach_trace_probe("sco", sched_set_state_tp, handle_sched_set_state);
+ rv_detach_trace_probe("sco", sched_entry_tp, handle_schedule_entry);
+ rv_detach_trace_probe("sco", sched_exit_tp, handle_schedule_exit);
+
+ da_monitor_destroy_sco();
+}
+
+static struct rv_monitor rv_sco = {
+ .name = "sco",
+ .description = "scheduling context operations.",
+ .enable = enable_sco,
+ .disable = disable_sco,
+ .reset = da_monitor_reset_all_sco,
+ .enabled = 0,
+};
+
+static int __init register_sco(void)
+{
+ rv_register_monitor(&rv_sco, &rv_sched);
+ return 0;
+}
+
+static void __exit unregister_sco(void)
+{
+ rv_unregister_monitor(&rv_sco);
+}
+
+module_init(register_sco);
+module_exit(unregister_sco);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>");
+MODULE_DESCRIPTION("sco: scheduling context operations.");
diff --git a/kernel/trace/rv/monitors/sco/sco.h b/kernel/trace/rv/monitors/sco/sco.h
new file mode 100644
index 0000000000000..7a4c1f2d5ca1c
--- /dev/null
+++ b/kernel/trace/rv/monitors/sco/sco.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Automatically generated C representation of sco automaton
+ * For further information about this format, see kernel documentation:
+ * Documentation/trace/rv/deterministic_automata.rst
+ */
+
+enum states_sco {
+ thread_context_sco = 0,
+ scheduling_context_sco,
+ state_max_sco
+};
+
+#define INVALID_STATE state_max_sco
+
+enum events_sco {
+ sched_set_state_sco = 0,
+ schedule_entry_sco,
+ schedule_exit_sco,
+ event_max_sco
+};
+
+struct automaton_sco {
+ char *state_names[state_max_sco];
+ char *event_names[event_max_sco];
+ unsigned char function[state_max_sco][event_max_sco];
+ unsigned char initial_state;
+ bool final_states[state_max_sco];
+};
+
+static const struct automaton_sco automaton_sco = {
+ .state_names = {
+ "thread_context",
+ "scheduling_context"
+ },
+ .event_names = {
+ "sched_set_state",
+ "schedule_entry",
+ "schedule_exit"
+ },
+ .function = {
+ { thread_context_sco, scheduling_context_sco, INVALID_STATE },
+ { INVALID_STATE, INVALID_STATE, thread_context_sco },
+ },
+ .initial_state = thread_context_sco,
+ .final_states = { 1, 0 },
+};
diff --git a/kernel/trace/rv/monitors/sco/sco_trace.h b/kernel/trace/rv/monitors/sco/sco_trace.h
new file mode 100644
index 0000000000000..b711cd9024ec4
--- /dev/null
+++ b/kernel/trace/rv/monitors/sco/sco_trace.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Snippet to be included in rv_trace.h
+ */
+
+#ifdef CONFIG_RV_MON_SCO
+DEFINE_EVENT(event_da_monitor, event_sco,
+ TP_PROTO(char *state, char *event, char *next_state, bool final_state),
+ TP_ARGS(state, event, next_state, final_state));
+
+DEFINE_EVENT(error_da_monitor, error_sco,
+ TP_PROTO(char *state, char *event),
+ TP_ARGS(state, event));
+#endif /* CONFIG_RV_MON_SCO */
diff --git a/kernel/trace/rv/monitors/tss/Kconfig b/kernel/trace/rv/monitors/tss/Kconfig
new file mode 100644
index 0000000000000..5d133a76cb74e
--- /dev/null
+++ b/kernel/trace/rv/monitors/tss/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+config RV_MON_TSS
+ depends on RV
+ depends on RV_MON_SCHED
+ select DA_MON_EVENTS_IMPLICIT
+ bool "tss monitor"
+ help
+ Monitor to ensure sched_switch happens only in scheduling context.
+ 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/tss/tss.c b/kernel/trace/rv/monitors/tss/tss.c
new file mode 100644
index 0000000000000..542787e6524fc
--- /dev/null
+++ b/kernel/trace/rv/monitors/tss/tss.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/ftrace.h>
+#include <linux/tracepoint.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/rv.h>
+#include <rv/instrumentation.h>
+#include <rv/da_monitor.h>
+
+#define MODULE_NAME "tss"
+
+#include <trace/events/sched.h>
+#include <rv_trace.h>
+#include <monitors/sched/sched.h>
+
+#include "tss.h"
+
+static struct rv_monitor rv_tss;
+DECLARE_DA_MON_PER_CPU(tss, unsigned char);
+
+static void handle_sched_switch(void *data, bool preempt,
+ struct task_struct *prev,
+ struct task_struct *next,
+ unsigned int prev_state)
+{
+ da_handle_event_tss(sched_switch_tss);
+}
+
+static void handle_schedule_entry(void *data, bool preempt, unsigned long ip)
+{
+ da_handle_event_tss(schedule_entry_tss);
+}
+
+static void handle_schedule_exit(void *data, bool is_switch, unsigned long ip)
+{
+ da_handle_start_event_tss(schedule_exit_tss);
+}
+
+static int enable_tss(void)
+{
+ int retval;
+
+ retval = da_monitor_init_tss();
+ if (retval)
+ return retval;
+
+ rv_attach_trace_probe("tss", sched_switch, handle_sched_switch);
+ rv_attach_trace_probe("tss", sched_entry_tp, handle_schedule_entry);
+ rv_attach_trace_probe("tss", sched_exit_tp, handle_schedule_exit);
+
+ return 0;
+}
+
+static void disable_tss(void)
+{
+ rv_tss.enabled = 0;
+
+ rv_detach_trace_probe("tss", sched_switch, handle_sched_switch);
+ rv_detach_trace_probe("tss", sched_entry_tp, handle_schedule_entry);
+ rv_detach_trace_probe("tss", sched_exit_tp, handle_schedule_exit);
+
+ da_monitor_destroy_tss();
+}
+
+static struct rv_monitor rv_tss = {
+ .name = "tss",
+ .description = "task switch while scheduling.",
+ .enable = enable_tss,
+ .disable = disable_tss,
+ .reset = da_monitor_reset_all_tss,
+ .enabled = 0,
+};
+
+static int __init register_tss(void)
+{
+ rv_register_monitor(&rv_tss, &rv_sched);
+ return 0;
+}
+
+static void __exit unregister_tss(void)
+{
+ rv_unregister_monitor(&rv_tss);
+}
+
+module_init(register_tss);
+module_exit(unregister_tss);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>");
+MODULE_DESCRIPTION("tss: task switch while scheduling.");
diff --git a/kernel/trace/rv/monitors/tss/tss.h b/kernel/trace/rv/monitors/tss/tss.h
new file mode 100644
index 0000000000000..f0a36fda1b873
--- /dev/null
+++ b/kernel/trace/rv/monitors/tss/tss.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Automatically generated C representation of tss automaton
+ * For further information about this format, see kernel documentation:
+ * Documentation/trace/rv/deterministic_automata.rst
+ */
+
+enum states_tss {
+ thread_tss = 0,
+ sched_tss,
+ state_max_tss
+};
+
+#define INVALID_STATE state_max_tss
+
+enum events_tss {
+ sched_switch_tss = 0,
+ schedule_entry_tss,
+ schedule_exit_tss,
+ event_max_tss
+};
+
+struct automaton_tss {
+ char *state_names[state_max_tss];
+ char *event_names[event_max_tss];
+ unsigned char function[state_max_tss][event_max_tss];
+ unsigned char initial_state;
+ bool final_states[state_max_tss];
+};
+
+static const struct automaton_tss automaton_tss = {
+ .state_names = {
+ "thread",
+ "sched"
+ },
+ .event_names = {
+ "sched_switch",
+ "schedule_entry",
+ "schedule_exit"
+ },
+ .function = {
+ { INVALID_STATE, sched_tss, INVALID_STATE },
+ { sched_tss, INVALID_STATE, thread_tss },
+ },
+ .initial_state = thread_tss,
+ .final_states = { 1, 0 },
+};
diff --git a/kernel/trace/rv/monitors/tss/tss_trace.h b/kernel/trace/rv/monitors/tss/tss_trace.h
new file mode 100644
index 0000000000000..4619dbb50cc06
--- /dev/null
+++ b/kernel/trace/rv/monitors/tss/tss_trace.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Snippet to be included in rv_trace.h
+ */
+
+#ifdef CONFIG_RV_MON_TSS
+DEFINE_EVENT(event_da_monitor, event_tss,
+ TP_PROTO(char *state, char *event, char *next_state, bool final_state),
+ TP_ARGS(state, event, next_state, final_state));
+
+DEFINE_EVENT(error_da_monitor, error_tss,
+ TP_PROTO(char *state, char *event),
+ TP_ARGS(state, event));
+#endif /* CONFIG_RV_MON_TSS */
diff --git a/kernel/trace/rv/rv_trace.h b/kernel/trace/rv/rv_trace.h
index 5e65097423ba4..f49e85ca97a1f 100644
--- a/kernel/trace/rv/rv_trace.h
+++ b/kernel/trace/rv/rv_trace.h
@@ -58,6 +58,8 @@ DECLARE_EVENT_CLASS(error_da_monitor,
);
#include <monitors/wip/wip_trace.h>
+#include <monitors/tss/tss_trace.h>
+#include <monitors/sco/sco_trace.h>
// Add new monitors based on CONFIG_DA_MON_EVENTS_IMPLICIT here
#endif /* CONFIG_DA_MON_EVENTS_IMPLICIT */
diff --git a/tools/verification/models/sched/sco.dot b/tools/verification/models/sched/sco.dot
new file mode 100644
index 0000000000000..20b0e3b449a6b
--- /dev/null
+++ b/tools/verification/models/sched/sco.dot
@@ -0,0 +1,18 @@
+digraph state_automaton {
+ center = true;
+ size = "7,11";
+ {node [shape = plaintext] "scheduling_context"};
+ {node [shape = plaintext, style=invis, label=""] "__init_thread_context"};
+ {node [shape = ellipse] "thread_context"};
+ {node [shape = plaintext] "thread_context"};
+ "__init_thread_context" -> "thread_context";
+ "scheduling_context" [label = "scheduling_context"];
+ "scheduling_context" -> "thread_context" [ label = "schedule_exit" ];
+ "thread_context" [label = "thread_context", color = green3];
+ "thread_context" -> "scheduling_context" [ label = "schedule_entry" ];
+ "thread_context" -> "thread_context" [ label = "sched_set_state" ];
+ { rank = min ;
+ "__init_thread_context";
+ "thread_context";
+ }
+}
diff --git a/tools/verification/models/sched/tss.dot b/tools/verification/models/sched/tss.dot
new file mode 100644
index 0000000000000..7dfa1d9121bbd
--- /dev/null
+++ b/tools/verification/models/sched/tss.dot
@@ -0,0 +1,18 @@
+digraph state_automaton {
+ center = true;
+ size = "7,11";
+ {node [shape = plaintext] "sched"};
+ {node [shape = plaintext, style=invis, label=""] "__init_thread"};
+ {node [shape = ellipse] "thread"};
+ {node [shape = plaintext] "thread"};
+ "__init_thread" -> "thread";
+ "sched" [label = "sched"];
+ "sched" -> "sched" [ label = "sched_switch" ];
+ "sched" -> "thread" [ label = "schedule_exit" ];
+ "thread" [label = "thread", color = green3];
+ "thread" -> "sched" [ label = "schedule_entry" ];
+ { rank = min ;
+ "__init_thread";
+ "thread";
+ }
+}
--
2.48.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC PATCH 06/11] rv: Add snroc per-task monitor
2025-02-06 8:09 [RFC PATCH 00/11] rv: Add scheduler specification monitors Gabriele Monaco
` (4 preceding siblings ...)
2025-02-06 8:09 ` [RFC PATCH 05/11] rv: Add sco and tss per-cpu monitors Gabriele Monaco
@ 2025-02-06 8:09 ` Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 07/11] rv: Add scpd, snep and sncid per-cpu monitors Gabriele Monaco
` (5 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Gabriele Monaco @ 2025-02-06 8:09 UTC (permalink / raw)
To: linux-kernel, Ingo Molnar, Peter Zijlstra, Steven Rostedt,
linux-trace-kernel
Cc: Gabriele Monaco, Juri Lelli, John Kacur, Clark Williams
Add a per-task monitor as part of the sched model:
* snroc: set non runnable on its own context
Monitor to ensure set_state happens only in the respective task's context
To: Ingo Molnar <mingo@redhat.com>
To: Peter Zijlstra <peterz@infradead.org>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
Cc: Clark Williams <williams@redhat.com>
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
kernel/trace/rv/Kconfig | 1 +
kernel/trace/rv/Makefile | 1 +
kernel/trace/rv/monitors/sched/Kconfig | 1 +
kernel/trace/rv/monitors/snroc/Kconfig | 13 +++
kernel/trace/rv/monitors/snroc/snroc.c | 87 ++++++++++++++++++++
kernel/trace/rv/monitors/snroc/snroc.h | 47 +++++++++++
kernel/trace/rv/monitors/snroc/snroc_trace.h | 15 ++++
kernel/trace/rv/rv_trace.h | 1 +
tools/verification/models/sched/snroc.dot | 18 ++++
9 files changed, 184 insertions(+)
create mode 100644 kernel/trace/rv/monitors/snroc/Kconfig
create mode 100644 kernel/trace/rv/monitors/snroc/snroc.c
create mode 100644 kernel/trace/rv/monitors/snroc/snroc.h
create mode 100644 kernel/trace/rv/monitors/snroc/snroc_trace.h
create mode 100644 tools/verification/models/sched/snroc.dot
diff --git a/kernel/trace/rv/Kconfig b/kernel/trace/rv/Kconfig
index 961ac1e487df1..c4f1c0fc3abc6 100644
--- a/kernel/trace/rv/Kconfig
+++ b/kernel/trace/rv/Kconfig
@@ -30,6 +30,7 @@ source "kernel/trace/rv/monitors/wwnr/Kconfig"
source "kernel/trace/rv/monitors/sched/Kconfig"
source "kernel/trace/rv/monitors/tss/Kconfig"
source "kernel/trace/rv/monitors/sco/Kconfig"
+source "kernel/trace/rv/monitors/snroc/Kconfig"
# Add new monitors here
config RV_REACTORS
diff --git a/kernel/trace/rv/Makefile b/kernel/trace/rv/Makefile
index ef2a084ff3102..6d11d6400ddd0 100644
--- a/kernel/trace/rv/Makefile
+++ b/kernel/trace/rv/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_RV_MON_WWNR) += monitors/wwnr/wwnr.o
obj-$(CONFIG_RV_MON_SCHED) += monitors/sched/sched.o
obj-$(CONFIG_RV_MON_TSS) += monitors/tss/tss.o
obj-$(CONFIG_RV_MON_SCO) += monitors/sco/sco.o
+obj-$(CONFIG_RV_MON_SNROC) += monitors/snroc/snroc.o
# Add new monitors here
obj-$(CONFIG_RV_REACTORS) += rv_reactors.o
obj-$(CONFIG_RV_REACT_PRINTK) += reactor_printk.o
diff --git a/kernel/trace/rv/monitors/sched/Kconfig b/kernel/trace/rv/monitors/sched/Kconfig
index 1eb368573124c..831d9bcbce94a 100644
--- a/kernel/trace/rv/monitors/sched/Kconfig
+++ b/kernel/trace/rv/monitors/sched/Kconfig
@@ -5,6 +5,7 @@ config RV_MON_SCHED
select DA_MON_EVENTS_IMPLICIT
select RV_MON_TSS
select RV_MON_SCO
+ select RV_MON_SNROC
bool "sched monitor"
help
Collection of monitors to check the scheduler behaves according to specifications.
diff --git a/kernel/trace/rv/monitors/snroc/Kconfig b/kernel/trace/rv/monitors/snroc/Kconfig
new file mode 100644
index 0000000000000..bb648ed1e39f8
--- /dev/null
+++ b/kernel/trace/rv/monitors/snroc/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+config RV_MON_SNROC
+ depends on RV
+ depends on RV_MON_SCHED
+ select DA_MON_EVENTS_ID
+ bool "snroc monitor"
+ help
+ Monitor to ensure sched_set_state happens only in the respective task's context.
+ 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/snroc/snroc.c b/kernel/trace/rv/monitors/snroc/snroc.c
new file mode 100644
index 0000000000000..14c8eca3d5c8e
--- /dev/null
+++ b/kernel/trace/rv/monitors/snroc/snroc.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/ftrace.h>
+#include <linux/tracepoint.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/rv.h>
+#include <rv/instrumentation.h>
+#include <rv/da_monitor.h>
+
+#define MODULE_NAME "snroc"
+
+#include <trace/events/sched.h>
+#include <rv_trace.h>
+#include <monitors/sched/sched.h>
+
+#include "snroc.h"
+
+static struct rv_monitor rv_snroc;
+DECLARE_DA_MON_PER_TASK(snroc, unsigned char);
+
+static void handle_sched_set_state(void *data, struct task_struct *tsk, int curr_state, int state)
+{
+ struct task_struct *p = tsk;
+
+ da_handle_event_snroc(p, sched_set_state_snroc);
+}
+
+static void handle_sched_switch(void *data, bool preempt,
+ struct task_struct *prev,
+ struct task_struct *next,
+ unsigned int prev_state)
+{
+ da_handle_start_event_snroc(prev, sched_switch_out_snroc);
+ da_handle_event_snroc(next, sched_switch_in_snroc);
+}
+
+static int enable_snroc(void)
+{
+ int retval;
+
+ retval = da_monitor_init_snroc();
+ if (retval)
+ return retval;
+
+ rv_attach_trace_probe("snroc", sched_set_state_tp, handle_sched_set_state);
+ rv_attach_trace_probe("snroc", sched_switch, handle_sched_switch);
+
+ return 0;
+}
+
+static void disable_snroc(void)
+{
+ rv_snroc.enabled = 0;
+
+ rv_detach_trace_probe("snroc", sched_set_state_tp, handle_sched_set_state);
+ rv_detach_trace_probe("snroc", sched_switch, handle_sched_switch);
+
+ da_monitor_destroy_snroc();
+}
+
+static struct rv_monitor rv_snroc = {
+ .name = "snroc",
+ .description = "set non runnable on its own context.",
+ .enable = enable_snroc,
+ .disable = disable_snroc,
+ .reset = da_monitor_reset_all_snroc,
+ .enabled = 0,
+};
+
+static int __init register_snroc(void)
+{
+ rv_register_monitor(&rv_snroc, &rv_sched);
+ return 0;
+}
+
+static void __exit unregister_snroc(void)
+{
+ rv_unregister_monitor(&rv_snroc);
+}
+
+module_init(register_snroc);
+module_exit(unregister_snroc);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>");
+MODULE_DESCRIPTION("snroc: set non runnable on its own context.");
diff --git a/kernel/trace/rv/monitors/snroc/snroc.h b/kernel/trace/rv/monitors/snroc/snroc.h
new file mode 100644
index 0000000000000..c3650a2b1b107
--- /dev/null
+++ b/kernel/trace/rv/monitors/snroc/snroc.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Automatically generated C representation of snroc automaton
+ * For further information about this format, see kernel documentation:
+ * Documentation/trace/rv/deterministic_automata.rst
+ */
+
+enum states_snroc {
+ other_context_snroc = 0,
+ own_context_snroc,
+ state_max_snroc
+};
+
+#define INVALID_STATE state_max_snroc
+
+enum events_snroc {
+ sched_set_state_snroc = 0,
+ sched_switch_in_snroc,
+ sched_switch_out_snroc,
+ event_max_snroc
+};
+
+struct automaton_snroc {
+ char *state_names[state_max_snroc];
+ char *event_names[event_max_snroc];
+ unsigned char function[state_max_snroc][event_max_snroc];
+ unsigned char initial_state;
+ bool final_states[state_max_snroc];
+};
+
+static const struct automaton_snroc automaton_snroc = {
+ .state_names = {
+ "other_context",
+ "own_context"
+ },
+ .event_names = {
+ "sched_set_state",
+ "sched_switch_in",
+ "sched_switch_out"
+ },
+ .function = {
+ { INVALID_STATE, own_context_snroc, INVALID_STATE },
+ { own_context_snroc, INVALID_STATE, other_context_snroc },
+ },
+ .initial_state = other_context_snroc,
+ .final_states = { 1, 0 },
+};
diff --git a/kernel/trace/rv/monitors/snroc/snroc_trace.h b/kernel/trace/rv/monitors/snroc/snroc_trace.h
new file mode 100644
index 0000000000000..50114cef51229
--- /dev/null
+++ b/kernel/trace/rv/monitors/snroc/snroc_trace.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Snippet to be included in rv_trace.h
+ */
+
+#ifdef CONFIG_RV_MON_SNROC
+DEFINE_EVENT(event_da_monitor_id, event_snroc,
+ TP_PROTO(int id, char *state, char *event, char *next_state, bool final_state),
+ TP_ARGS(id, state, event, next_state, final_state));
+
+DEFINE_EVENT(error_da_monitor_id, error_snroc,
+ TP_PROTO(int id, char *state, char *event),
+ TP_ARGS(id, state, event));
+#endif /* CONFIG_RV_MON_SNROC */
diff --git a/kernel/trace/rv/rv_trace.h b/kernel/trace/rv/rv_trace.h
index f49e85ca97a1f..a533bc29cfddf 100644
--- a/kernel/trace/rv/rv_trace.h
+++ b/kernel/trace/rv/rv_trace.h
@@ -120,6 +120,7 @@ DECLARE_EVENT_CLASS(error_da_monitor_id,
);
#include <monitors/wwnr/wwnr_trace.h>
+#include <monitors/snroc/snroc_trace.h>
// Add new monitors based on CONFIG_DA_MON_EVENTS_ID here
#endif /* CONFIG_DA_MON_EVENTS_ID */
diff --git a/tools/verification/models/sched/snroc.dot b/tools/verification/models/sched/snroc.dot
new file mode 100644
index 0000000000000..8b71c32d4dca4
--- /dev/null
+++ b/tools/verification/models/sched/snroc.dot
@@ -0,0 +1,18 @@
+digraph state_automaton {
+ center = true;
+ size = "7,11";
+ {node [shape = plaintext, style=invis, label=""] "__init_other_context"};
+ {node [shape = ellipse] "other_context"};
+ {node [shape = plaintext] "other_context"};
+ {node [shape = plaintext] "own_context"};
+ "__init_other_context" -> "other_context";
+ "other_context" [label = "other_context", color = green3];
+ "other_context" -> "own_context" [ label = "sched_switch_in" ];
+ "own_context" [label = "own_context"];
+ "own_context" -> "other_context" [ label = "sched_switch_out" ];
+ "own_context" -> "own_context" [ label = "sched_set_state" ];
+ { rank = min ;
+ "__init_other_context";
+ "other_context";
+ }
+}
--
2.48.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC PATCH 07/11] rv: Add scpd, snep and sncid per-cpu monitors
2025-02-06 8:09 [RFC PATCH 00/11] rv: Add scheduler specification monitors Gabriele Monaco
` (5 preceding siblings ...)
2025-02-06 8:09 ` [RFC PATCH 06/11] rv: Add snroc per-task monitor Gabriele Monaco
@ 2025-02-06 8:09 ` Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 08/11] tools/rv: Add support for nested monitors Gabriele Monaco
` (4 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Gabriele Monaco @ 2025-02-06 8:09 UTC (permalink / raw)
To: linux-kernel, Ingo Molnar, Peter Zijlstra, Steven Rostedt,
linux-trace-kernel
Cc: Gabriele Monaco, Juri Lelli, John Kacur, Clark Williams
Add 3 per-cpu monitors as part of the sched model:
* scpd: schedule called with preemption disabled
Monitor to ensure schedule is called with preemption disabled
* snep: schedule does not enable preempt
Monitor to ensure schedule does not enable preempt
* sncid: schedule not called with interrupt disabled
Monitor to ensure schedule is not called with interrupt disabled
To: Ingo Molnar <mingo@redhat.com>
To: Peter Zijlstra <peterz@infradead.org>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
Cc: Clark Williams <williams@redhat.com>
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
kernel/trace/rv/Kconfig | 3 +
kernel/trace/rv/Makefile | 3 +
kernel/trace/rv/monitors/sched/Kconfig | 3 +
kernel/trace/rv/monitors/scpd/Kconfig | 14 +++
kernel/trace/rv/monitors/scpd/scpd.c | 96 ++++++++++++++++++++
kernel/trace/rv/monitors/scpd/scpd.h | 49 ++++++++++
kernel/trace/rv/monitors/scpd/scpd_trace.h | 15 +++
kernel/trace/rv/monitors/sncid/Kconfig | 14 +++
kernel/trace/rv/monitors/sncid/sncid.c | 96 ++++++++++++++++++++
kernel/trace/rv/monitors/sncid/sncid.h | 49 ++++++++++
kernel/trace/rv/monitors/sncid/sncid_trace.h | 15 +++
kernel/trace/rv/monitors/snep/Kconfig | 14 +++
kernel/trace/rv/monitors/snep/snep.c | 96 ++++++++++++++++++++
kernel/trace/rv/monitors/snep/snep.h | 49 ++++++++++
kernel/trace/rv/monitors/snep/snep_trace.h | 15 +++
kernel/trace/rv/rv_trace.h | 3 +
tools/verification/models/sched/scpd.dot | 18 ++++
tools/verification/models/sched/sncid.dot | 18 ++++
tools/verification/models/sched/snep.dot | 18 ++++
19 files changed, 588 insertions(+)
create mode 100644 kernel/trace/rv/monitors/scpd/Kconfig
create mode 100644 kernel/trace/rv/monitors/scpd/scpd.c
create mode 100644 kernel/trace/rv/monitors/scpd/scpd.h
create mode 100644 kernel/trace/rv/monitors/scpd/scpd_trace.h
create mode 100644 kernel/trace/rv/monitors/sncid/Kconfig
create mode 100644 kernel/trace/rv/monitors/sncid/sncid.c
create mode 100644 kernel/trace/rv/monitors/sncid/sncid.h
create mode 100644 kernel/trace/rv/monitors/sncid/sncid_trace.h
create mode 100644 kernel/trace/rv/monitors/snep/Kconfig
create mode 100644 kernel/trace/rv/monitors/snep/snep.c
create mode 100644 kernel/trace/rv/monitors/snep/snep.h
create mode 100644 kernel/trace/rv/monitors/snep/snep_trace.h
create mode 100644 tools/verification/models/sched/scpd.dot
create mode 100644 tools/verification/models/sched/sncid.dot
create mode 100644 tools/verification/models/sched/snep.dot
diff --git a/kernel/trace/rv/Kconfig b/kernel/trace/rv/Kconfig
index c4f1c0fc3abc6..b39f36013ef23 100644
--- a/kernel/trace/rv/Kconfig
+++ b/kernel/trace/rv/Kconfig
@@ -31,6 +31,9 @@ source "kernel/trace/rv/monitors/sched/Kconfig"
source "kernel/trace/rv/monitors/tss/Kconfig"
source "kernel/trace/rv/monitors/sco/Kconfig"
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/sncid/Kconfig"
# Add new monitors here
config RV_REACTORS
diff --git a/kernel/trace/rv/Makefile b/kernel/trace/rv/Makefile
index 6d11d6400ddd0..f9b2cd0483c3c 100644
--- a/kernel/trace/rv/Makefile
+++ b/kernel/trace/rv/Makefile
@@ -9,6 +9,9 @@ obj-$(CONFIG_RV_MON_SCHED) += monitors/sched/sched.o
obj-$(CONFIG_RV_MON_TSS) += monitors/tss/tss.o
obj-$(CONFIG_RV_MON_SCO) += monitors/sco/sco.o
obj-$(CONFIG_RV_MON_SNROC) += monitors/snroc/snroc.o
+obj-$(CONFIG_RV_MON_SCPD) += monitors/scpd/scpd.o
+obj-$(CONFIG_RV_MON_SNEP) += monitors/snep/snep.o
+obj-$(CONFIG_RV_MON_SNCID) += monitors/sncid/sncid.o
# Add new monitors here
obj-$(CONFIG_RV_REACTORS) += rv_reactors.o
obj-$(CONFIG_RV_REACT_PRINTK) += reactor_printk.o
diff --git a/kernel/trace/rv/monitors/sched/Kconfig b/kernel/trace/rv/monitors/sched/Kconfig
index 831d9bcbce94a..89d272d902f48 100644
--- a/kernel/trace/rv/monitors/sched/Kconfig
+++ b/kernel/trace/rv/monitors/sched/Kconfig
@@ -6,6 +6,9 @@ config RV_MON_SCHED
select RV_MON_TSS
select RV_MON_SCO
select RV_MON_SNROC
+ select RV_MON_SCPD if PREEMPT_TRACER
+ select RV_MON_SNEP if PREEMPT_TRACER
+ select RV_MON_SNCID if IRQSOFF_TRACER
bool "sched monitor"
help
Collection of monitors to check the scheduler behaves according to specifications.
diff --git a/kernel/trace/rv/monitors/scpd/Kconfig b/kernel/trace/rv/monitors/scpd/Kconfig
new file mode 100644
index 0000000000000..1f81da0a3f7c1
--- /dev/null
+++ b/kernel/trace/rv/monitors/scpd/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+config RV_MON_SCPD
+ depends on RV
+ depends on RV_MON_SCHED
+ depends on PREEMPT_TRACER
+ select DA_MON_EVENTS_IMPLICIT
+ bool "scpd monitor"
+ help
+ Monitor to ensure schedule is called with preemption disabled.
+ 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/scpd/scpd.c b/kernel/trace/rv/monitors/scpd/scpd.c
new file mode 100644
index 0000000000000..cbdd6a5f8d7fd
--- /dev/null
+++ b/kernel/trace/rv/monitors/scpd/scpd.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/ftrace.h>
+#include <linux/tracepoint.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/rv.h>
+#include <rv/instrumentation.h>
+#include <rv/da_monitor.h>
+
+#define MODULE_NAME "scpd"
+
+#include <trace/events/sched.h>
+#include <trace/events/preemptirq.h>
+#include <rv_trace.h>
+#include <monitors/sched/sched.h>
+
+#include "scpd.h"
+
+static struct rv_monitor rv_scpd;
+DECLARE_DA_MON_PER_CPU(scpd, unsigned char);
+
+static void handle_preempt_disable(void *data, unsigned long ip, unsigned long parent_ip)
+{
+ da_handle_event_scpd(preempt_disable_scpd);
+}
+
+static void handle_preempt_enable(void *data, unsigned long ip, unsigned long parent_ip)
+{
+ da_handle_start_event_scpd(preempt_enable_scpd);
+}
+
+static void handle_schedule_entry(void *data, bool preempt, unsigned long ip)
+{
+ da_handle_event_scpd(schedule_entry_scpd);
+}
+
+static void handle_schedule_exit(void *data, bool is_switch, unsigned long ip)
+{
+ da_handle_event_scpd(schedule_exit_scpd);
+}
+
+static int enable_scpd(void)
+{
+ int retval;
+
+ retval = da_monitor_init_scpd();
+ if (retval)
+ return retval;
+
+ rv_attach_trace_probe("scpd", preempt_disable, handle_preempt_disable);
+ rv_attach_trace_probe("scpd", preempt_enable, handle_preempt_enable);
+ rv_attach_trace_probe("scpd", sched_entry_tp, handle_schedule_entry);
+ rv_attach_trace_probe("scpd", sched_exit_tp, handle_schedule_exit);
+
+ return 0;
+}
+
+static void disable_scpd(void)
+{
+ rv_scpd.enabled = 0;
+
+ rv_detach_trace_probe("scpd", preempt_disable, handle_preempt_disable);
+ rv_detach_trace_probe("scpd", preempt_enable, handle_preempt_enable);
+ rv_detach_trace_probe("scpd", sched_entry_tp, handle_schedule_entry);
+ rv_detach_trace_probe("scpd", sched_exit_tp, handle_schedule_exit);
+
+ da_monitor_destroy_scpd();
+}
+
+static struct rv_monitor rv_scpd = {
+ .name = "scpd",
+ .description = "schedule called with preemption disabled.",
+ .enable = enable_scpd,
+ .disable = disable_scpd,
+ .reset = da_monitor_reset_all_scpd,
+ .enabled = 0,
+};
+
+static int __init register_scpd(void)
+{
+ rv_register_monitor(&rv_scpd, &rv_sched);
+ return 0;
+}
+
+static void __exit unregister_scpd(void)
+{
+ rv_unregister_monitor(&rv_scpd);
+}
+
+module_init(register_scpd);
+module_exit(unregister_scpd);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>");
+MODULE_DESCRIPTION("scpd: schedule called with preemption disabled.");
diff --git a/kernel/trace/rv/monitors/scpd/scpd.h b/kernel/trace/rv/monitors/scpd/scpd.h
new file mode 100644
index 0000000000000..295f735a58110
--- /dev/null
+++ b/kernel/trace/rv/monitors/scpd/scpd.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Automatically generated C representation of scpd automaton
+ * For further information about this format, see kernel documentation:
+ * Documentation/trace/rv/deterministic_automata.rst
+ */
+
+enum states_scpd {
+ cant_sched_scpd = 0,
+ can_sched_scpd,
+ state_max_scpd
+};
+
+#define INVALID_STATE state_max_scpd
+
+enum events_scpd {
+ preempt_disable_scpd = 0,
+ preempt_enable_scpd,
+ schedule_entry_scpd,
+ schedule_exit_scpd,
+ event_max_scpd
+};
+
+struct automaton_scpd {
+ char *state_names[state_max_scpd];
+ char *event_names[event_max_scpd];
+ unsigned char function[state_max_scpd][event_max_scpd];
+ unsigned char initial_state;
+ bool final_states[state_max_scpd];
+};
+
+static const struct automaton_scpd automaton_scpd = {
+ .state_names = {
+ "cant_sched",
+ "can_sched"
+ },
+ .event_names = {
+ "preempt_disable",
+ "preempt_enable",
+ "schedule_entry",
+ "schedule_exit"
+ },
+ .function = {
+ { can_sched_scpd, INVALID_STATE, INVALID_STATE, INVALID_STATE },
+ { INVALID_STATE, cant_sched_scpd, can_sched_scpd, can_sched_scpd },
+ },
+ .initial_state = cant_sched_scpd,
+ .final_states = { 1, 0 },
+};
diff --git a/kernel/trace/rv/monitors/scpd/scpd_trace.h b/kernel/trace/rv/monitors/scpd/scpd_trace.h
new file mode 100644
index 0000000000000..6b0f4aa4732e8
--- /dev/null
+++ b/kernel/trace/rv/monitors/scpd/scpd_trace.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Snippet to be included in rv_trace.h
+ */
+
+#ifdef CONFIG_RV_MON_SCPD
+DEFINE_EVENT(event_da_monitor, event_scpd,
+ TP_PROTO(char *state, char *event, char *next_state, bool final_state),
+ TP_ARGS(state, event, next_state, final_state));
+
+DEFINE_EVENT(error_da_monitor, error_scpd,
+ TP_PROTO(char *state, char *event),
+ TP_ARGS(state, event));
+#endif /* CONFIG_RV_MON_SCPD */
diff --git a/kernel/trace/rv/monitors/sncid/Kconfig b/kernel/trace/rv/monitors/sncid/Kconfig
new file mode 100644
index 0000000000000..12d05512f86e7
--- /dev/null
+++ b/kernel/trace/rv/monitors/sncid/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+config RV_MON_SNCID
+ depends on RV
+ depends on RV_MON_SCHED
+ depends on IRQSOFF_TRACER
+ select DA_MON_EVENTS_IMPLICIT
+ bool "sncid monitor"
+ help
+ Monitor to ensure schedule is not called with interrupt disabled.
+ 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/sncid/sncid.c b/kernel/trace/rv/monitors/sncid/sncid.c
new file mode 100644
index 0000000000000..f5037cd6214c2
--- /dev/null
+++ b/kernel/trace/rv/monitors/sncid/sncid.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/ftrace.h>
+#include <linux/tracepoint.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/rv.h>
+#include <rv/instrumentation.h>
+#include <rv/da_monitor.h>
+
+#define MODULE_NAME "sncid"
+
+#include <trace/events/sched.h>
+#include <trace/events/preemptirq.h>
+#include <rv_trace.h>
+#include <monitors/sched/sched.h>
+
+#include "sncid.h"
+
+static struct rv_monitor rv_sncid;
+DECLARE_DA_MON_PER_CPU(sncid, unsigned char);
+
+static void handle_irq_disable(void *data, unsigned long ip, unsigned long parent_ip)
+{
+ da_handle_event_sncid(irq_disable_sncid);
+}
+
+static void handle_irq_enable(void *data, unsigned long ip, unsigned long parent_ip)
+{
+ da_handle_start_event_sncid(irq_enable_sncid);
+}
+
+static void handle_schedule_entry(void *data, bool preempt, unsigned long ip)
+{
+ da_handle_start_event_sncid(schedule_entry_sncid);
+}
+
+static void handle_schedule_exit(void *data, bool is_switch, unsigned long ip)
+{
+ da_handle_start_event_sncid(schedule_exit_sncid);
+}
+
+static int enable_sncid(void)
+{
+ int retval;
+
+ retval = da_monitor_init_sncid();
+ if (retval)
+ return retval;
+
+ rv_attach_trace_probe("sncid", irq_disable, handle_irq_disable);
+ rv_attach_trace_probe("sncid", irq_enable, handle_irq_enable);
+ rv_attach_trace_probe("sncid", sched_entry_tp, handle_schedule_entry);
+ rv_attach_trace_probe("sncid", sched_exit_tp, handle_schedule_exit);
+
+ return 0;
+}
+
+static void disable_sncid(void)
+{
+ rv_sncid.enabled = 0;
+
+ rv_detach_trace_probe("sncid", irq_disable, handle_irq_disable);
+ rv_detach_trace_probe("sncid", irq_enable, handle_irq_enable);
+ rv_detach_trace_probe("sncid", sched_entry_tp, handle_schedule_entry);
+ rv_detach_trace_probe("sncid", sched_exit_tp, handle_schedule_exit);
+
+ da_monitor_destroy_sncid();
+}
+
+static struct rv_monitor rv_sncid = {
+ .name = "sncid",
+ .description = "schedule not called with interrupt disabled.",
+ .enable = enable_sncid,
+ .disable = disable_sncid,
+ .reset = da_monitor_reset_all_sncid,
+ .enabled = 0,
+};
+
+static int __init register_sncid(void)
+{
+ rv_register_monitor(&rv_sncid, &rv_sched);
+ return 0;
+}
+
+static void __exit unregister_sncid(void)
+{
+ rv_unregister_monitor(&rv_sncid);
+}
+
+module_init(register_sncid);
+module_exit(unregister_sncid);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>");
+MODULE_DESCRIPTION("sncid: schedule not called with interrupt disabled.");
diff --git a/kernel/trace/rv/monitors/sncid/sncid.h b/kernel/trace/rv/monitors/sncid/sncid.h
new file mode 100644
index 0000000000000..21304725142bc
--- /dev/null
+++ b/kernel/trace/rv/monitors/sncid/sncid.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Automatically generated C representation of sncid automaton
+ * For further information about this format, see kernel documentation:
+ * Documentation/trace/rv/deterministic_automata.rst
+ */
+
+enum states_sncid {
+ can_sched_sncid = 0,
+ cant_sched_sncid,
+ state_max_sncid
+};
+
+#define INVALID_STATE state_max_sncid
+
+enum events_sncid {
+ irq_disable_sncid = 0,
+ irq_enable_sncid,
+ schedule_entry_sncid,
+ schedule_exit_sncid,
+ event_max_sncid
+};
+
+struct automaton_sncid {
+ char *state_names[state_max_sncid];
+ char *event_names[event_max_sncid];
+ unsigned char function[state_max_sncid][event_max_sncid];
+ unsigned char initial_state;
+ bool final_states[state_max_sncid];
+};
+
+static const struct automaton_sncid automaton_sncid = {
+ .state_names = {
+ "can_sched",
+ "cant_sched"
+ },
+ .event_names = {
+ "irq_disable",
+ "irq_enable",
+ "schedule_entry",
+ "schedule_exit"
+ },
+ .function = {
+ { cant_sched_sncid, INVALID_STATE, can_sched_sncid, can_sched_sncid },
+ { INVALID_STATE, can_sched_sncid, INVALID_STATE, INVALID_STATE },
+ },
+ .initial_state = can_sched_sncid,
+ .final_states = { 1, 0 },
+};
diff --git a/kernel/trace/rv/monitors/sncid/sncid_trace.h b/kernel/trace/rv/monitors/sncid/sncid_trace.h
new file mode 100644
index 0000000000000..3ce42a57671d4
--- /dev/null
+++ b/kernel/trace/rv/monitors/sncid/sncid_trace.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Snippet to be included in rv_trace.h
+ */
+
+#ifdef CONFIG_RV_MON_SNCID
+DEFINE_EVENT(event_da_monitor, event_sncid,
+ TP_PROTO(char *state, char *event, char *next_state, bool final_state),
+ TP_ARGS(state, event, next_state, final_state));
+
+DEFINE_EVENT(error_da_monitor, error_sncid,
+ TP_PROTO(char *state, char *event),
+ TP_ARGS(state, event));
+#endif /* CONFIG_RV_MON_SNCID */
diff --git a/kernel/trace/rv/monitors/snep/Kconfig b/kernel/trace/rv/monitors/snep/Kconfig
new file mode 100644
index 0000000000000..83b6ba9033ccf
--- /dev/null
+++ b/kernel/trace/rv/monitors/snep/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+config RV_MON_SNEP
+ depends on RV
+ depends on RV_MON_SCHED
+ depends on PREEMPT_TRACER
+ select DA_MON_EVENTS_IMPLICIT
+ bool "snep monitor"
+ help
+ Monitor to ensure schedule does not enable preempt.
+ 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/snep/snep.c b/kernel/trace/rv/monitors/snep/snep.c
new file mode 100644
index 0000000000000..0076ba6d7ea44
--- /dev/null
+++ b/kernel/trace/rv/monitors/snep/snep.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/ftrace.h>
+#include <linux/tracepoint.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/rv.h>
+#include <rv/instrumentation.h>
+#include <rv/da_monitor.h>
+
+#define MODULE_NAME "snep"
+
+#include <trace/events/sched.h>
+#include <trace/events/preemptirq.h>
+#include <rv_trace.h>
+#include <monitors/sched/sched.h>
+
+#include "snep.h"
+
+static struct rv_monitor rv_snep;
+DECLARE_DA_MON_PER_CPU(snep, unsigned char);
+
+static void handle_preempt_disable(void *data, unsigned long ip, unsigned long parent_ip)
+{
+ da_handle_start_event_snep(preempt_disable_snep);
+}
+
+static void handle_preempt_enable(void *data, unsigned long ip, unsigned long parent_ip)
+{
+ da_handle_start_event_snep(preempt_enable_snep);
+}
+
+static void handle_schedule_entry(void *data, bool preempt, unsigned long ip)
+{
+ da_handle_event_snep(schedule_entry_snep);
+}
+
+static void handle_schedule_exit(void *data, bool is_switch, unsigned long ip)
+{
+ da_handle_start_event_snep(schedule_exit_snep);
+}
+
+static int enable_snep(void)
+{
+ int retval;
+
+ retval = da_monitor_init_snep();
+ if (retval)
+ return retval;
+
+ rv_attach_trace_probe("snep", preempt_disable, handle_preempt_disable);
+ rv_attach_trace_probe("snep", preempt_enable, handle_preempt_enable);
+ rv_attach_trace_probe("snep", sched_entry_tp, handle_schedule_entry);
+ rv_attach_trace_probe("snep", sched_exit_tp, handle_schedule_exit);
+
+ return 0;
+}
+
+static void disable_snep(void)
+{
+ rv_snep.enabled = 0;
+
+ rv_detach_trace_probe("snep", preempt_disable, handle_preempt_disable);
+ rv_detach_trace_probe("snep", preempt_enable, handle_preempt_enable);
+ rv_detach_trace_probe("snep", sched_entry_tp, handle_schedule_entry);
+ rv_detach_trace_probe("snep", sched_exit_tp, handle_schedule_exit);
+
+ da_monitor_destroy_snep();
+}
+
+static struct rv_monitor rv_snep = {
+ .name = "snep",
+ .description = "schedule does not enable preempt.",
+ .enable = enable_snep,
+ .disable = disable_snep,
+ .reset = da_monitor_reset_all_snep,
+ .enabled = 0,
+};
+
+static int __init register_snep(void)
+{
+ rv_register_monitor(&rv_snep, &rv_sched);
+ return 0;
+}
+
+static void __exit unregister_snep(void)
+{
+ rv_unregister_monitor(&rv_snep);
+}
+
+module_init(register_snep);
+module_exit(unregister_snep);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>");
+MODULE_DESCRIPTION("snep: schedule does not enable preempt.");
diff --git a/kernel/trace/rv/monitors/snep/snep.h b/kernel/trace/rv/monitors/snep/snep.h
new file mode 100644
index 0000000000000..6d16b9ad931e1
--- /dev/null
+++ b/kernel/trace/rv/monitors/snep/snep.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Automatically generated C representation of snep automaton
+ * For further information about this format, see kernel documentation:
+ * Documentation/trace/rv/deterministic_automata.rst
+ */
+
+enum states_snep {
+ non_scheduling_context_snep = 0,
+ scheduling_contex_snep,
+ state_max_snep
+};
+
+#define INVALID_STATE state_max_snep
+
+enum events_snep {
+ preempt_disable_snep = 0,
+ preempt_enable_snep,
+ schedule_entry_snep,
+ schedule_exit_snep,
+ event_max_snep
+};
+
+struct automaton_snep {
+ char *state_names[state_max_snep];
+ char *event_names[event_max_snep];
+ unsigned char function[state_max_snep][event_max_snep];
+ unsigned char initial_state;
+ bool final_states[state_max_snep];
+};
+
+static const struct automaton_snep automaton_snep = {
+ .state_names = {
+ "non_scheduling_context",
+ "scheduling_contex"
+ },
+ .event_names = {
+ "preempt_disable",
+ "preempt_enable",
+ "schedule_entry",
+ "schedule_exit"
+ },
+ .function = {
+ { non_scheduling_context_snep, non_scheduling_context_snep, scheduling_contex_snep, INVALID_STATE },
+ { INVALID_STATE, INVALID_STATE, INVALID_STATE, non_scheduling_context_snep },
+ },
+ .initial_state = non_scheduling_context_snep,
+ .final_states = { 1, 0 },
+};
diff --git a/kernel/trace/rv/monitors/snep/snep_trace.h b/kernel/trace/rv/monitors/snep/snep_trace.h
new file mode 100644
index 0000000000000..01aad49a949a8
--- /dev/null
+++ b/kernel/trace/rv/monitors/snep/snep_trace.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Snippet to be included in rv_trace.h
+ */
+
+#ifdef CONFIG_RV_MON_SNEP
+DEFINE_EVENT(event_da_monitor, event_snep,
+ TP_PROTO(char *state, char *event, char *next_state, bool final_state),
+ TP_ARGS(state, event, next_state, final_state));
+
+DEFINE_EVENT(error_da_monitor, error_snep,
+ TP_PROTO(char *state, char *event),
+ TP_ARGS(state, event));
+#endif /* CONFIG_RV_MON_SNEP */
diff --git a/kernel/trace/rv/rv_trace.h b/kernel/trace/rv/rv_trace.h
index a533bc29cfddf..422b75f58891e 100644
--- a/kernel/trace/rv/rv_trace.h
+++ b/kernel/trace/rv/rv_trace.h
@@ -60,6 +60,9 @@ DECLARE_EVENT_CLASS(error_da_monitor,
#include <monitors/wip/wip_trace.h>
#include <monitors/tss/tss_trace.h>
#include <monitors/sco/sco_trace.h>
+#include <monitors/scpd/scpd_trace.h>
+#include <monitors/snep/snep_trace.h>
+#include <monitors/sncid/sncid_trace.h>
// Add new monitors based on CONFIG_DA_MON_EVENTS_IMPLICIT here
#endif /* CONFIG_DA_MON_EVENTS_IMPLICIT */
diff --git a/tools/verification/models/sched/scpd.dot b/tools/verification/models/sched/scpd.dot
new file mode 100644
index 0000000000000..340413896765c
--- /dev/null
+++ b/tools/verification/models/sched/scpd.dot
@@ -0,0 +1,18 @@
+digraph state_automaton {
+ center = true;
+ size = "7,11";
+ {node [shape = plaintext] "can_sched"};
+ {node [shape = plaintext, style=invis, label=""] "__init_cant_sched"};
+ {node [shape = ellipse] "cant_sched"};
+ {node [shape = plaintext] "cant_sched"};
+ "__init_cant_sched" -> "cant_sched";
+ "can_sched" [label = "can_sched"];
+ "can_sched" -> "can_sched" [ label = "schedule_entry\nschedule_exit" ];
+ "can_sched" -> "cant_sched" [ label = "preempt_enable" ];
+ "cant_sched" [label = "cant_sched", color = green3];
+ "cant_sched" -> "can_sched" [ label = "preempt_disable" ];
+ { rank = min ;
+ "__init_cant_sched";
+ "cant_sched";
+ }
+}
diff --git a/tools/verification/models/sched/sncid.dot b/tools/verification/models/sched/sncid.dot
new file mode 100644
index 0000000000000..072851721b50a
--- /dev/null
+++ b/tools/verification/models/sched/sncid.dot
@@ -0,0 +1,18 @@
+digraph state_automaton {
+ center = true;
+ size = "7,11";
+ {node [shape = plaintext, style=invis, label=""] "__init_can_sched"};
+ {node [shape = ellipse] "can_sched"};
+ {node [shape = plaintext] "can_sched"};
+ {node [shape = plaintext] "cant_sched"};
+ "__init_can_sched" -> "can_sched";
+ "can_sched" [label = "can_sched", color = green3];
+ "can_sched" -> "can_sched" [ label = "schedule_entry\nschedule_exit" ];
+ "can_sched" -> "cant_sched" [ label = "irq_disable" ];
+ "cant_sched" [label = "cant_sched"];
+ "cant_sched" -> "can_sched" [ label = "irq_enable" ];
+ { rank = min ;
+ "__init_can_sched";
+ "can_sched";
+ }
+}
diff --git a/tools/verification/models/sched/snep.dot b/tools/verification/models/sched/snep.dot
new file mode 100644
index 0000000000000..fe1300e93f211
--- /dev/null
+++ b/tools/verification/models/sched/snep.dot
@@ -0,0 +1,18 @@
+digraph state_automaton {
+ center = true;
+ size = "7,11";
+ {node [shape = plaintext, style=invis, label=""] "__init_non_scheduling_context"};
+ {node [shape = ellipse] "non_scheduling_context"};
+ {node [shape = plaintext] "non_scheduling_context"};
+ {node [shape = plaintext] "scheduling_contex"};
+ "__init_non_scheduling_context" -> "non_scheduling_context";
+ "non_scheduling_context" [label = "non_scheduling_context", color = green3];
+ "non_scheduling_context" -> "non_scheduling_context" [ label = "preempt_disable\npreempt_enable" ];
+ "non_scheduling_context" -> "scheduling_contex" [ label = "schedule_entry" ];
+ "scheduling_contex" [label = "scheduling_contex"];
+ "scheduling_contex" -> "non_scheduling_context" [ label = "schedule_exit" ];
+ { rank = min ;
+ "__init_non_scheduling_context";
+ "non_scheduling_context";
+ }
+}
--
2.48.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC PATCH 08/11] tools/rv: Add support for nested monitors
2025-02-06 8:09 [RFC PATCH 00/11] rv: Add scheduler specification monitors Gabriele Monaco
` (6 preceding siblings ...)
2025-02-06 8:09 ` [RFC PATCH 07/11] rv: Add scpd, snep and sncid per-cpu monitors Gabriele Monaco
@ 2025-02-06 8:09 ` Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 09/11] verification/dot2k: " Gabriele Monaco
` (3 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Gabriele Monaco @ 2025-02-06 8:09 UTC (permalink / raw)
To: linux-kernel, Steven Rostedt, linux-trace-kernel; +Cc: Gabriele Monaco
RV now supports nested monitors, this functionality requires a container
monitor, which has virtually no functionality besides holding other
monitors, and nested monitors, that have a container as parent.
Nested monitors' sysfs folders are physically nested in the container's
folder, and they are listed in the available_monitors file with the
notation container:monitor.
These changes go against the assumption that each line in the
available_monitors file correspond to a folder in the rv directory,
breaking the functionality of the rv tool.
Add support for nested containers in the rv userspace tool, indenting
nested monitors while listed and allowing both the notation with and
without container name, which are equivalent:
# rv list
mon1
mon2
container:
- nested1
- nested2
## notation with container name
# rv mon container:nested1
## notation without container name
# rv mon nested1
Either way, enabling a nested monitor is the same as enabling any other
non-nested monitor.
Selecting the container with rv mon enables all the nested monitors, if
-t is passed, the trace also includes the monitor name next to the
event:
# rv mon nested1 -t
<idle>-0 [004] event state1 x event -> state2
<idle>-0 [004] error event not expected in state2
# rv mon sched -t
<idle>-0 [004] event_nested1 state1 x event -> state2
<idle>-0 [004] error_nested1 event not expected in state2
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
tools/verification/rv/include/rv.h | 1 +
tools/verification/rv/src/in_kernel.c | 226 ++++++++++++++++++++------
2 files changed, 179 insertions(+), 48 deletions(-)
diff --git a/tools/verification/rv/include/rv.h b/tools/verification/rv/include/rv.h
index 0cab1037a98f7..6f668eb266cbb 100644
--- a/tools/verification/rv/include/rv.h
+++ b/tools/verification/rv/include/rv.h
@@ -7,6 +7,7 @@ struct monitor {
char name[MAX_DA_NAME_LEN];
char desc[MAX_DESCRIPTION];
int enabled;
+ int nested;
};
int should_stop(void);
diff --git a/tools/verification/rv/src/in_kernel.c b/tools/verification/rv/src/in_kernel.c
index f2bbc75a76f4d..032b851019290 100644
--- a/tools/verification/rv/src/in_kernel.c
+++ b/tools/verification/rv/src/in_kernel.c
@@ -6,15 +6,18 @@
*/
#include <getopt.h>
#include <stdlib.h>
+#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
+#include <dirent.h>
#include <trace.h>
#include <utils.h>
#include <rv.h>
static int config_has_id;
+static int config_is_container;
static int config_my_pid;
static int config_trace;
@@ -44,6 +47,51 @@ static int __ikm_read_enable(char *monitor_name)
return enabled;
}
+/*
+ * __ikm_find_monitor - find the full name of a possibly nested module
+ *
+ * __does not log errors.
+ *
+ * Returns 1 if we found the monitor, -1 on error and 0 if it does not exist.
+ * The string out_name is populated with the full name, which can be
+ * equal to monitor_name or container/monitor_name if nested
+ */
+static int __ikm_find_monitor_name(char *monitor_name, char *out_name)
+{
+ char *available_monitors, container[MAX_DA_NAME_LEN+1], *cursor, *end;
+ int retval = 1;
+
+ available_monitors = tracefs_instance_file_read(NULL, "rv/available_monitors", NULL);
+ if (!available_monitors)
+ return -1;
+
+ cursor = strstr(available_monitors, monitor_name);
+ if (!cursor) {
+ retval = 0;
+ goto out_free;
+ }
+
+ for (; cursor > available_monitors; cursor--)
+ if (*(cursor-1) == '\n')
+ break;
+ end = strstr(cursor, "\n");
+ memcpy(out_name, cursor, end-cursor);
+ out_name[end-cursor] = '\0';
+
+ cursor = strstr(out_name, ":");
+ if (cursor)
+ *cursor = '/';
+ else {
+ sprintf(container, "%s:", monitor_name);
+ if (strstr(available_monitors, container))
+ config_is_container = 1;
+ }
+
+out_free:
+ free(available_monitors);
+ return retval;
+}
+
/*
* ikm_read_enable - reads monitor's enable status
*
@@ -137,7 +185,17 @@ static char *ikm_read_desc(char *monitor_name)
static int ikm_fill_monitor_definition(char *name, struct monitor *ikm)
{
int enabled;
- char *desc;
+ char *desc, *nested_name;
+
+ nested_name = strstr(name, ":");
+ if (nested_name) {
+ *nested_name = '/';
+ ++nested_name;
+ ikm->nested = 1;
+ } else {
+ nested_name = name;
+ ikm->nested = 0;
+ }
enabled = ikm_read_enable(name);
if (enabled < 0) {
@@ -151,7 +209,7 @@ static int ikm_fill_monitor_definition(char *name, struct monitor *ikm)
return -1;
}
- strncpy(ikm->name, name, MAX_DA_NAME_LEN);
+ strncpy(ikm->name, nested_name, MAX_DA_NAME_LEN);
ikm->enabled = enabled;
strncpy(ikm->desc, desc, MAX_DESCRIPTION);
@@ -273,7 +331,7 @@ static int ikm_has_id(char *monitor_name)
int ikm_list_monitors(void)
{
char *available_monitors;
- struct monitor ikm;
+ struct monitor ikm = {0};
char *curr, *next;
int retval;
@@ -293,7 +351,9 @@ int ikm_list_monitors(void)
if (retval)
err_msg("ikm: error reading %d in kernel monitor, skipping\n", curr);
- printf("%-24s %s %s\n", ikm.name, ikm.desc, ikm.enabled ? "[ON]" : "[OFF]");
+ printf("%s%-*s %s %s\n", ikm.nested ? " - " : "",
+ ikm.nested ? MAX_DA_NAME_LEN - 3 : MAX_DA_NAME_LEN,
+ ikm.name, ikm.desc, ikm.enabled ? "[ON]" : "[OFF]");
curr = ++next;
} while (strlen(curr));
@@ -343,11 +403,11 @@ ikm_event_handler(struct trace_seq *s, struct tep_record *record,
unsigned long long final_state;
unsigned long long pid;
unsigned long long id;
- int cpu = record->cpu;
int val;
+ bool missing_id;
if (config_has_id)
- tep_get_field_val(s, trace_event, "id", record, &id, 1);
+ missing_id = tep_get_field_val(s, trace_event, "id", record, &id, 1);
tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1);
@@ -356,12 +416,21 @@ ikm_event_handler(struct trace_seq *s, struct tep_record *record,
else if (config_my_pid && (config_my_pid == pid))
return 0;
- tep_print_event(trace_event->tep, s, record, "%16s-%-8d ", TEP_PRINT_COMM, TEP_PRINT_PID);
+ tep_print_event(trace_event->tep, s, record, "%16s-%-8d [%.3d] ",
+ TEP_PRINT_COMM, TEP_PRINT_PID, TEP_PRINT_CPU);
- trace_seq_printf(s, "[%.3d] event ", cpu);
+ if (config_is_container)
+ tep_print_event(trace_event->tep, s, record, "%s ", TEP_PRINT_NAME);
+ else
+ trace_seq_printf(s, "event ");
- if (config_has_id)
- trace_seq_printf(s, "%8llu ", id);
+ if (config_has_id) {
+ if (missing_id)
+ /* placeholder if we are dealing with a mixed-type container*/
+ trace_seq_printf(s, " ");
+ else
+ trace_seq_printf(s, "%8llu ", id);
+ }
state = tep_get_field_raw(s, trace_event, "state", record, &val, 0);
event = tep_get_field_raw(s, trace_event, "event", record, &val, 0);
@@ -394,9 +463,10 @@ ikm_error_handler(struct trace_seq *s, struct tep_record *record,
int cpu = record->cpu;
char *state, *event;
int val;
+ bool missing_id;
if (config_has_id)
- tep_get_field_val(s, trace_event, "id", record, &id, 1);
+ missing_id = tep_get_field_val(s, trace_event, "id", record, &id, 1);
tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1);
@@ -405,10 +475,20 @@ ikm_error_handler(struct trace_seq *s, struct tep_record *record,
else if (config_my_pid == pid)
return 0;
- trace_seq_printf(s, "%8lld [%03d] error ", pid, cpu);
+ trace_seq_printf(s, "%8lld [%03d] ", pid, cpu);
- if (config_has_id)
- trace_seq_printf(s, "%8llu ", id);
+ if (config_is_container)
+ tep_print_event(trace_event->tep, s, record, "%s ", TEP_PRINT_NAME);
+ else
+ trace_seq_printf(s, "error ");
+
+ if (config_has_id) {
+ if (missing_id)
+ /* placeholder if we are dealing with a mixed-type container*/
+ trace_seq_printf(s, " ");
+ else
+ trace_seq_printf(s, "%8llu ", id);
+ }
state = tep_get_field_raw(s, trace_event, "state", record, &val, 0);
event = tep_get_field_raw(s, trace_event, "event", record, &val, 0);
@@ -421,6 +501,64 @@ ikm_error_handler(struct trace_seq *s, struct tep_record *record,
return 0;
}
+static int ikm_enable_trace_events(char *monitor_name, struct trace_instance *inst)
+{
+ char event[MAX_DA_NAME_LEN + 7]; /* max(error_,event_) + '0' = 7 */
+ int retval;
+
+ snprintf(event, sizeof(event), "event_%s", monitor_name);
+ retval = tracefs_event_enable(inst->inst, "rv", event);
+ if (retval)
+ return -1;
+
+ tep_register_event_handler(inst->tep, -1, "rv", event,
+ ikm_event_handler, NULL);
+
+ snprintf(event, sizeof(event), "error_%s", monitor_name);
+ retval = tracefs_event_enable(inst->inst, "rv", event);
+ if (retval)
+ return -1;
+
+ tep_register_event_handler(inst->tep, -1, "rv", event,
+ ikm_error_handler, NULL);
+
+ /* set if at least 1 monitor has id in case of a container */
+ config_has_id = ikm_has_id(monitor_name);
+ if (config_has_id < 0)
+ return -1;
+
+
+ return 0;
+}
+
+static int ikm_enable_trace_container(char *monitor_name,
+ struct trace_instance *inst)
+{
+ DIR *dp;
+ char *abs_path, rv_path[MAX_PATH];
+ struct dirent *ep;
+ int retval = 0;
+
+ snprintf(rv_path, MAX_PATH, "rv/monitors/%s", monitor_name);
+ abs_path = tracefs_instance_get_file(NULL, rv_path);
+ if (!abs_path)
+ return -1;
+ dp = opendir(abs_path);
+ if (!dp)
+ goto out_free;
+
+ while (!retval && (ep = readdir(dp))) {
+ if (ep->d_type != DT_DIR || ep->d_name[0] == '.')
+ continue;
+ retval = ikm_enable_trace_events(ep->d_name, inst);
+ }
+
+ closedir(dp);
+out_free:
+ free(abs_path);
+ return retval;
+}
+
/*
* ikm_setup_trace_instance - set up a tracing instance to collect data
*
@@ -430,19 +568,12 @@ ikm_error_handler(struct trace_seq *s, struct tep_record *record,
*/
static struct trace_instance *ikm_setup_trace_instance(char *monitor_name)
{
- char event[MAX_DA_NAME_LEN + 7]; /* max(error_,event_) + '0' = 7 */
struct trace_instance *inst;
int retval;
if (!config_trace)
return NULL;
- config_has_id = ikm_has_id(monitor_name);
- if (config_has_id < 0) {
- err_msg("ikm: failed to read monitor %s event format\n", monitor_name);
- goto out_err;
- }
-
/* alloc data */
inst = calloc(1, sizeof(*inst));
if (!inst) {
@@ -454,23 +585,13 @@ static struct trace_instance *ikm_setup_trace_instance(char *monitor_name)
if (retval)
goto out_free;
- /* enable events */
- snprintf(event, sizeof(event), "event_%s", monitor_name);
- retval = tracefs_event_enable(inst->inst, "rv", event);
- if (retval)
- goto out_inst;
-
- tep_register_event_handler(inst->tep, -1, "rv", event,
- ikm_event_handler, NULL);
-
- snprintf(event, sizeof(event), "error_%s", monitor_name);
- retval = tracefs_event_enable(inst->inst, "rv", event);
+ if (config_is_container)
+ retval = ikm_enable_trace_container(monitor_name, inst);
+ else
+ retval = ikm_enable_trace_events(monitor_name, inst);
if (retval)
goto out_inst;
- tep_register_event_handler(inst->tep, -1, "rv", event,
- ikm_error_handler, NULL);
-
/* ready to enable */
tracefs_trace_on(inst->inst);
@@ -633,32 +754,41 @@ static int parse_arguments(char *monitor_name, int argc, char **argv)
int ikm_run_monitor(char *monitor_name, int argc, char **argv)
{
struct trace_instance *inst = NULL;
+ char *nested_name, full_name[2*MAX_DA_NAME_LEN];
int retval;
- /*
- * Check if monitor exists by seeing it is enabled.
- */
- retval = __ikm_read_enable(monitor_name);
- if (retval < 0)
+ nested_name = strstr(monitor_name, ":");
+ if (nested_name)
+ ++nested_name;
+ else
+ nested_name = monitor_name;
+
+ retval = __ikm_find_monitor_name(monitor_name, full_name);
+ if (!retval)
return 0;
+ if (retval < 0) {
+ err_msg("ikm: error finding monitor %s\n", nested_name);
+ return -1;
+ }
+ retval = __ikm_read_enable(full_name);
if (retval) {
- err_msg("ikm: monitor %s (in-kernel) is already enabled\n", monitor_name);
+ err_msg("ikm: monitor %s (in-kernel) is already enabled\n", nested_name);
return -1;
}
/* we should be good to go */
- retval = parse_arguments(monitor_name, argc, argv);
+ retval = parse_arguments(full_name, argc, argv);
if (retval)
- ikm_usage(1, monitor_name, "ikm: failed parsing arguments");
+ ikm_usage(1, nested_name, "ikm: failed parsing arguments");
if (config_trace) {
- inst = ikm_setup_trace_instance(monitor_name);
+ inst = ikm_setup_trace_instance(nested_name);
if (!inst)
return -1;
}
- retval = ikm_enable(monitor_name);
+ retval = ikm_enable(full_name);
if (retval < 0)
goto out_free_instance;
@@ -682,17 +812,17 @@ int ikm_run_monitor(char *monitor_name, int argc, char **argv)
sleep(1);
}
- ikm_disable(monitor_name);
+ ikm_disable(full_name);
ikm_destroy_trace_instance(inst);
if (config_reactor && config_initial_reactor)
- ikm_write_reactor(monitor_name, config_initial_reactor);
+ ikm_write_reactor(full_name, config_initial_reactor);
return 1;
out_free_instance:
ikm_destroy_trace_instance(inst);
if (config_reactor && config_initial_reactor)
- ikm_write_reactor(monitor_name, config_initial_reactor);
+ ikm_write_reactor(full_name, config_initial_reactor);
return -1;
}
--
2.48.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC PATCH 09/11] verification/dot2k: Add support for nested monitors
2025-02-06 8:09 [RFC PATCH 00/11] rv: Add scheduler specification monitors Gabriele Monaco
` (7 preceding siblings ...)
2025-02-06 8:09 ` [RFC PATCH 08/11] tools/rv: Add support for nested monitors Gabriele Monaco
@ 2025-02-06 8:09 ` Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 10/11] Documentation/rv: Add docs for the sched monitors Gabriele Monaco
` (2 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Gabriele Monaco @ 2025-02-06 8:09 UTC (permalink / raw)
To: linux-kernel, Steven Rostedt, linux-trace-kernel; +Cc: Gabriele Monaco
RV now supports nested monitors, this functionality requires a container
monitor, which has virtually no functionality besides holding other
monitors, and nested monitors, that have a container as parent.
Add the -p flag to pass a parent to a monitor, this sets it up while
registering the monitor and adds necessary includes and configurations.
Add the -c flag to create a container, since containers are empty, we
don't allow supplying a dot model or a monitor type, the template is
also different since functions to enable and disable the monitor are not
defined, nor any tracepoint. The generated header file only allows to
include the rv_monitor structure in children monitors.
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
tools/verification/dot2/dot2k | 27 ++++---
tools/verification/dot2/dot2k.py | 78 +++++++++++++++----
.../verification/dot2/dot2k_templates/Kconfig | 1 +
.../verification/dot2/dot2k_templates/main.c | 4 +-
.../dot2/dot2k_templates/main_container.c | 38 +++++++++
.../dot2/dot2k_templates/main_container.h | 3 +
6 files changed, 124 insertions(+), 27 deletions(-)
create mode 100644 tools/verification/dot2/dot2k_templates/main_container.c
create mode 100644 tools/verification/dot2/dot2k_templates/main_container.h
diff --git a/tools/verification/dot2/dot2k b/tools/verification/dot2/dot2k
index 559ba191a1f6d..767064f415e76 100644
--- a/tools/verification/dot2/dot2k
+++ b/tools/verification/dot2/dot2k
@@ -11,22 +11,30 @@
if __name__ == '__main__':
from dot2.dot2k import dot2k
import argparse
- import ntpath
- import os
- import platform
import sys
+ def is_container():
+ """Should work even before parsing the arguments"""
+ return "-c" in sys.argv or "--container" in sys.argv
+
parser = argparse.ArgumentParser(description='transform .dot file into kernel rv monitor')
- parser.add_argument('-d', "--dot", dest="dot_file", required=True)
- parser.add_argument('-t', "--monitor_type", dest="monitor_type", required=True)
- parser.add_argument('-n', "--model_name", dest="model_name", required=False)
+ parser.add_argument('-d', "--dot", dest="dot_file", required=not is_container())
+ parser.add_argument('-t', "--monitor_type", dest="monitor_type", required=not is_container(),
+ help=f"Available options: {', '.join(dot2k.monitor_types.keys())}")
+ parser.add_argument('-n', "--model_name", dest="model_name", required=is_container())
parser.add_argument("-D", "--description", dest="description", required=False)
parser.add_argument("-a", "--auto_patch", dest="auto_patch",
action="store_true", required=False,
help="Patch the kernel in place")
+ parser.add_argument("-p", "--parent", dest="parent",
+ required=False, help="Create a monitor nested to parent")
+ parser.add_argument("-c", "--container", dest="container",
+ action="store_true", required=False,
+ help="Create an empty monitor to be used as a container")
params = parser.parse_args()
- print("Opening and parsing the dot file %s" % params.dot_file)
+ if not is_container():
+ print("Opening and parsing the dot file %s" % params.dot_file)
try:
monitor=dot2k(params.dot_file, params.monitor_type, vars(params))
except Exception as e:
@@ -37,8 +45,9 @@ if __name__ == '__main__':
print("Writing the monitor into the directory %s" % monitor.name)
monitor.print_files()
print("Almost done, checklist")
- print(" - Edit the %s/%s.c to add the instrumentation" % (monitor.name, monitor.name))
- print(monitor.fill_tracepoint_tooltip())
+ if not is_container():
+ print(" - Edit the %s/%s.c to add the instrumentation" % (monitor.name, monitor.name))
+ print(monitor.fill_tracepoint_tooltip())
print(monitor.fill_makefile_tooltip())
print(monitor.fill_kconfig_tooltip())
print(monitor.fill_monitor_tooltip())
diff --git a/tools/verification/dot2/dot2k.py b/tools/verification/dot2/dot2k.py
index 153cc14bcca45..736c0c7c3ef21 100644
--- a/tools/verification/dot2/dot2k.py
+++ b/tools/verification/dot2/dot2k.py
@@ -19,16 +19,31 @@ class dot2k(Dot2c):
monitor_type = "per_cpu"
def __init__(self, file_path, MonitorType, extra_params={}):
- super().__init__(file_path, extra_params.get("model_name"))
-
- self.monitor_type = self.monitor_types.get(MonitorType)
- if self.monitor_type is None:
- raise ValueError("Unknown monitor type: %s" % MonitorType)
-
- self.monitor_type = MonitorType
+ self.container = extra_params.get("container")
+ self.parent = extra_params.get("parent")
self.__fill_rv_templates_dir()
- self.main_c = self.__read_file(self.monitor_templates_dir + "main.c")
- self.trace_h = self.__read_file(self.monitor_templates_dir + "trace.h")
+
+ if self.container:
+ if file_path:
+ raise ValueError("A container does not require a dot file")
+ if MonitorType:
+ raise ValueError("A container does not require a monitor type")
+ if self.parent:
+ raise ValueError("A container cannot have a parent")
+ self.name = extra_params.get("model_name")
+ self.events = []
+ self.states = []
+ self.main_c = self.__read_file(self.monitor_templates_dir + "main_container.c")
+ self.main_h = self.__read_file(self.monitor_templates_dir + "main_container.h")
+ else:
+ super().__init__(file_path, extra_params.get("model_name"))
+
+ self.monitor_type = self.monitor_types.get(MonitorType)
+ if self.monitor_type is None:
+ raise ValueError("Unknown monitor type: %s" % MonitorType)
+ self.monitor_type = MonitorType
+ self.main_c = self.__read_file(self.monitor_templates_dir + "main.c")
+ self.trace_h = self.__read_file(self.monitor_templates_dir + "trace.h")
self.kconfig = self.__read_file(self.monitor_templates_dir + "Kconfig")
self.enum_suffix = "_%s" % self.name
self.description = extra_params.get("description", self.name) or "auto-generated"
@@ -105,6 +120,14 @@ class dot2k(Dot2c):
def fill_monitor_type(self):
return self.monitor_type.upper()
+ def fill_parent(self):
+ return "&rv_%s" % self.parent if self.parent else "NULL"
+
+ def fill_include_parent(self):
+ if self.parent:
+ return "#include <monitors/%s/%s.h>\n" % (self.parent, self.parent)
+ return ""
+
def fill_tracepoint_handlers_skel(self):
buff = []
for event in self.events:
@@ -146,6 +169,8 @@ class dot2k(Dot2c):
tracepoint_handlers = self.fill_tracepoint_handlers_skel()
tracepoint_attach = self.fill_tracepoint_attach_probe()
tracepoint_detach = self.fill_tracepoint_detach_helper()
+ parent = self.fill_parent()
+ parent_include = self.fill_include_parent()
main_c = main_c.replace("%%MONITOR_TYPE%%", monitor_type)
main_c = main_c.replace("%%MIN_TYPE%%", min_type)
@@ -155,6 +180,8 @@ class dot2k(Dot2c):
main_c = main_c.replace("%%TRACEPOINT_ATTACH%%", tracepoint_attach)
main_c = main_c.replace("%%TRACEPOINT_DETACH%%", tracepoint_detach)
main_c = main_c.replace("%%DESCRIPTION%%", self.description)
+ main_c = main_c.replace("%%PARENT%%", parent)
+ main_c = main_c.replace("%%INCLUDE_PARENT%%", parent_include)
return main_c
@@ -216,6 +243,13 @@ class dot2k(Dot2c):
buff.append(" TP_ARGS(%s)" % tp_args_c)
return self.__buff_to_string(buff)
+ def fill_monitor_deps(self):
+ buff = []
+ if self.parent:
+ buff.append(" depends on RV_MON_%s" % self.parent.upper())
+ buff.append(" # XXX: add dependencies if there")
+ return self.__buff_to_string(buff)
+
def fill_trace_h(self):
trace_h = self.trace_h
monitor_class = self.fill_monitor_class()
@@ -233,12 +267,19 @@ class dot2k(Dot2c):
def fill_kconfig(self):
kconfig = self.kconfig
monitor_class_type = self.fill_monitor_class_type()
+ monitor_deps = self.fill_monitor_deps()
kconfig = kconfig.replace("%%MODEL_NAME%%", self.name)
kconfig = kconfig.replace("%%MODEL_NAME_UP%%", self.name.upper())
kconfig = kconfig.replace("%%MONITOR_CLASS_TYPE%%", monitor_class_type)
kconfig = kconfig.replace("%%DESCRIPTION%%", self.description)
+ kconfig = kconfig.replace("%%MONITOR_DEPS%%", monitor_deps)
return kconfig
+ def fill_main_container_h(self):
+ main_h = self.main_h
+ main_h = main_h.replace("%%MODEL_NAME%%", self.name)
+ return main_h
+
def __patch_file(self, file, marker, line):
file_to_patch = os.path.join(self.rv_dir, file)
content = self.__read_file(file_to_patch)
@@ -324,19 +365,24 @@ obj-$(CONFIG_RV_MON_%s) += monitors/%s/%s.o
def print_files(self):
main_c = self.fill_main_c()
- model_h = self.fill_model_h()
self.__create_directory()
path = "%s.c" % self.name
self.__create_file(path, main_c)
- path = "%s.h" % self.name
- self.__create_file(path, model_h)
-
- trace_h = self.fill_trace_h()
- path = "%s_trace.h" % self.name
- self.__create_file(path, trace_h)
+ if self.container:
+ main_h = self.fill_main_container_h()
+ path = "%s.h" % self.name
+ self.__create_file(path, main_h)
+ else:
+ model_h = self.fill_model_h()
+ path = "%s.h" % self.name
+ self.__create_file(path, model_h)
+
+ trace_h = self.fill_trace_h()
+ path = "%s_trace.h" % self.name
+ self.__create_file(path, trace_h)
kconfig = self.fill_kconfig()
self.__create_file("Kconfig", kconfig)
diff --git a/tools/verification/dot2/dot2k_templates/Kconfig b/tools/verification/dot2/dot2k_templates/Kconfig
index 03100eda17075..291b29ea28db3 100644
--- a/tools/verification/dot2/dot2k_templates/Kconfig
+++ b/tools/verification/dot2/dot2k_templates/Kconfig
@@ -2,6 +2,7 @@
#
config RV_MON_%%MODEL_NAME_UP%%
depends on RV
+%%MONITOR_DEPS%%
select %%MONITOR_CLASS_TYPE%%
bool "%%MODEL_NAME%% monitor"
help
diff --git a/tools/verification/dot2/dot2k_templates/main.c b/tools/verification/dot2/dot2k_templates/main.c
index 9605ca994416b..83044a20c89aa 100644
--- a/tools/verification/dot2/dot2k_templates/main.c
+++ b/tools/verification/dot2/dot2k_templates/main.c
@@ -15,7 +15,7 @@
* #include <trace/events/sched.h>
*/
#include <rv_trace.h>
-
+%%INCLUDE_PARENT%%
/*
* This is the self-generated part of the monitor. Generally, there is no need
* to touch this section.
@@ -74,7 +74,7 @@ static struct rv_monitor rv_%%MODEL_NAME%% = {
static int __init register_%%MODEL_NAME%%(void)
{
- rv_register_monitor(&rv_%%MODEL_NAME%%);
+ rv_register_monitor(&rv_%%MODEL_NAME%%, %%PARENT%%);
return 0;
}
diff --git a/tools/verification/dot2/dot2k_templates/main_container.c b/tools/verification/dot2/dot2k_templates/main_container.c
new file mode 100644
index 0000000000000..89fc17cf8958e
--- /dev/null
+++ b/tools/verification/dot2/dot2k_templates/main_container.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/rv.h>
+
+#define MODULE_NAME "%%MODEL_NAME%%"
+
+#include "%%MODEL_NAME%%.h"
+
+struct rv_monitor rv_%%MODEL_NAME%%;
+
+struct rv_monitor rv_%%MODEL_NAME%% = {
+ .name = "%%MODEL_NAME%%",
+ .description = "%%DESCRIPTION%%",
+ .enable = NULL,
+ .disable = NULL,
+ .reset = NULL,
+ .enabled = 0,
+};
+
+static int __init register_%%MODEL_NAME%%(void)
+{
+ rv_register_monitor(&rv_%%MODEL_NAME%%, NULL);
+ return 0;
+}
+
+static void __exit unregister_%%MODEL_NAME%%(void)
+{
+ rv_unregister_monitor(&rv_%%MODEL_NAME%%);
+}
+
+module_init(register_%%MODEL_NAME%%);
+module_exit(unregister_%%MODEL_NAME%%);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("dot2k: auto-generated");
+MODULE_DESCRIPTION("%%MODEL_NAME%%: %%DESCRIPTION%%");
diff --git a/tools/verification/dot2/dot2k_templates/main_container.h b/tools/verification/dot2/dot2k_templates/main_container.h
new file mode 100644
index 0000000000000..0f6883ab4bcc7
--- /dev/null
+++ b/tools/verification/dot2/dot2k_templates/main_container.h
@@ -0,0 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+extern struct rv_monitor rv_%%MODEL_NAME%%;
--
2.48.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC PATCH 10/11] Documentation/rv: Add docs for the sched monitors
2025-02-06 8:09 [RFC PATCH 00/11] rv: Add scheduler specification monitors Gabriele Monaco
` (8 preceding siblings ...)
2025-02-06 8:09 ` [RFC PATCH 09/11] verification/dot2k: " Gabriele Monaco
@ 2025-02-06 8:09 ` Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 11/11] tools/rv: Allow rv list to filter for container Gabriele Monaco
2025-02-07 10:55 ` [RFC PATCH 00/11] rv: Add scheduler specification monitors Juri Lelli
11 siblings, 0 replies; 23+ messages in thread
From: Gabriele Monaco @ 2025-02-06 8:09 UTC (permalink / raw)
To: linux-kernel, Ingo Molnar, Peter Zijlstra, Jonathan Corbet,
Steven Rostedt, linux-doc, linux-trace-kernel
Cc: Gabriele Monaco, Juri Lelli, John Kacur, Clark Williams
Add man page and kernel documentation for the sched monitors, as sched
is a container of other monitors, document all in the same page.
sched is the first nested monitor, also explain what is a nested monitor
and how enabling containers or children monitors work.
To: Ingo Molnar <mingo@redhat.com>
To: Peter Zijlstra <peterz@infradead.org>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
Cc: Clark Williams <williams@redhat.com>
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
Documentation/tools/rv/rv-mon-sched.rst | 69 +++++++++
Documentation/trace/rv/monitor_sched.rst | 171 +++++++++++++++++++++++
2 files changed, 240 insertions(+)
create mode 100644 Documentation/tools/rv/rv-mon-sched.rst
create mode 100644 Documentation/trace/rv/monitor_sched.rst
diff --git a/Documentation/tools/rv/rv-mon-sched.rst b/Documentation/tools/rv/rv-mon-sched.rst
new file mode 100644
index 0000000000000..da0fe4c79ae52
--- /dev/null
+++ b/Documentation/tools/rv/rv-mon-sched.rst
@@ -0,0 +1,69 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+============
+rv-mon-sched
+============
+-----------------------------
+Scheduler monitors collection
+-----------------------------
+
+:Manual section: 1
+
+SYNOPSIS
+========
+
+**rv mon sched** [*OPTIONS*]
+
+**rv mon <NESTED_MONITOR>** [*OPTIONS*]
+
+**rv mon sched:<NESTED_MONITOR>** [*OPTIONS*]
+
+DESCRIPTION
+===========
+
+The scheduler monitor collection is a container for several monitors to model
+the behaviour of the scheduler. Each monitor describes a specification that
+the scheduler should follow.
+
+As a monitor container, it will enable all nested monitors and set them
+according to OPTIONS.
+Nevertheless nested monitors can also be activated independently both by name
+and by specifying sched: , e.g. to enable only monitor tss you can do any of:
+
+ # rv mon sched:tss
+
+ # rv mon tss
+
+See kernel documentation for further information about this monitor:
+<https://docs.kernel.org/trace/rv/monitor_sched.html>
+
+OPTIONS
+=======
+
+.. include:: common_ikm.rst
+
+NESTED MONITOR
+==============
+
+The available nested monitors are:
+ * scpd: schedule called with preemption disabled
+ * snep: schedule does not enable preempt
+ * sncid: schedule not called with interrupt disabled
+ * snroc: set non runnable on its own context
+ * sco: scheduling context operations
+ * tss: task switch while scheduling
+
+SEE ALSO
+========
+
+**rv**\(1), **rv-mon**\(1)
+
+Linux kernel *RV* documentation:
+<https://www.kernel.org/doc/html/latest/trace/rv/index.html>
+
+AUTHOR
+======
+
+Written by Gabriele Monaco <gmonaco@redhat.com>
+
+.. include:: common_appendix.rst
diff --git a/Documentation/trace/rv/monitor_sched.rst b/Documentation/trace/rv/monitor_sched.rst
new file mode 100644
index 0000000000000..24b2c62a3bc26
--- /dev/null
+++ b/Documentation/trace/rv/monitor_sched.rst
@@ -0,0 +1,171 @@
+Scheduler monitors
+==================
+
+- Name: sched
+- Type: container for multiple monitors
+- Author: Gabriele Monaco <gmonaco@redhat.com>, Daniel Bristot de Oliveira <bristot@kernel.org>
+
+Description
+-----------
+
+Monitors describing complex systems, such as the scheduler, can easily grow to
+the point where they are just hard to understand because of the many possible
+state transitions.
+Often it is possible to break such descriptions into smaller monitors,
+sharing some or all events. Enabling those smaller monitors concurrently is,
+in fact, testing the system as if we had one single larger monitor.
+Splitting models into multiple specification is not only easier to
+understand, but gives some more clues when we see errors.
+
+The sched monitor is a set of specifications to describe the scheduler behaviour.
+It includes several per-cpu and per-task monitors that work independently to verify
+different specifications the scheduler should follow.
+
+To make this system as straightforward as possible, sched specifications are *nested*
+monitors, whereas sched itself is a *container*.
+From the interface perspective, sched includes other monitors as sub-directories,
+enabling/disabling or setting reactors to sched, propagates the change to all monitors,
+however single monitors can be used independently as well.
+
+It is important that future modules are built after their container (sched, in
+this case), otherwise the linker would not respect the order and the nesting
+wouldn't work as expected.
+To do so, simply add them after sched in the Makefile.
+
+Specifications
+--------------
+
+The specifications included in sched are currently a work in progress, adapting the ones
+defined in by Daniel Bristot in [1].
+
+Currently we included the following:
+
+Monitor tss
+~~~~~~~~~~~
+
+The task switch while scheduling (tss) monitor ensures a task switch happens
+only in scheduling context, that is inside a call to `__schedule`::
+
+ |
+ |
+ v
+ +-----------------+
+ | thread | <+
+ +-----------------+ |
+ | |
+ | schedule_entry | schedule_exit
+ v |
+ sched_switch |
+ +--------------- |
+ | sched |
+ +--------------> -+
+
+Monitor sco
+~~~~~~~~~~~
+
+The scheduling context operations (sco) monitor ensures changes in a task state
+happen only in thread context::
+
+
+ |
+ |
+ v
+ sched_set_state +------------------+
+ +------------------ | |
+ | | thread_context |
+ +-----------------> | | <+
+ +------------------+ |
+ | |
+ | schedule_entry | schedule_exit
+ v |
+ |
+ scheduling_context -+
+
+Monitor snroc
+~~~~~~~~~~~~~
+
+The set non runnable on its own context (snroc) monitor ensures changes in a
+task state happens only in the respective task's context. This is a per-task
+monitor::
+
+ |
+ |
+ v
+ +------------------+
+ | other_context | <+
+ +------------------+ |
+ | |
+ | sched_switch_in | sched_switch_out
+ v |
+ sched_set_state |
+ +------------------ |
+ | own_context |
+ +-----------------> -+
+
+Monitor scpd
+~~~~~~~~~~~~
+
+The schedule called with preemption disabled (scpd) monitor ensures schedule is
+called with preemption disabled::
+
+ |
+ |
+ v
+ +------------------+
+ | cant_sched | <+
+ +------------------+ |
+ | |
+ | preempt_disable | preempt_enable
+ v |
+ schedule_entry |
+ schedule_exit |
+ +----------------- can_sched |
+ | |
+ +----------------> -+
+
+Monitor snep
+~~~~~~~~~~~~
+
+The schedule does not enable preempt (snep) monitor ensures a schedule call
+does not enable preemption::
+
+ |
+ |
+ v
+ preempt_disable +------------------------+
+ preempt_enable | |
+ +------------------ | non_scheduling_context |
+ | | |
+ +-----------------> | | <+
+ +------------------------+ |
+ | |
+ | schedule_entry | schedule_exit
+ v |
+ |
+ scheduling_contex -+
+
+Monitor sncid
+~~~~~~~~~~~~~
+
+The schedule not called with interrupt disabled (sncid) monitor ensures
+schedule is not called with interrupt disabled::
+
+ |
+ |
+ v
+ schedule_entry +--------------+
+ schedule_exit | |
+ +----------------- | can_sched |
+ | | |
+ +----------------> | | <+
+ +--------------+ |
+ | |
+ | irq_disable | irq_enable
+ v |
+ |
+ cant_sched -+
+
+References
+----------
+
+[1] - https://bristot.me/linux-task-model
--
2.48.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [RFC PATCH 11/11] tools/rv: Allow rv list to filter for container
2025-02-06 8:09 [RFC PATCH 00/11] rv: Add scheduler specification monitors Gabriele Monaco
` (9 preceding siblings ...)
2025-02-06 8:09 ` [RFC PATCH 10/11] Documentation/rv: Add docs for the sched monitors Gabriele Monaco
@ 2025-02-06 8:09 ` Gabriele Monaco
2025-02-07 10:55 ` [RFC PATCH 00/11] rv: Add scheduler specification monitors Juri Lelli
11 siblings, 0 replies; 23+ messages in thread
From: Gabriele Monaco @ 2025-02-06 8:09 UTC (permalink / raw)
To: linux-kernel, Steven Rostedt, linux-trace-kernel; +Cc: Gabriele Monaco
Add possibility to supply the container name to rv list:
# rv list sched
mon1
mon2
mon3
This lists only monitors in sched, without indentation.
Supplying -h, any option (string starting with -) or more than 1
argument will still print the usage.
Passing a non-existent container prints nothing and passing no container
continues to print all monitors, showing indentation for nested
monitors, reported after their container.
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
tools/verification/rv/include/in_kernel.h | 2 +-
tools/verification/rv/src/in_kernel.c | 36 +++++++++++++++------
tools/verification/rv/src/rv.c | 38 +++++++++++++++--------
3 files changed, 53 insertions(+), 23 deletions(-)
diff --git a/tools/verification/rv/include/in_kernel.h b/tools/verification/rv/include/in_kernel.h
index 3090638c8d710..f3bfd3b9895fe 100644
--- a/tools/verification/rv/include/in_kernel.h
+++ b/tools/verification/rv/include/in_kernel.h
@@ -1,3 +1,3 @@
// SPDX-License-Identifier: GPL-2.0
-int ikm_list_monitors(void);
+int ikm_list_monitors(char *container);
int ikm_run_monitor(char *monitor, int argc, char **argv);
diff --git a/tools/verification/rv/src/in_kernel.c b/tools/verification/rv/src/in_kernel.c
index 032b851019290..c0dcee795c0de 100644
--- a/tools/verification/rv/src/in_kernel.c
+++ b/tools/verification/rv/src/in_kernel.c
@@ -180,19 +180,25 @@ static char *ikm_read_desc(char *monitor_name)
/*
* ikm_fill_monitor_definition - fill monitor's definition
*
- * Returns -1 on error, 0 otherwise.
+ * Returns -1 on error, 1 if the monitor does not belong in the container, 0 otherwise.
+ * container can be NULL
*/
-static int ikm_fill_monitor_definition(char *name, struct monitor *ikm)
+static int ikm_fill_monitor_definition(char *name, struct monitor *ikm, char *container)
{
int enabled;
char *desc, *nested_name;
nested_name = strstr(name, ":");
if (nested_name) {
+ /* it belongs in container if it starts with "container:" */
+ if (container && strstr(name, container) != name)
+ return 1;
*nested_name = '/';
++nested_name;
ikm->nested = 1;
} else {
+ if (container)
+ return 1;
nested_name = name;
ikm->nested = 0;
}
@@ -328,12 +334,12 @@ static int ikm_has_id(char *monitor_name)
*
* Returns 0 on success, -1 otherwise.
*/
-int ikm_list_monitors(void)
+int ikm_list_monitors(char *container)
{
char *available_monitors;
struct monitor ikm = {0};
char *curr, *next;
- int retval;
+ int retval, list_monitor = 0;
available_monitors = tracefs_instance_file_read(NULL, "rv/available_monitors", NULL);
@@ -347,17 +353,29 @@ int ikm_list_monitors(void)
next = strstr(curr, "\n");
*next = '\0';
- retval = ikm_fill_monitor_definition(curr, &ikm);
- if (retval)
+ retval = ikm_fill_monitor_definition(curr, &ikm, container);
+ if (retval < 0)
err_msg("ikm: error reading %d in kernel monitor, skipping\n", curr);
- printf("%s%-*s %s %s\n", ikm.nested ? " - " : "",
- ikm.nested ? MAX_DA_NAME_LEN - 3 : MAX_DA_NAME_LEN,
- ikm.name, ikm.desc, ikm.enabled ? "[ON]" : "[OFF]");
+ if (!retval) {
+ int indent = ikm.nested && !container;
+
+ list_monitor = 1;
+ printf("%s%-*s %s %s\n", indent ? " - " : "",
+ indent ? MAX_DA_NAME_LEN - 3 : MAX_DA_NAME_LEN,
+ ikm.name, ikm.desc, ikm.enabled ? "[ON]" : "[OFF]");
+ }
curr = ++next;
} while (strlen(curr));
+ if (!list_monitor) {
+ if (container)
+ printf("-- No monitor found in container %s --\n", container);
+ else
+ printf("-- No monitor found --\n");
+ }
+
free(available_monitors);
return 0;
diff --git a/tools/verification/rv/src/rv.c b/tools/verification/rv/src/rv.c
index 1ddb855328165..239de054d1e06 100644
--- a/tools/verification/rv/src/rv.c
+++ b/tools/verification/rv/src/rv.c
@@ -41,30 +41,42 @@ static void rv_list(int argc, char **argv)
{
static const char *const usage[] = {
"",
- " usage: rv list [-h]",
+ " usage: rv list [-h] [container]",
"",
" list all available monitors",
"",
" -h/--help: print this menu",
+ "",
+ " [container]: list only monitors in this container",
NULL,
};
- int i;
-
- if (argc > 1) {
+ int i, print_help = 0, retval = 0;
+ char *container = NULL;
+
+ if (argc == 2) {
+ if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+ print_help = 1;
+ retval = 0;
+ } else if (argv[1][0] == '-') {
+ /* assume invalid option */
+ print_help = 1;
+ retval = 1;
+ } else
+ container = argv[1];
+ } else if (argc > 2) {
+ /* more than 2 is always usage */
+ print_help = 1;
+ retval = 1;
+ }
+ if (print_help) {
fprintf(stderr, "rv version %s\n", VERSION);
-
- /* more than 1 is always usage */
for (i = 0; usage[i]; i++)
fprintf(stderr, "%s\n", usage[i]);
-
- /* but only -h is valid */
- if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
- exit(0);
- else
- exit(1);
+ exit(retval);
}
- ikm_list_monitors();
+ ikm_list_monitors(container);
+
exit(0);
}
--
2.48.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [RFC PATCH 03/11] sched: Add sched tracepoints for RV task model
2025-02-06 8:09 ` [RFC PATCH 03/11] sched: Add sched tracepoints for RV task model Gabriele Monaco
@ 2025-02-06 8:19 ` Peter Zijlstra
2025-02-06 8:36 ` Gabriele Monaco
0 siblings, 1 reply; 23+ messages in thread
From: Peter Zijlstra @ 2025-02-06 8:19 UTC (permalink / raw)
To: Gabriele Monaco
Cc: linux-kernel, Steven Rostedt, Ingo Molnar, Masami Hiramatsu,
linux-trace-kernel
On Thu, Feb 06, 2025 at 09:09:39AM +0100, Gabriele Monaco wrote:
> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index 9632e3318e0d6..af9fa18035c71 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -226,12 +226,14 @@ struct user_event_mm;
> #define __set_current_state(state_value) \
> do { \
> debug_normal_state_change((state_value)); \
> + trace_set_current_state(state_value); \
> WRITE_ONCE(current->__state, (state_value)); \
> } while (0)
>
> #define set_current_state(state_value) \
> do { \
> debug_normal_state_change((state_value)); \
> + trace_set_current_state(state_value); \
> smp_store_mb(current->__state, (state_value)); \
> } while (0)
>
> @@ -247,6 +249,7 @@ struct user_event_mm;
> \
> raw_spin_lock_irqsave(¤t->pi_lock, flags); \
> debug_special_state_change((state_value)); \
> + trace_set_current_state(state_value); \
> WRITE_ONCE(current->__state, (state_value)); \
> raw_spin_unlock_irqrestore(¤t->pi_lock, flags); \
> } while (0)
> @@ -282,6 +285,7 @@ struct user_event_mm;
> raw_spin_lock(¤t->pi_lock); \
> current->saved_state = current->__state; \
> debug_rtlock_wait_set_state(); \
> + trace_set_current_state(TASK_RTLOCK_WAIT); \
> WRITE_ONCE(current->__state, TASK_RTLOCK_WAIT); \
> raw_spin_unlock(¤t->pi_lock); \
> } while (0);
> @@ -291,6 +295,7 @@ struct user_event_mm;
> lockdep_assert_irqs_disabled(); \
> raw_spin_lock(¤t->pi_lock); \
> debug_rtlock_wait_restore_state(); \
> + trace_set_current_state(TASK_RUNNING); \
> WRITE_ONCE(current->__state, current->saved_state); \
> current->saved_state = TASK_RUNNING; \
> raw_spin_unlock(¤t->pi_lock); \
> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> index 165c90ba64ea9..fb5f8aa61ef5d 100644
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -491,6 +491,12 @@ sched_core_dequeue(struct rq *rq, struct task_struct *p, int flags) { }
>
> #endif /* CONFIG_SCHED_CORE */
>
> +void trace_set_current_state(int state_value)
> +{
> + trace_sched_set_state_tp(current, current->__state, state_value);
> +}
> +EXPORT_SYMBOL(trace_set_current_state);
Urgh, why !?!
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [RFC PATCH 03/11] sched: Add sched tracepoints for RV task model
2025-02-06 8:19 ` Peter Zijlstra
@ 2025-02-06 8:36 ` Gabriele Monaco
2025-02-06 8:57 ` Peter Zijlstra
0 siblings, 1 reply; 23+ messages in thread
From: Gabriele Monaco @ 2025-02-06 8:36 UTC (permalink / raw)
To: Peter Zijlstra
Cc: linux-kernel, Steven Rostedt, Ingo Molnar, Masami Hiramatsu,
linux-trace-kernel
On Thu, 2025-02-06 at 09:19 +0100, Peter Zijlstra wrote:
> On Thu, Feb 06, 2025 at 09:09:39AM +0100, Gabriele Monaco wrote:
>
> > diff --git a/include/linux/sched.h b/include/linux/sched.h
> > index 9632e3318e0d6..af9fa18035c71 100644
> > --- a/include/linux/sched.h
> > +++ b/include/linux/sched.h
> > @@ -226,12 +226,14 @@ struct user_event_mm;
> > #define
> > __set_current_state(state_value) \
> > do
> > { \
> > debug_normal_state_change((state_value));
> > \
> > + trace_set_current_state(state_value);
> > \
> > WRITE_ONCE(current->__state,
> > (state_value)); \
> > } while (0)
> >
> > #define
> > set_current_state(state_value) \
> > do
> > { \
> > debug_normal_state_change((state_value));
> > \
> > + trace_set_current_state(state_value);
> > \
> > smp_store_mb(current->__state,
> > (state_value)); \
> > } while (0)
> >
> > @@ -247,6 +249,7 @@ struct user_event_mm;
> >
> > \
> > raw_spin_lock_irqsave(¤t->pi_lock,
> > flags); \
> > debug_special_state_change((state_value));
> > \
> > + trace_set_current_state(state_value);
> > \
> > WRITE_ONCE(current->__state,
> > (state_value)); \
> > raw_spin_unlock_irqrestore(¤t->pi_lock,
> > flags); \
> > } while (0)
> > @@ -282,6 +285,7 @@ struct user_event_mm;
> > raw_spin_lock(¤t-
> > >pi_lock); \
> > current->saved_state = current-
> > >__state; \
> > debug_rtlock_wait_set_state();
> > \
> > + trace_set_current_state(TASK_RTLOCK_WAIT);
> > \
> > WRITE_ONCE(current->__state,
> > TASK_RTLOCK_WAIT); \
> > raw_spin_unlock(¤t-
> > >pi_lock); \
> > } while (0);
> > @@ -291,6 +295,7 @@ struct user_event_mm;
> > lockdep_assert_irqs_disabled();
> > \
> > raw_spin_lock(¤t-
> > >pi_lock); \
> > debug_rtlock_wait_restore_state();
> > \
> > + trace_set_current_state(TASK_RUNNING);
> > \
> > WRITE_ONCE(current->__state, current-
> > >saved_state); \
> > current->saved_state =
> > TASK_RUNNING; \
> > raw_spin_unlock(¤t-
> > >pi_lock); \
>
> > diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> > index 165c90ba64ea9..fb5f8aa61ef5d 100644
> > --- a/kernel/sched/core.c
> > +++ b/kernel/sched/core.c
> > @@ -491,6 +491,12 @@ sched_core_dequeue(struct rq *rq, struct
> > task_struct *p, int flags) { }
> >
> > #endif /* CONFIG_SCHED_CORE */
> >
> > +void trace_set_current_state(int state_value)
> > +{
> > + trace_sched_set_state_tp(current, current->__state,
> > state_value);
> > +}
> > +EXPORT_SYMBOL(trace_set_current_state);
>
> Urgh, why !?!
>
Do you mean why exporting it?
At first I was puzzled too (this line is borrowed from Daniel), but the
thing is: set_current_state and friends are macros called by any sort
of code (e.g. modules), this seems the easiest way without messing up
with the current code.
I'm not sure if it would be cleaner to just drop this function and
define it directly in the header (including also trace/events/sched.h
there). It felt like files including sched shouldn't know about
tracepoints.
What do you think would be better?
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [RFC PATCH 03/11] sched: Add sched tracepoints for RV task model
2025-02-06 8:36 ` Gabriele Monaco
@ 2025-02-06 8:57 ` Peter Zijlstra
2025-02-06 11:47 ` Gabriele Monaco
0 siblings, 1 reply; 23+ messages in thread
From: Peter Zijlstra @ 2025-02-06 8:57 UTC (permalink / raw)
To: Gabriele Monaco
Cc: linux-kernel, Steven Rostedt, Ingo Molnar, Masami Hiramatsu,
linux-trace-kernel
On Thu, Feb 06, 2025 at 09:36:41AM +0100, Gabriele Monaco wrote:
> > > diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> > > index 165c90ba64ea9..fb5f8aa61ef5d 100644
> > > --- a/kernel/sched/core.c
> > > +++ b/kernel/sched/core.c
> > > @@ -491,6 +491,12 @@ sched_core_dequeue(struct rq *rq, struct
> > > task_struct *p, int flags) { }
> > >
> > > #endif /* CONFIG_SCHED_CORE */
> > >
> > > +void trace_set_current_state(int state_value)
> > > +{
> > > + trace_sched_set_state_tp(current, current->__state,
> > > state_value);
> > > +}
> > > +EXPORT_SYMBOL(trace_set_current_state);
> >
> > Urgh, why !?!
> >
>
> Do you mean why exporting it?
> At first I was puzzled too (this line is borrowed from Daniel), but the
> thing is: set_current_state and friends are macros called by any sort
> of code (e.g. modules), this seems the easiest way without messing up
> with the current code.
>
> I'm not sure if it would be cleaner to just drop this function and
> define it directly in the header (including also trace/events/sched.h
> there). It felt like files including sched shouldn't know about
> tracepoints.
>
> What do you think would be better?
So I would think having the tracepoint in-line would be better. Because
as is, everything gets to have this pointless CALL to an empty function.
If this were x86_64 only, I would suggest using static_call(), but
barring that, the static_branch() already in the tracepoint is the best
we can do.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [RFC PATCH 03/11] sched: Add sched tracepoints for RV task model
2025-02-06 8:57 ` Peter Zijlstra
@ 2025-02-06 11:47 ` Gabriele Monaco
2025-02-06 13:36 ` Steven Rostedt
0 siblings, 1 reply; 23+ messages in thread
From: Gabriele Monaco @ 2025-02-06 11:47 UTC (permalink / raw)
To: Peter Zijlstra
Cc: linux-kernel, Steven Rostedt, Ingo Molnar, Masami Hiramatsu,
linux-trace-kernel
On Thu, 2025-02-06 at 09:57 +0100, Peter Zijlstra wrote:
> On Thu, Feb 06, 2025 at 09:36:41AM +0100, Gabriele Monaco wrote:
>
> > > > diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> > > > index 165c90ba64ea9..fb5f8aa61ef5d 100644
> > > > --- a/kernel/sched/core.c
> > > > +++ b/kernel/sched/core.c
> > > > @@ -491,6 +491,12 @@ sched_core_dequeue(struct rq *rq, struct
> > > > task_struct *p, int flags) { }
> > > >
> > > > #endif /* CONFIG_SCHED_CORE */
> > > >
> > > > +void trace_set_current_state(int state_value)
> > > > +{
> > > > + trace_sched_set_state_tp(current, current->__state,
> > > > state_value);
> > > > +}
> > > > +EXPORT_SYMBOL(trace_set_current_state);
> > >
> > > Urgh, why !?!
> >
> > What do you think would be better?
>
> So I would think having the tracepoint in-line would be better.
> Because
> as is, everything gets to have this pointless CALL to an empty
> function.
>
> If this were x86_64 only, I would suggest using static_call(), but
> barring that, the static_branch() already in the tracepoint is the
> best
> we can do.
>
Ok, I see your point now..
Adding the trace_ call inline seems far from trivial to me, but we
could indeed do what's suggested in tracepoint-defs.h and practically
use a static branch to call this trace_set_current_state, not sure if
this is already what you were suggesting, though.
Ignore the inconsistent naming, but something like this should work:
diff --git a/include/linux/sched.h b/include/linux/sched.h
index af9fa18035c7..7b9d84dbc2f5 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -223,6 +223,12 @@ struct user_event_mm;
*
* Also see the comments of try_to_wake_up().
*/
+
+#define trace_set_current_state(state_value) do { \
+ if (tracepoint_enabled(sched_set_state_tp)) \
+ do_trace_set_current_state(state_value); \
+} while(0)
+
#define __set_current_state(state_value) \
do { \
debug_normal_state_change((state_value)); \
@@ -332,7 +338,9 @@ extern void io_schedule_finish(int token);
extern long io_schedule_timeout(long timeout);
extern void io_schedule(void);
-extern void trace_set_current_state(int state_value);
+#include <linux/tracepoint-defs.h>
+DECLARE_TRACEPOINT(sched_set_state_tp);
+extern void do_trace_set_current_state(int state_value);
/**
* struct prev_cputime - snapshot of system and user cputime
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 149d55195532..9fc2be079bb5 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -491,11 +491,12 @@ sched_core_dequeue(struct rq *rq, struct task_struct *p, int flags) { }
#endif /* CONFIG_SCHED_CORE */
-void trace_set_current_state(int state_value)
+void do_trace_set_current_state(int state_value)
{
trace_sched_set_state_tp(current, current->__state, state_value);
}
-EXPORT_SYMBOL(trace_set_current_state);
+EXPORT_SYMBOL(do_trace_set_current_state);
+EXPORT_TRACEPOINT_SYMBOL(sched_set_state_tp);
/*
* Serialization rules:
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [RFC PATCH 03/11] sched: Add sched tracepoints for RV task model
2025-02-06 11:47 ` Gabriele Monaco
@ 2025-02-06 13:36 ` Steven Rostedt
0 siblings, 0 replies; 23+ messages in thread
From: Steven Rostedt @ 2025-02-06 13:36 UTC (permalink / raw)
To: Gabriele Monaco
Cc: Peter Zijlstra, linux-kernel, Ingo Molnar, Masami Hiramatsu,
linux-trace-kernel
On Thu, 06 Feb 2025 12:47:17 +0100
Gabriele Monaco <gmonaco@redhat.com> wrote:
> > > What do you think would be better?
> >
> > So I would think having the tracepoint in-line would be better.
> > Because
> > as is, everything gets to have this pointless CALL to an empty
> > function.
> >
> > If this were x86_64 only, I would suggest using static_call(), but
> > barring that, the static_branch() already in the tracepoint is the
> > best
> > we can do.
> >
>
> Ok, I see your point now..
>
> Adding the trace_ call inline seems far from trivial to me, but we
> could indeed do what's suggested in tracepoint-defs.h and practically
> use a static branch to call this trace_set_current_state, not sure if
> this is already what you were suggesting, though.
Right, due to the macro magic of how tracepoints are created, you can't
have them in header files. It causes too many side effects that can easily
break the build.
-- Steve
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [RFC PATCH 00/11] rv: Add scheduler specification monitors
2025-02-06 8:09 [RFC PATCH 00/11] rv: Add scheduler specification monitors Gabriele Monaco
` (10 preceding siblings ...)
2025-02-06 8:09 ` [RFC PATCH 11/11] tools/rv: Allow rv list to filter for container Gabriele Monaco
@ 2025-02-07 10:55 ` Juri Lelli
2025-02-07 11:36 ` Gabriele Monaco
11 siblings, 1 reply; 23+ messages in thread
From: Juri Lelli @ 2025-02-07 10:55 UTC (permalink / raw)
To: Gabriele Monaco
Cc: linux-kernel, Steven Rostedt, Ingo Molnar, Peter Zijlstra,
linux-trace-kernel, John Kacur, Clark Williams
Hi Gabriele,
On 06/02/25 09:09, Gabriele Monaco wrote:
> This patchset starts including adapted scheduler specifications from
> Daniel's task model [1].
Thanks a lot for working on this. Apart from being cool stuff per-se, it
means a lot personally to see Daniel's work continuing to be developed.
> As the model is fairly complicated, it is split in several generators
> and specifications. The tool used to create the model can output a
> unified model, but that would be hardly readable (9k states).
>
> RV allows monitors to run and react concurrently. Running the cumulative
> model is equivalent to running single components using the same
> reactors, with the advantage that it's easier to point out which
> specification failed in case of error.
>
> We allow this by introducing nested monitors, in short, the sysfs
> monitor folder will contain a monitor named sched, which is nothing but
> an empty container for other monitors. Controlling the sched monitor
> (enable, disable, set reactors) controls all nested monitors.
>
> The task model proposed by Daniel includes 12 generators and 33
> specifications. The generators are good for documentation but are
> usually implied in some specifications.
> Not all monitors work out of the box, mainly because of those reasons:
> * need to distinguish if preempt disable leads to schedule
> * need to distinguish if irq disable comes from an actual irq
> * assumptions not always true on SMP
>
> The original task model was designed for PREEMPT_RT and this patchset is
> only tested on an upstream kernel with full preemption enabled.
I played with your additions a bit and I was able to enable/disable
monitors, switch reactors, etc., w/o noticing any issue.
I wonder if you also had ways to test that the monitors actually react
properly in case of erroneous conditions (so that we can see a reactor
actually react :).
Thanks,
Juri
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [RFC PATCH 00/11] rv: Add scheduler specification monitors
2025-02-07 10:55 ` [RFC PATCH 00/11] rv: Add scheduler specification monitors Juri Lelli
@ 2025-02-07 11:36 ` Gabriele Monaco
2025-02-07 14:27 ` Juri Lelli
0 siblings, 1 reply; 23+ messages in thread
From: Gabriele Monaco @ 2025-02-07 11:36 UTC (permalink / raw)
To: Juri Lelli
Cc: linux-kernel, Steven Rostedt, Ingo Molnar, Peter Zijlstra,
linux-trace-kernel, John Kacur, Clark Williams
On Fri, 2025-02-07 at 11:55 +0100, Juri Lelli wrote:
> Hi Gabriele,
>
> On 06/02/25 09:09, Gabriele Monaco wrote:
> > This patchset starts including adapted scheduler specifications
> > from
> > Daniel's task model [1].
>
> Thanks a lot for working on this. Apart from being cool stuff per-se,
> it
> means a lot personally to see Daniel's work continuing to be
> developed.
>
> > As the model is fairly complicated, it is split in several
> > generators
> > and specifications. The tool used to create the model can output a
> > unified model, but that would be hardly readable (9k states).
> >
> > RV allows monitors to run and react concurrently. Running the
> > cumulative
> > model is equivalent to running single components using the same
> > reactors, with the advantage that it's easier to point out which
> > specification failed in case of error.
> >
> > We allow this by introducing nested monitors, in short, the sysfs
> > monitor folder will contain a monitor named sched, which is nothing
> > but
> > an empty container for other monitors. Controlling the sched
> > monitor
> > (enable, disable, set reactors) controls all nested monitors.
> >
> > The task model proposed by Daniel includes 12 generators and 33
> > specifications. The generators are good for documentation but are
> > usually implied in some specifications.
> > Not all monitors work out of the box, mainly because of those
> > reasons:
> > * need to distinguish if preempt disable leads to schedule
> > * need to distinguish if irq disable comes from an actual irq
> > * assumptions not always true on SMP
> >
> > The original task model was designed for PREEMPT_RT and this
> > patchset is
> > only tested on an upstream kernel with full preemption enabled.
>
> I played with your additions a bit and I was able to enable/disable
> monitors, switch reactors, etc., w/o noticing any issue.
>
Thanks for trying it out!
> I wonder if you also had ways to test that the monitors actually
> react
> properly in case of erroneous conditions (so that we can see a
> reactor
> actually react :).
>
Well, in my understanding, reactors should fire if there is a problem
either in the kernel or in the model logic.
While trying things out, I had more than a few models failing and I
excluded them from this patch because they are not stable.
Ideally you shouldn't be seeing errors using those monitors, unless you
(un)intentionally break something in the kernel.
That said, the monitor task switch while scheduling (tss) imposes
context switches whenever we reach the scheduler.
Daniel modified the sched_switch tracepoint to fire also if prev==next
(in fact no switch is happening), I'm assuming the tss specification is
partly why that was necessary.
During my tests, I didn't apply that change, yet I've never seen the
monitor failing.
If you manage to call __schedule while the next picked task is the same
as the currently running one, you should see an error and a reactor
firing.
Since I couldn't reproduce the above case, I ignored it for the current
RFC, however if that's possible in practice, we should perhaps add
another event describing this fake switch to prevent the monitor from
failing.
Thanks,
Gabriele
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [RFC PATCH 00/11] rv: Add scheduler specification monitors
2025-02-07 11:36 ` Gabriele Monaco
@ 2025-02-07 14:27 ` Juri Lelli
2025-02-07 14:57 ` Gabriele Monaco
2025-02-10 12:56 ` Gabriele Monaco
0 siblings, 2 replies; 23+ messages in thread
From: Juri Lelli @ 2025-02-07 14:27 UTC (permalink / raw)
To: Gabriele Monaco
Cc: linux-kernel, Steven Rostedt, Ingo Molnar, Peter Zijlstra,
linux-trace-kernel, John Kacur, Clark Williams
On 07/02/25 12:36, Gabriele Monaco wrote:
>
>
> On Fri, 2025-02-07 at 11:55 +0100, Juri Lelli wrote:
> > Hi Gabriele,
> >
> > On 06/02/25 09:09, Gabriele Monaco wrote:
> > > This patchset starts including adapted scheduler specifications
> > > from
> > > Daniel's task model [1].
> >
> > Thanks a lot for working on this. Apart from being cool stuff per-se,
> > it
> > means a lot personally to see Daniel's work continuing to be
> > developed.
> >
> > > As the model is fairly complicated, it is split in several
> > > generators
> > > and specifications. The tool used to create the model can output a
> > > unified model, but that would be hardly readable (9k states).
> > >
> > > RV allows monitors to run and react concurrently. Running the
> > > cumulative
> > > model is equivalent to running single components using the same
> > > reactors, with the advantage that it's easier to point out which
> > > specification failed in case of error.
> > >
> > > We allow this by introducing nested monitors, in short, the sysfs
> > > monitor folder will contain a monitor named sched, which is nothing
> > > but
> > > an empty container for other monitors. Controlling the sched
> > > monitor
> > > (enable, disable, set reactors) controls all nested monitors.
> > >
> > > The task model proposed by Daniel includes 12 generators and 33
> > > specifications. The generators are good for documentation but are
> > > usually implied in some specifications.
> > > Not all monitors work out of the box, mainly because of those
> > > reasons:
> > > * need to distinguish if preempt disable leads to schedule
> > > * need to distinguish if irq disable comes from an actual irq
> > > * assumptions not always true on SMP
> > >
> > > The original task model was designed for PREEMPT_RT and this
> > > patchset is
> > > only tested on an upstream kernel with full preemption enabled.
> >
> > I played with your additions a bit and I was able to enable/disable
> > monitors, switch reactors, etc., w/o noticing any issue.
> >
>
> Thanks for trying it out!
>
> > I wonder if you also had ways to test that the monitors actually
> > react
> > properly in case of erroneous conditions (so that we can see a
> > reactor
> > actually react :).
> >
>
> Well, in my understanding, reactors should fire if there is a problem
> either in the kernel or in the model logic.
Right. I guess I wonder if we can find a way to inject kernel problems
somehow, so that model(s) can be further tested explicitly thus making
us confident that they will be able to identify real problems when they
occur.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [RFC PATCH 00/11] rv: Add scheduler specification monitors
2025-02-07 14:27 ` Juri Lelli
@ 2025-02-07 14:57 ` Gabriele Monaco
2025-02-10 12:56 ` Gabriele Monaco
1 sibling, 0 replies; 23+ messages in thread
From: Gabriele Monaco @ 2025-02-07 14:57 UTC (permalink / raw)
To: Juri Lelli
Cc: linux-kernel, Steven Rostedt, Ingo Molnar, Peter Zijlstra,
linux-trace-kernel, John Kacur, Clark Williams
On Fri, 2025-02-07 at 15:27 +0100, Juri Lelli wrote:
> On 07/02/25 12:36, Gabriele Monaco wrote:
> >
> >
> > On Fri, 2025-02-07 at 11:55 +0100, Juri Lelli wrote:
> > > Hi Gabriele,
> > >
> > > On 06/02/25 09:09, Gabriele Monaco wrote:
> > > > This patchset starts including adapted scheduler specifications
> > > > from
> > > > Daniel's task model [1].
> > >
> > > Thanks a lot for working on this. Apart from being cool stuff
> > > per-se,
> > > it
> > > means a lot personally to see Daniel's work continuing to be
> > > developed.
> > >
> > > > As the model is fairly complicated, it is split in several
> > > > generators
> > > > and specifications. The tool used to create the model can
> > > > output a
> > > > unified model, but that would be hardly readable (9k states).
> > > >
> > > > RV allows monitors to run and react concurrently. Running the
> > > > cumulative
> > > > model is equivalent to running single components using the same
> > > > reactors, with the advantage that it's easier to point out
> > > > which
> > > > specification failed in case of error.
> > > >
> > > > We allow this by introducing nested monitors, in short, the
> > > > sysfs
> > > > monitor folder will contain a monitor named sched, which is
> > > > nothing
> > > > but
> > > > an empty container for other monitors. Controlling the sched
> > > > monitor
> > > > (enable, disable, set reactors) controls all nested monitors.
> > > >
> > > > The task model proposed by Daniel includes 12 generators and 33
> > > > specifications. The generators are good for documentation but
> > > > are
> > > > usually implied in some specifications.
> > > > Not all monitors work out of the box, mainly because of those
> > > > reasons:
> > > > * need to distinguish if preempt disable leads to schedule
> > > > * need to distinguish if irq disable comes from an actual irq
> > > > * assumptions not always true on SMP
> > > >
> > > > The original task model was designed for PREEMPT_RT and this
> > > > patchset is
> > > > only tested on an upstream kernel with full preemption enabled.
> > >
> > > I played with your additions a bit and I was able to
> > > enable/disable
> > > monitors, switch reactors, etc., w/o noticing any issue.
> > >
> >
> > Thanks for trying it out!
> >
> > > I wonder if you also had ways to test that the monitors actually
> > > react
> > > properly in case of erroneous conditions (so that we can see a
> > > reactor
> > > actually react :).
> > >
> >
> > Well, in my understanding, reactors should fire if there is a
> > problem
> > either in the kernel or in the model logic.
>
> Right. I guess I wonder if we can find a way to inject kernel
> problems
> somehow, so that model(s) can be further tested explicitly thus
> making
> us confident that they will be able to identify real problems when
> they
> occur.
>
Just for the sake of testing reactors there is already the wwnr monitor
which is intentionally broken exactly for that reason, Daniel described
a bit what scenario can trigger the error (some IRQ, so it may be
harder to see in a VM).
If we want any monitor to react, yeah that could be a bit trickier. We
could perhaps do something like livepatching/kprobes.
I'd assume we'd need some care though, since some of those monitors are
pretty basic and making them fail may cause pretty bad errors in the
kernel.
Another approach could be to just inject the tracepoint/handler call
those are all static functions but we may have some luck there and
wouldn't break the system, just trick the monitor.
But good point, I can have a look.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [RFC PATCH 00/11] rv: Add scheduler specification monitors
2025-02-07 14:27 ` Juri Lelli
2025-02-07 14:57 ` Gabriele Monaco
@ 2025-02-10 12:56 ` Gabriele Monaco
2025-02-11 9:38 ` Juri Lelli
1 sibling, 1 reply; 23+ messages in thread
From: Gabriele Monaco @ 2025-02-10 12:56 UTC (permalink / raw)
To: Juri Lelli
Cc: linux-kernel, Steven Rostedt, Ingo Molnar, Peter Zijlstra,
linux-trace-kernel, John Kacur, Clark Williams
On Fri, 2025-02-07 at 15:27 +0100, Juri Lelli wrote:
>
> Right. I guess I wonder if we can find a way to inject kernel
> problems
> somehow, so that model(s) can be further tested explicitly thus
> making
> us confident that they will be able to identify real problems when
> they
> occur.
>
I sketched it quickly and I wouldn't include it in this series not to
make it heavier, but if you want to play with it I wrote a patch
exporting a function to inject events and building a kernel module
calling the function periodically.
You'd need to build the kernel with CONFIG_RV_DEBUG_TRIGGER and do
something like
# modprobe monitor=snroc event=1
# ./tools/verification/rv/rv mon snroc -r printk
# dmesg
[ 88.327892] rv: monitor snroc does not allow event sched_switch_in
on state own_context
You can omit event (in which case it will select the first) and select
different monitors. In case of per-task monitors (as the one above),
some events may never trigger errors, but if you choose carefully while
modprobe-ing you should be fine. The events numbers are defined as enum
in the monitor header (e.g. snroc.h).
Subject: [PATCH] rv: Add infrastructure to trigger debug events
RV monitors are supposed to test some core functionality and, in ideal
scenarios, should never fire errors. This implies that we cannot test if
reactors work as expected on a properly set monitor, which may add false
positives.
A common example is a monitor where no da_handle_start_event_ function
is called, in such a case, the monitor would never start, so it never
produces events nor errors.
It is easy to understand this monitor is wrongly configured by checking
the events tracepoints, but if a test setup expects the monitor to
trigger reactors in case of failure, it will erroneously flag such a
monitor as correct.
Enable creation for each monitor of an exported function to simulate
triggering an event. This function can be used from any other kernel
code, including modules, to inject events into the monitor for debugging
purposes.
This can effectively used to test reactors on monitors which, otherwise,
would never fire any error.
The function has the following prototype, where name is the monitor name:
bool da_trigger_event_name(int event)
event can be any integer, but real events will be triggered only if the
supplied number is a valid event for the monitor, otherwise nothing
happens and the function returns false.
If this configuration is disabled, no function is defined.
Also add a module that relies on this function to periodically trigger
events to the selected monitor.
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
include/rv/da_monitor.h | 59 +++++++++++++++-
kernel/trace/rv/Kconfig | 27 +++++++
kernel/trace/rv/Makefile | 1 +
kernel/trace/rv/rv_debug_trigger.c | 110 +++++++++++++++++++++++++++++
4 files changed, 195 insertions(+), 2 deletions(-)
create mode 100644 kernel/trace/rv/rv_debug_trigger.c
diff --git a/include/rv/da_monitor.h b/include/rv/da_monitor.h
index 510c88bfabd43..ed9f66c53ed7b 100644
--- a/include/rv/da_monitor.h
+++ b/include/rv/da_monitor.h
@@ -514,6 +514,59 @@ da_handle_start_event_##name(struct task_struct *tsk, enum events_##name event)
return 1; \
}
+#ifdef CONFIG_RV_DEBUG_TRIGGER
+
+/*
+ * Handle event for implicit monitors
+ */
+#define DECLARE_DA_MON_TRIGGER_IMPLICIT(name) \
+/* \
+ * da_trigger_event_##name - trigger an event from outside the monitor \
+ * \
+ * This function is used only for debug purposes, it calls the function to \
+ * handle events to simulate the occurrence of the event. This may can be \
+ * useful to make the monitor fail and test reactors but may have unintended \
+ * consequences. \
+ * For simplicity, accept the event as int but validate its value and return \
+ * true if the event was valid, false if not and we did not trigger it. \
+ */ \
+bool da_trigger_event_##name(int event); \
+bool da_trigger_event_##name(int event) \
+{ \
+ if (event < 0 || event >= event_max_##name) \
+ return false; \
+ da_handle_event_##name(event); \
+ return true; \
+} \
+EXPORT_SYMBOL(da_trigger_event_##name);
+
+/*
+ * Handle event for per-task monitors
+ */
+#define DECLARE_DA_MON_TRIGGER_PER_TASK(name) \
+/* \
+ * da_trigger_event_##name - trigger an event from outside the monitor \
+ * \
+ * This function is used only for debug purposes, it calls the function to \
+ * handle events to simulate the occurrence of the event. This may can be \
+ * useful to make the monitor fail and test reactors but may have unintended \
+ * consequences. \
+ * For simplicity, accept the event as int but validate its value and return \
+ * true if the event was valid, false if not and we did not trigger it. \
+ * Also to keep it simple for the caller, fill the task with current. \
+ */ \
+bool da_trigger_event_##name(int event); \
+bool da_trigger_event_##name(int event) \
+{ \
+ if (event < 0 || event >= event_max_##name) \
+ return false; \
+ da_handle_event_##name(current, event); \
+ return true; \
+} \
+EXPORT_SYMBOL(da_trigger_event_##name);
+
+#endif /* CONFIG_RV_DEBUG_TRIGGER */
+
/*
* Entry point for the global monitor.
*/
@@ -534,7 +587,8 @@ DECLARE_AUTOMATA_HELPERS(name, type) \
DECLARE_DA_MON_GENERIC_HELPERS(name, type) \
DECLARE_DA_MON_MODEL_HANDLER_IMPLICIT(name, type) \
DECLARE_DA_MON_INIT_PER_CPU(name, type) \
-DECLARE_DA_MON_MONITOR_HANDLER_IMPLICIT(name, type)
+DECLARE_DA_MON_MONITOR_HANDLER_IMPLICIT(name, type) \
+DECLARE_DA_MON_TRIGGER_IMPLICIT(name)
/*
* Entry point for the per-task monitor.
@@ -545,4 +599,5 @@ DECLARE_AUTOMATA_HELPERS(name, type) \
DECLARE_DA_MON_GENERIC_HELPERS(name, type) \
DECLARE_DA_MON_MODEL_HANDLER_PER_TASK(name, type) \
DECLARE_DA_MON_INIT_PER_TASK(name, type) \
-DECLARE_DA_MON_MONITOR_HANDLER_PER_TASK(name, type)
+DECLARE_DA_MON_MONITOR_HANDLER_PER_TASK(name, type) \
+DECLARE_DA_MON_TRIGGER_PER_TASK(name)
diff --git a/kernel/trace/rv/Kconfig b/kernel/trace/rv/Kconfig
index b39f36013ef23..6aa927db99ee8 100644
--- a/kernel/trace/rv/Kconfig
+++ b/kernel/trace/rv/Kconfig
@@ -62,3 +62,30 @@ config RV_REACT_PANIC
help
Enables the panic reactor. The panic reactor emits a printk()
message if an exception is found and panic()s the system.
+
+config RV_DEBUG_TRIGGER
+ bool "Runtime verification debug trigger event"
+ default n
+ depends on RV
+ help
+ Enables creation for each monitor of an exported function to simulate
+ triggering an event. This function can be used from any other kernel
+ code, including modules, to inject events into the monitor for debugging
+ purposes. A common use-case is to test reactors on monitors which,
+ otherwise, would never fire any error.
+ Use the function with care as it might have unintended consequences.
+ The function has the following prototype, where name is the monitor name:
+ bool da_trigger_event_name(int event)
+ event can be any integer, but real events will be triggered only if the
+ supplied number is a valid event for the monitor, otherwise nothing
+ happens and the function returns false.
+
+ This configuration enables compilation of the rv_debug_trigger kernel
+ module which relies on this function to periodically trigger events.
+ If the configuration is disabled, no function is defined.
+
+config RV_DEBUG_TRIGGER_MODULE
+ tristate
+ default m if RV_DEBUG_TRIGGER
+ depends on RV
+ depends on RV_DEBUG_TRIGGER
diff --git a/kernel/trace/rv/Makefile b/kernel/trace/rv/Makefile
index f9b2cd0483c3c..47207c81260ee 100644
--- a/kernel/trace/rv/Makefile
+++ b/kernel/trace/rv/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_RV_MON_SNCID) += monitors/sncid/sncid.o
obj-$(CONFIG_RV_REACTORS) += rv_reactors.o
obj-$(CONFIG_RV_REACT_PRINTK) += reactor_printk.o
obj-$(CONFIG_RV_REACT_PANIC) += reactor_panic.o
+obj-$(CONFIG_RV_DEBUG_TRIGGER_MODULE) += rv_debug_trigger.o
diff --git a/kernel/trace/rv/rv_debug_trigger.c b/kernel/trace/rv/rv_debug_trigger.c
new file mode 100644
index 0000000000000..fa5bbdf14ca5f
--- /dev/null
+++ b/kernel/trace/rv/rv_debug_trigger.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025-2028 Red Hat, Inc. Gabriele Monaco <gmonaco@redhat.com>
+ *
+ * RV debug trigger module:
+ * Insert this module to periodically trigger a fake event to the monitor
+ * provided as parameter. The numerical value of the event can be set as
+ * parameter as well.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rv.h>
+
+bool da_trigger_event_wip(int event);
+bool da_trigger_event_wwnr(int event);
+bool da_trigger_event_tss(int event);
+bool da_trigger_event_sco(int event);
+bool da_trigger_event_snroc(int event);
+bool da_trigger_event_scpd(int event);
+bool da_trigger_event_snep(int event);
+bool da_trigger_event_sncid(int event);
+
+/* do not allow periodicity lower than 1 us */
+#define MIN_PERIOD 1000
+
+static char monitor[MAX_DA_NAME_LEN] = "wwnr";
+module_param_string(monitor, monitor, sizeof(monitor), 0644);
+
+static int event = 0;
+module_param(event, int, 0644);
+
+static int period = 1000000;
+module_param(period, int, 0644);
+
+static bool (*trigger)(int event);
+static struct hrtimer periodic_timer;
+
+static enum hrtimer_restart trigger_worker(struct hrtimer *timer)
+{
+ hrtimer_forward_now(timer, period);
+ trigger(event);
+ return HRTIMER_RESTART;
+}
+
+static int __init rv_debug_trigger_init(void)
+{
+#ifdef CONFIG_RV_MON_WIP
+ if (!strcmp(monitor, "wip"))
+ trigger = da_trigger_event_wip;
+#endif
+#ifdef CONFIG_RV_MON_WWNR
+ if (!strcmp(monitor, "wwnr"))
+ trigger = da_trigger_event_wwnr;
+#endif
+#ifdef CONFIG_RV_MON_TSS
+ if (!strcmp(monitor, "tss"))
+ trigger = da_trigger_event_tss;
+#endif
+#ifdef CONFIG_RV_MON_SCO
+ if (!strcmp(monitor, "sco"))
+ trigger = da_trigger_event_sco;
+#endif
+#ifdef CONFIG_RV_MON_SNROC
+ if (!strcmp(monitor, "snroc"))
+ trigger = da_trigger_event_snroc;
+#endif
+#ifdef CONFIG_RV_MON_SCPD
+ if (!strcmp(monitor, "scpd"))
+ trigger = da_trigger_event_scpd;
+#endif
+#ifdef CONFIG_RV_MON_SNEP
+ if (!strcmp(monitor, "snep"))
+ trigger = da_trigger_event_snep;
+#endif
+#ifdef CONFIG_RV_MON_SNCID
+ if (!strcmp(monitor, "sncid"))
+ trigger = da_trigger_event_sncid;
+#endif
+
+ if (!trigger) {
+ pr_warn("Invalid monitor %s\n", monitor);
+ return -EINVAL;
+ }
+ if (!trigger(event)) {
+ pr_warn("Invalid event %d for monitor %s\n", event,
+ monitor);
+ return -EINVAL;
+ }
+ if (period < MIN_PERIOD) {
+ pr_warn("Use at least %d us as period, %d provided\n",
+ MIN_PERIOD, period);
+ return -EINVAL;
+ }
+ hrtimer_init(&periodic_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ periodic_timer.function = trigger_worker;
+ hrtimer_start(&periodic_timer, period, HRTIMER_MODE_REL);
+ return 0;
+}
+
+static void __exit rv_debug_trigger_exit(void)
+{
+ hrtimer_cancel(&periodic_timer);
+}
+
+module_init(rv_debug_trigger_init);
+module_exit(rv_debug_trigger_exit);
+
+MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>");
+MODULE_DESCRIPTION("RV debug trigger: periodically trigger a fake event.");
+MODULE_LICENSE("GPL");
base-commit: df5b7771dc64df426b4bd52c7d591a316b839570
--
2.48.1
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [RFC PATCH 00/11] rv: Add scheduler specification monitors
2025-02-10 12:56 ` Gabriele Monaco
@ 2025-02-11 9:38 ` Juri Lelli
0 siblings, 0 replies; 23+ messages in thread
From: Juri Lelli @ 2025-02-11 9:38 UTC (permalink / raw)
To: Gabriele Monaco
Cc: linux-kernel, Steven Rostedt, Ingo Molnar, Peter Zijlstra,
linux-trace-kernel, John Kacur, Clark Williams
On 10/02/25 13:56, Gabriele Monaco wrote:
> On Fri, 2025-02-07 at 15:27 +0100, Juri Lelli wrote:
> >
> > Right. I guess I wonder if we can find a way to inject kernel
> > problems
> > somehow, so that model(s) can be further tested explicitly thus
> > making
> > us confident that they will be able to identify real problems when
> > they
> > occur.
> >
>
> I sketched it quickly and I wouldn't include it in this series not to
> make it heavier, but if you want to play with it I wrote a patch
> exporting a function to inject events and building a kernel module
> calling the function periodically.
Ah, this is cool. Thanks for working on it!
Yeah, agree, we can leave it for later.
Thanks!
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2025-02-11 9:38 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-06 8:09 [RFC PATCH 00/11] rv: Add scheduler specification monitors Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 01/11] tracing: Fix DECLARE_TRACE_CONDITION Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 02/11] rv: Add license identifiers to monitor files Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 03/11] sched: Add sched tracepoints for RV task model Gabriele Monaco
2025-02-06 8:19 ` Peter Zijlstra
2025-02-06 8:36 ` Gabriele Monaco
2025-02-06 8:57 ` Peter Zijlstra
2025-02-06 11:47 ` Gabriele Monaco
2025-02-06 13:36 ` Steven Rostedt
2025-02-06 8:09 ` [RFC PATCH 04/11] rv: Add option for nested monitors and include sched Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 05/11] rv: Add sco and tss per-cpu monitors Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 06/11] rv: Add snroc per-task monitor Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 07/11] rv: Add scpd, snep and sncid per-cpu monitors Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 08/11] tools/rv: Add support for nested monitors Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 09/11] verification/dot2k: " Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 10/11] Documentation/rv: Add docs for the sched monitors Gabriele Monaco
2025-02-06 8:09 ` [RFC PATCH 11/11] tools/rv: Allow rv list to filter for container Gabriele Monaco
2025-02-07 10:55 ` [RFC PATCH 00/11] rv: Add scheduler specification monitors Juri Lelli
2025-02-07 11:36 ` Gabriele Monaco
2025-02-07 14:27 ` Juri Lelli
2025-02-07 14:57 ` Gabriele Monaco
2025-02-10 12:56 ` Gabriele Monaco
2025-02-11 9:38 ` Juri Lelli
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).