Commit d0096c2f authored by Gabriele Monaco's avatar Gabriele Monaco Committed by Steven Rostedt (Google)
Browse files

rv: Replace tss and sncid monitors with more complete sts

The tss monitor currently guarantees task switches can happen only while
scheduling, whereas the sncid monitor enforces scheduling occurs with
interrupt disabled.

Replace the monitors with a more comprehensive specification which
implies both but also ensures that:
* each scheduler call disable interrupts to switch
* each task switch happens with interrupts disabled

Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Nam Cao <namcao@linutronix.de>
Cc: Tomas Glozar <tglozar@redhat.com>
Cc: Juri Lelli <jlelli@redhat.com>
Cc: Clark Williams <williams@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/20250728135022.255578-8-gmonaco@redhat.com


Signed-off-by: default avatarGabriele Monaco <gmonaco@redhat.com>
Signed-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
parent adcc3bfa
Loading
Loading
Loading
Loading
+48 −39
Original line number Diff line number Diff line
@@ -40,26 +40,6 @@ 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
~~~~~~~~~~~

@@ -144,26 +124,55 @@ does not enable preemption::
                                                  |
                          scheduling_contex      -+

Monitor sncid
~~~~~~~~~~~~~

The schedule not called with interrupt disabled (sncid) monitor ensures
schedule is not called with interrupt disabled::
Monitor sts
~~~~~~~~~~~

                       |
                       |
                       v
    schedule_entry   +--------------+
    schedule_exit    |              |
  +----------------- |  can_sched   |
  |                  |              |
  +----------------> |              | <+
                     +--------------+  |
The schedule implies task switch (sts) monitor ensures a task switch happens
only in scheduling context and up to once, as well as scheduling occurs with
interrupts enabled but no task switch can happen before interrupts are
disabled. When the next task picked for execution is the same as the previously
running one, no real task switch occurs but interrupts are disabled nonetheless::

    irq_entry                      |
     +----+                        |
     v    |                        v
 +------------+ irq_enable    #===================#   irq_disable
 |            | ------------> H                   H   irq_entry
 | cant_sched | <------------ H                   H   irq_enable
 |            | irq_disable   H     can_sched     H --------------+
 +------------+               H                   H               |
                              H                   H               |
            +---------------> H                   H <-------------+
            |                 #===================#
            |                   |
                       | irq_disable   | irq_enable
                       v               |
                                       |
                        cant_sched    -+
      schedule_exit             | schedule_entry
            |                   v
            |   +-------------------+     irq_enable
            |   |    scheduling     | <---------------+
            |   +-------------------+                 |
            |     |                                   |
            |     | irq_disable                    +--------+  irq_entry
            |     v                                |        | --------+
            |   +-------------------+  irq_entry   | in_irq |         |
            |   |                   | -----------> |        | <-------+
            |   | disable_to_switch |              +--------+
            |   |                   | --+
            |   +-------------------+   |
            |     |                     |
            |     | sched_switch        |
            |     v                     |
            |   +-------------------+   |
            |   |     switching     |   | irq_enable
            |   +-------------------+   |
            |     |                     |
            |     | irq_enable          |
            |     v                     |
            |   +-------------------+   |
            +-- |  enable_to_exit   | <-+
                +-------------------+
                  ^               | irq_disable
                  |               | irq_entry
                  +---------------+ irq_enable

References
----------
+1 −2
Original line number Diff line number Diff line
@@ -50,12 +50,11 @@ 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"
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"
source "kernel/trace/rv/monitors/sts/Kconfig"
# Add new sched monitors here

source "kernel/trace/rv/monitors/rtapp/Kconfig"
+1 −2
Original line number Diff line number Diff line
@@ -6,15 +6,14 @@ 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
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
obj-$(CONFIG_RV_MON_RTAPP) += monitors/rtapp/rtapp.o
obj-$(CONFIG_RV_MON_PAGEFAULT) += monitors/pagefault/pagefault.o
obj-$(CONFIG_RV_MON_SLEEP) += monitors/sleep/sleep.o
obj-$(CONFIG_RV_MON_STS) += monitors/sts/sts.o
# Add new monitors here
obj-$(CONFIG_RV_REACTORS) += rv_reactors.o
obj-$(CONFIG_RV_REACT_PRINTK) += reactor_printk.o
+0 −95
Original line number Diff line number Diff line
// 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)
{
	da_handle_start_event_sncid(schedule_entry_sncid);
}

static void handle_schedule_exit(void *data, bool is_switch)
{
	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)
{
	return rv_register_monitor(&rv_sncid, &rv_sched);
}

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.");
+0 −49
Original line number Diff line number Diff line
/* 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 },
};
Loading