Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'trace-latency-v6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull latency tracing updates from Steven Rostedt:

- Add some trace events to osnoise and timerlat sample generation

This adds more information to the osnoise and timerlat tracers as
well as allows BPF programs to be attached to these locations to
extract even more data.

- Fix to DECLARE_TRACE_CONDITION() macro

It wasn't used but now will be and it happened to be broken causing
the build to fail.

- Add scheduler specification monitors to runtime verifier (RV)

This is a continuation of Daniel Bristot's work.

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.

This update introduces nested monitors to RV, 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 following scheduling monitors are added:

- 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

- snroc: set non runnable on its own context
Monitor to ensure set_state happens only in the respective task's context

- 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

* tag 'trace-latency-v6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
tools/rv: Allow rv list to filter for container
Documentation/rv: Add docs for the sched monitors
verification/dot2k: Add support for nested monitors
tools/rv: Add support for nested monitors
rv: Add scpd, snep and sncid per-cpu monitors
rv: Add snroc per-task monitor
rv: Add sco and tss per-cpu monitors
rv: Add option for nested monitors and include sched
sched: Add sched tracepoints for RV task model
rv: Add license identifiers to monitor files
tracing: Fix DECLARE_TRACE_CONDITION
trace/osnoise: Add trace events for samples

+2134 -165
+69
Documentation/tools/rv/rv-mon-sched.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + ============ 4 + rv-mon-sched 5 + ============ 6 + ----------------------------- 7 + Scheduler monitors collection 8 + ----------------------------- 9 + 10 + :Manual section: 1 11 + 12 + SYNOPSIS 13 + ======== 14 + 15 + **rv mon sched** [*OPTIONS*] 16 + 17 + **rv mon <NESTED_MONITOR>** [*OPTIONS*] 18 + 19 + **rv mon sched:<NESTED_MONITOR>** [*OPTIONS*] 20 + 21 + DESCRIPTION 22 + =========== 23 + 24 + The scheduler monitor collection is a container for several monitors to model 25 + the behaviour of the scheduler. Each monitor describes a specification that 26 + the scheduler should follow. 27 + 28 + As a monitor container, it will enable all nested monitors and set them 29 + according to OPTIONS. 30 + Nevertheless nested monitors can also be activated independently both by name 31 + and by specifying sched: , e.g. to enable only monitor tss you can do any of: 32 + 33 + # rv mon sched:tss 34 + 35 + # rv mon tss 36 + 37 + See kernel documentation for further information about this monitor: 38 + <https://docs.kernel.org/trace/rv/monitor_sched.html> 39 + 40 + OPTIONS 41 + ======= 42 + 43 + .. include:: common_ikm.rst 44 + 45 + NESTED MONITOR 46 + ============== 47 + 48 + The available nested monitors are: 49 + * scpd: schedule called with preemption disabled 50 + * snep: schedule does not enable preempt 51 + * sncid: schedule not called with interrupt disabled 52 + * snroc: set non runnable on its own context 53 + * sco: scheduling context operations 54 + * tss: task switch while scheduling 55 + 56 + SEE ALSO 57 + ======== 58 + 59 + **rv**\(1), **rv-mon**\(1) 60 + 61 + Linux kernel *RV* documentation: 62 + <https://www.kernel.org/doc/html/latest/trace/rv/index.html> 63 + 64 + AUTHOR 65 + ====== 66 + 67 + Written by Gabriele Monaco <gmonaco@redhat.com> 68 + 69 + .. include:: common_appendix.rst
+171
Documentation/trace/rv/monitor_sched.rst
··· 1 + Scheduler monitors 2 + ================== 3 + 4 + - Name: sched 5 + - Type: container for multiple monitors 6 + - Author: Gabriele Monaco <gmonaco@redhat.com>, Daniel Bristot de Oliveira <bristot@kernel.org> 7 + 8 + Description 9 + ----------- 10 + 11 + Monitors describing complex systems, such as the scheduler, can easily grow to 12 + the point where they are just hard to understand because of the many possible 13 + state transitions. 14 + Often it is possible to break such descriptions into smaller monitors, 15 + sharing some or all events. Enabling those smaller monitors concurrently is, 16 + in fact, testing the system as if we had one single larger monitor. 17 + Splitting models into multiple specification is not only easier to 18 + understand, but gives some more clues when we see errors. 19 + 20 + The sched monitor is a set of specifications to describe the scheduler behaviour. 21 + It includes several per-cpu and per-task monitors that work independently to verify 22 + different specifications the scheduler should follow. 23 + 24 + To make this system as straightforward as possible, sched specifications are *nested* 25 + monitors, whereas sched itself is a *container*. 26 + From the interface perspective, sched includes other monitors as sub-directories, 27 + enabling/disabling or setting reactors to sched, propagates the change to all monitors, 28 + however single monitors can be used independently as well. 29 + 30 + It is important that future modules are built after their container (sched, in 31 + this case), otherwise the linker would not respect the order and the nesting 32 + wouldn't work as expected. 33 + To do so, simply add them after sched in the Makefile. 34 + 35 + Specifications 36 + -------------- 37 + 38 + The specifications included in sched are currently a work in progress, adapting the ones 39 + defined in by Daniel Bristot in [1]. 40 + 41 + Currently we included the following: 42 + 43 + Monitor tss 44 + ~~~~~~~~~~~ 45 + 46 + The task switch while scheduling (tss) monitor ensures a task switch happens 47 + only in scheduling context, that is inside a call to `__schedule`:: 48 + 49 + | 50 + | 51 + v 52 + +-----------------+ 53 + | thread | <+ 54 + +-----------------+ | 55 + | | 56 + | schedule_entry | schedule_exit 57 + v | 58 + sched_switch | 59 + +--------------- | 60 + | sched | 61 + +--------------> -+ 62 + 63 + Monitor sco 64 + ~~~~~~~~~~~ 65 + 66 + The scheduling context operations (sco) monitor ensures changes in a task state 67 + happen only in thread context:: 68 + 69 + 70 + | 71 + | 72 + v 73 + sched_set_state +------------------+ 74 + +------------------ | | 75 + | | thread_context | 76 + +-----------------> | | <+ 77 + +------------------+ | 78 + | | 79 + | schedule_entry | schedule_exit 80 + v | 81 + | 82 + scheduling_context -+ 83 + 84 + Monitor snroc 85 + ~~~~~~~~~~~~~ 86 + 87 + The set non runnable on its own context (snroc) monitor ensures changes in a 88 + task state happens only in the respective task's context. This is a per-task 89 + monitor:: 90 + 91 + | 92 + | 93 + v 94 + +------------------+ 95 + | other_context | <+ 96 + +------------------+ | 97 + | | 98 + | sched_switch_in | sched_switch_out 99 + v | 100 + sched_set_state | 101 + +------------------ | 102 + | own_context | 103 + +-----------------> -+ 104 + 105 + Monitor scpd 106 + ~~~~~~~~~~~~ 107 + 108 + The schedule called with preemption disabled (scpd) monitor ensures schedule is 109 + called with preemption disabled:: 110 + 111 + | 112 + | 113 + v 114 + +------------------+ 115 + | cant_sched | <+ 116 + +------------------+ | 117 + | | 118 + | preempt_disable | preempt_enable 119 + v | 120 + schedule_entry | 121 + schedule_exit | 122 + +----------------- can_sched | 123 + | | 124 + +----------------> -+ 125 + 126 + Monitor snep 127 + ~~~~~~~~~~~~ 128 + 129 + The schedule does not enable preempt (snep) monitor ensures a schedule call 130 + does not enable preemption:: 131 + 132 + | 133 + | 134 + v 135 + preempt_disable +------------------------+ 136 + preempt_enable | | 137 + +------------------ | non_scheduling_context | 138 + | | | 139 + +-----------------> | | <+ 140 + +------------------------+ | 141 + | | 142 + | schedule_entry | schedule_exit 143 + v | 144 + | 145 + scheduling_contex -+ 146 + 147 + Monitor sncid 148 + ~~~~~~~~~~~~~ 149 + 150 + The schedule not called with interrupt disabled (sncid) monitor ensures 151 + schedule is not called with interrupt disabled:: 152 + 153 + | 154 + | 155 + v 156 + schedule_entry +--------------+ 157 + schedule_exit | | 158 + +----------------- | can_sched | 159 + | | | 160 + +----------------> | | <+ 161 + +--------------+ | 162 + | | 163 + | irq_disable | irq_enable 164 + v | 165 + | 166 + cant_sched -+ 167 + 168 + References 169 + ---------- 170 + 171 + [1] - https://bristot.me/linux-task-model
+2 -2
include/linux/rv.h
··· 7 7 #ifndef _LINUX_RV_H 8 8 #define _LINUX_RV_H 9 9 10 - #define MAX_DA_NAME_LEN 24 10 + #define MAX_DA_NAME_LEN 32 11 11 12 12 #ifdef CONFIG_RV 13 13 /* ··· 56 56 57 57 bool rv_monitoring_on(void); 58 58 int rv_unregister_monitor(struct rv_monitor *monitor); 59 - int rv_register_monitor(struct rv_monitor *monitor); 59 + int rv_register_monitor(struct rv_monitor *monitor, struct rv_monitor *parent); 60 60 int rv_get_task_monitor_slot(void); 61 61 void rv_put_task_monitor_slot(int slot); 62 62
+16
include/linux/sched.h
··· 46 46 #include <linux/rv.h> 47 47 #include <linux/livepatch_sched.h> 48 48 #include <linux/uidgid_types.h> 49 + #include <linux/tracepoint-defs.h> 49 50 #include <asm/kmap_size.h> 50 51 51 52 /* task_struct member predeclarations (sorted alphabetically): */ ··· 188 187 # define debug_rtlock_wait_restore_state() do { } while (0) 189 188 #endif 190 189 190 + #define trace_set_current_state(state_value) \ 191 + do { \ 192 + if (tracepoint_enabled(sched_set_state_tp)) \ 193 + __trace_set_current_state(state_value); \ 194 + } while (0) 195 + 191 196 /* 192 197 * set_current_state() includes a barrier so that the write of current->__state 193 198 * is correctly serialised wrt the caller's subsequent test of whether to ··· 234 227 #define __set_current_state(state_value) \ 235 228 do { \ 236 229 debug_normal_state_change((state_value)); \ 230 + trace_set_current_state(state_value); \ 237 231 WRITE_ONCE(current->__state, (state_value)); \ 238 232 } while (0) 239 233 240 234 #define set_current_state(state_value) \ 241 235 do { \ 242 236 debug_normal_state_change((state_value)); \ 237 + trace_set_current_state(state_value); \ 243 238 smp_store_mb(current->__state, (state_value)); \ 244 239 } while (0) 245 240 ··· 257 248 \ 258 249 raw_spin_lock_irqsave(&current->pi_lock, flags); \ 259 250 debug_special_state_change((state_value)); \ 251 + trace_set_current_state(state_value); \ 260 252 WRITE_ONCE(current->__state, (state_value)); \ 261 253 raw_spin_unlock_irqrestore(&current->pi_lock, flags); \ 262 254 } while (0) ··· 293 283 raw_spin_lock(&current->pi_lock); \ 294 284 current->saved_state = current->__state; \ 295 285 debug_rtlock_wait_set_state(); \ 286 + trace_set_current_state(TASK_RTLOCK_WAIT); \ 296 287 WRITE_ONCE(current->__state, TASK_RTLOCK_WAIT); \ 297 288 raw_spin_unlock(&current->pi_lock); \ 298 289 } while (0); ··· 303 292 lockdep_assert_irqs_disabled(); \ 304 293 raw_spin_lock(&current->pi_lock); \ 305 294 debug_rtlock_wait_restore_state(); \ 295 + trace_set_current_state(current->saved_state); \ 306 296 WRITE_ONCE(current->__state, current->saved_state); \ 307 297 current->saved_state = TASK_RUNNING; \ 308 298 raw_spin_unlock(&current->pi_lock); \ ··· 339 327 extern void io_schedule_finish(int token); 340 328 extern long io_schedule_timeout(long timeout); 341 329 extern void io_schedule(void); 330 + 331 + /* wrapper function to trace from this header file */ 332 + DECLARE_TRACEPOINT(sched_set_state_tp); 333 + extern void __trace_set_current_state(int state_value); 342 334 343 335 /** 344 336 * struct prev_cputime - snapshot of system and user cputime
+7
include/trace/define_trace.h
··· 76 76 #define DECLARE_TRACE(name, proto, args) \ 77 77 DEFINE_TRACE(name, PARAMS(proto), PARAMS(args)) 78 78 79 + #undef DECLARE_TRACE_CONDITION 80 + #define DECLARE_TRACE_CONDITION(name, proto, args, cond) \ 81 + DEFINE_TRACE(name, PARAMS(proto), PARAMS(args)) 82 + 79 83 /* If requested, create helpers for calling these tracepoints from Rust. */ 80 84 #ifdef CREATE_RUST_TRACE_POINTS 81 85 #undef DEFINE_RUST_DO_TRACE ··· 112 108 /* Make all open coded DECLARE_TRACE nops */ 113 109 #undef DECLARE_TRACE 114 110 #define DECLARE_TRACE(name, proto, args) 111 + #undef DECLARE_TRACE_CONDITION 112 + #define DECLARE_TRACE_CONDITION(name, proto, args, cond) 115 113 116 114 #ifdef TRACEPOINTS_ENABLED 117 115 #include <trace/trace_events.h> ··· 135 129 #undef DEFINE_EVENT_CONDITION 136 130 #undef TRACE_HEADER_MULTI_READ 137 131 #undef DECLARE_TRACE 132 + #undef DECLARE_TRACE_CONDITION 138 133 139 134 /* Only undef what we defined in this file */ 140 135 #ifdef UNDEF_TRACE_INCLUDE_FILE
+96
include/trace/events/osnoise.h
··· 3 3 #define TRACE_SYSTEM osnoise 4 4 5 5 #if !defined(_OSNOISE_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) 6 + 7 + #ifndef _OSNOISE_TRACE_H 6 8 #define _OSNOISE_TRACE_H 9 + /* 10 + * osnoise sample structure definition. Used to store the statistics of a 11 + * sample run. 12 + */ 13 + struct osnoise_sample { 14 + u64 runtime; /* runtime */ 15 + u64 noise; /* noise */ 16 + u64 max_sample; /* max single noise sample */ 17 + int hw_count; /* # HW (incl. hypervisor) interference */ 18 + int nmi_count; /* # NMIs during this sample */ 19 + int irq_count; /* # IRQs during this sample */ 20 + int softirq_count; /* # softirqs during this sample */ 21 + int thread_count; /* # threads during this sample */ 22 + }; 23 + 24 + #ifdef CONFIG_TIMERLAT_TRACER 25 + /* 26 + * timerlat sample structure definition. Used to store the statistics of 27 + * a sample run. 28 + */ 29 + struct timerlat_sample { 30 + u64 timer_latency; /* timer_latency */ 31 + unsigned int seqnum; /* unique sequence */ 32 + int context; /* timer context */ 33 + }; 34 + #endif // CONFIG_TIMERLAT_TRACER 35 + #endif // _OSNOISE_TRACE_H 7 36 8 37 #include <linux/tracepoint.h> 38 + TRACE_EVENT(osnoise_sample, 39 + 40 + TP_PROTO(struct osnoise_sample *s), 41 + 42 + TP_ARGS(s), 43 + 44 + TP_STRUCT__entry( 45 + __field( u64, runtime ) 46 + __field( u64, noise ) 47 + __field( u64, max_sample ) 48 + __field( int, hw_count ) 49 + __field( int, irq_count ) 50 + __field( int, nmi_count ) 51 + __field( int, softirq_count ) 52 + __field( int, thread_count ) 53 + ), 54 + 55 + TP_fast_assign( 56 + __entry->runtime = s->runtime; 57 + __entry->noise = s->noise; 58 + __entry->max_sample = s->max_sample; 59 + __entry->hw_count = s->hw_count; 60 + __entry->irq_count = s->irq_count; 61 + __entry->nmi_count = s->nmi_count; 62 + __entry->softirq_count = s->softirq_count; 63 + __entry->thread_count = s->thread_count; 64 + ), 65 + 66 + TP_printk("runtime=%llu noise=%llu max_sample=%llu hw_count=%d" 67 + " irq_count=%d nmi_count=%d softirq_count=%d" 68 + " thread_count=%d", 69 + __entry->runtime, 70 + __entry->noise, 71 + __entry->max_sample, 72 + __entry->hw_count, 73 + __entry->irq_count, 74 + __entry->nmi_count, 75 + __entry->softirq_count, 76 + __entry->thread_count) 77 + ); 78 + 79 + #ifdef CONFIG_TIMERLAT_TRACER 80 + TRACE_EVENT(timerlat_sample, 81 + 82 + TP_PROTO(struct timerlat_sample *s), 83 + 84 + TP_ARGS(s), 85 + 86 + TP_STRUCT__entry( 87 + __field( u64, timer_latency ) 88 + __field( unsigned int, seqnum ) 89 + __field( int, context ) 90 + ), 91 + 92 + TP_fast_assign( 93 + __entry->timer_latency = s->timer_latency; 94 + __entry->seqnum = s->seqnum; 95 + __entry->context = s->context; 96 + ), 97 + 98 + TP_printk("timer_latency=%llu seqnum=%u context=%d", 99 + __entry->timer_latency, 100 + __entry->seqnum, 101 + __entry->context) 102 + ); 103 + #endif // CONFIG_TIMERLAT_TRACER 104 + 9 105 TRACE_EVENT(thread_noise, 10 106 11 107 TP_PROTO(struct task_struct *t, u64 start, u64 duration),
+13
include/trace/events/sched.h
··· 822 822 unsigned long max_util, unsigned long busy_time), 823 823 TP_ARGS(p, dst_cpu, energy, max_util, busy_time)); 824 824 825 + DECLARE_TRACE(sched_entry_tp, 826 + TP_PROTO(bool preempt, unsigned long ip), 827 + TP_ARGS(preempt, ip)); 828 + 829 + DECLARE_TRACE(sched_exit_tp, 830 + TP_PROTO(bool is_switch, unsigned long ip), 831 + TP_ARGS(is_switch, ip)); 832 + 833 + DECLARE_TRACE_CONDITION(sched_set_state_tp, 834 + TP_PROTO(struct task_struct *tsk, int state), 835 + TP_ARGS(tsk, state), 836 + TP_CONDITION(!!(tsk->__state) != !!state)); 837 + 825 838 #endif /* _TRACE_SCHED_H */ 826 839 827 840 /* This part must be outside protection */
+22 -1
kernel/sched/core.c
··· 488 488 489 489 #endif /* CONFIG_SCHED_CORE */ 490 490 491 + /* need a wrapper since we may need to trace from modules */ 492 + EXPORT_TRACEPOINT_SYMBOL(sched_set_state_tp); 493 + 494 + /* Call via the helper macro trace_set_current_state. */ 495 + void __trace_set_current_state(int state_value) 496 + { 497 + trace_sched_set_state_tp(current, state_value); 498 + } 499 + EXPORT_SYMBOL(__trace_set_current_state); 500 + 491 501 /* 492 502 * Serialization rules: 493 503 * ··· 5305 5295 */ 5306 5296 5307 5297 finish_task_switch(prev); 5298 + /* 5299 + * This is a special case: the newly created task has just 5300 + * switched the context for the first time. It is returning from 5301 + * schedule for the first time in this path. 5302 + */ 5303 + trace_sched_exit_tp(true, CALLER_ADDR0); 5308 5304 preempt_enable(); 5309 5305 5310 5306 if (current->set_child_tid) ··· 6650 6634 * as a preemption by schedule_debug() and RCU. 6651 6635 */ 6652 6636 bool preempt = sched_mode > SM_NONE; 6637 + bool is_switch = false; 6653 6638 unsigned long *switch_count; 6654 6639 unsigned long prev_state; 6655 6640 struct rq_flags rf; 6656 6641 struct rq *rq; 6657 6642 int cpu; 6643 + 6644 + trace_sched_entry_tp(preempt, CALLER_ADDR0); 6658 6645 6659 6646 cpu = smp_processor_id(); 6660 6647 rq = cpu_rq(cpu); ··· 6724 6705 clear_preempt_need_resched(); 6725 6706 rq->last_seen_need_resched_ns = 0; 6726 6707 6727 - if (likely(prev != next)) { 6708 + is_switch = prev != next; 6709 + if (likely(is_switch)) { 6728 6710 rq->nr_switches++; 6729 6711 /* 6730 6712 * RCU users of rcu_dereference(rq->curr) may not see ··· 6770 6750 __balance_callbacks(rq); 6771 6751 raw_spin_rq_unlock_irq(rq); 6772 6752 } 6753 + trace_sched_exit_tp(is_switch, CALLER_ADDR0); 6773 6754 } 6774 6755 6775 6756 void __noreturn do_task_dead(void)
+7
kernel/trace/rv/Kconfig
··· 27 27 28 28 source "kernel/trace/rv/monitors/wip/Kconfig" 29 29 source "kernel/trace/rv/monitors/wwnr/Kconfig" 30 + source "kernel/trace/rv/monitors/sched/Kconfig" 31 + source "kernel/trace/rv/monitors/tss/Kconfig" 32 + source "kernel/trace/rv/monitors/sco/Kconfig" 33 + source "kernel/trace/rv/monitors/snroc/Kconfig" 34 + source "kernel/trace/rv/monitors/scpd/Kconfig" 35 + source "kernel/trace/rv/monitors/snep/Kconfig" 36 + source "kernel/trace/rv/monitors/sncid/Kconfig" 30 37 # Add new monitors here 31 38 32 39 config RV_REACTORS
+7
kernel/trace/rv/Makefile
··· 5 5 obj-$(CONFIG_RV) += rv.o 6 6 obj-$(CONFIG_RV_MON_WIP) += monitors/wip/wip.o 7 7 obj-$(CONFIG_RV_MON_WWNR) += monitors/wwnr/wwnr.o 8 + obj-$(CONFIG_RV_MON_SCHED) += monitors/sched/sched.o 9 + obj-$(CONFIG_RV_MON_TSS) += monitors/tss/tss.o 10 + obj-$(CONFIG_RV_MON_SCO) += monitors/sco/sco.o 11 + obj-$(CONFIG_RV_MON_SNROC) += monitors/snroc/snroc.o 12 + obj-$(CONFIG_RV_MON_SCPD) += monitors/scpd/scpd.o 13 + obj-$(CONFIG_RV_MON_SNEP) += monitors/snep/snep.o 14 + obj-$(CONFIG_RV_MON_SNCID) += monitors/sncid/sncid.o 8 15 # Add new monitors here 9 16 obj-$(CONFIG_RV_REACTORS) += rv_reactors.o 10 17 obj-$(CONFIG_RV_REACT_PRINTK) += reactor_printk.o
+11
kernel/trace/rv/monitors/sched/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 3 + config RV_MON_SCHED 4 + depends on RV 5 + bool "sched monitor" 6 + help 7 + Collection of monitors to check the scheduler behaves according to specifications. 8 + Enable this to enable all scheduler specification supported by the current kernel. 9 + 10 + For further information, see: 11 + Documentation/trace/rv/monitor_sched.rst
+38
kernel/trace/rv/monitors/sched/sched.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/kernel.h> 3 + #include <linux/module.h> 4 + #include <linux/init.h> 5 + #include <linux/rv.h> 6 + 7 + #define MODULE_NAME "sched" 8 + 9 + #include "sched.h" 10 + 11 + struct rv_monitor rv_sched; 12 + 13 + struct rv_monitor rv_sched = { 14 + .name = "sched", 15 + .description = "container for several scheduler monitor specifications.", 16 + .enable = NULL, 17 + .disable = NULL, 18 + .reset = NULL, 19 + .enabled = 0, 20 + }; 21 + 22 + static int __init register_sched(void) 23 + { 24 + rv_register_monitor(&rv_sched, NULL); 25 + return 0; 26 + } 27 + 28 + static void __exit unregister_sched(void) 29 + { 30 + rv_unregister_monitor(&rv_sched); 31 + } 32 + 33 + module_init(register_sched); 34 + module_exit(unregister_sched); 35 + 36 + MODULE_LICENSE("GPL"); 37 + MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>"); 38 + MODULE_DESCRIPTION("sched: container for several scheduler monitor specifications.");
+3
kernel/trace/rv/monitors/sched/sched.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + extern struct rv_monitor rv_sched;
+14
kernel/trace/rv/monitors/sco/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 3 + config RV_MON_SCO 4 + depends on RV 5 + depends on RV_MON_SCHED 6 + default y 7 + select DA_MON_EVENTS_IMPLICIT 8 + bool "sco monitor" 9 + help 10 + Monitor to ensure sched_set_state happens only in thread context. 11 + This monitor is part of the sched monitors collection. 12 + 13 + For further information, see: 14 + Documentation/trace/rv/monitor_sched.rst
+88
kernel/trace/rv/monitors/sco/sco.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/ftrace.h> 3 + #include <linux/tracepoint.h> 4 + #include <linux/kernel.h> 5 + #include <linux/module.h> 6 + #include <linux/init.h> 7 + #include <linux/rv.h> 8 + #include <rv/instrumentation.h> 9 + #include <rv/da_monitor.h> 10 + 11 + #define MODULE_NAME "sco" 12 + 13 + #include <trace/events/sched.h> 14 + #include <rv_trace.h> 15 + #include <monitors/sched/sched.h> 16 + 17 + #include "sco.h" 18 + 19 + static struct rv_monitor rv_sco; 20 + DECLARE_DA_MON_PER_CPU(sco, unsigned char); 21 + 22 + static void handle_sched_set_state(void *data, struct task_struct *tsk, int state) 23 + { 24 + da_handle_start_event_sco(sched_set_state_sco); 25 + } 26 + 27 + static void handle_schedule_entry(void *data, bool preempt, unsigned long ip) 28 + { 29 + da_handle_event_sco(schedule_entry_sco); 30 + } 31 + 32 + static void handle_schedule_exit(void *data, bool is_switch, unsigned long ip) 33 + { 34 + da_handle_start_event_sco(schedule_exit_sco); 35 + } 36 + 37 + static int enable_sco(void) 38 + { 39 + int retval; 40 + 41 + retval = da_monitor_init_sco(); 42 + if (retval) 43 + return retval; 44 + 45 + rv_attach_trace_probe("sco", sched_set_state_tp, handle_sched_set_state); 46 + rv_attach_trace_probe("sco", sched_entry_tp, handle_schedule_entry); 47 + rv_attach_trace_probe("sco", sched_exit_tp, handle_schedule_exit); 48 + 49 + return 0; 50 + } 51 + 52 + static void disable_sco(void) 53 + { 54 + rv_sco.enabled = 0; 55 + 56 + rv_detach_trace_probe("sco", sched_set_state_tp, handle_sched_set_state); 57 + rv_detach_trace_probe("sco", sched_entry_tp, handle_schedule_entry); 58 + rv_detach_trace_probe("sco", sched_exit_tp, handle_schedule_exit); 59 + 60 + da_monitor_destroy_sco(); 61 + } 62 + 63 + static struct rv_monitor rv_sco = { 64 + .name = "sco", 65 + .description = "scheduling context operations.", 66 + .enable = enable_sco, 67 + .disable = disable_sco, 68 + .reset = da_monitor_reset_all_sco, 69 + .enabled = 0, 70 + }; 71 + 72 + static int __init register_sco(void) 73 + { 74 + rv_register_monitor(&rv_sco, &rv_sched); 75 + return 0; 76 + } 77 + 78 + static void __exit unregister_sco(void) 79 + { 80 + rv_unregister_monitor(&rv_sco); 81 + } 82 + 83 + module_init(register_sco); 84 + module_exit(unregister_sco); 85 + 86 + MODULE_LICENSE("GPL"); 87 + MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>"); 88 + MODULE_DESCRIPTION("sco: scheduling context operations.");
+47
kernel/trace/rv/monitors/sco/sco.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Automatically generated C representation of sco automaton 4 + * For further information about this format, see kernel documentation: 5 + * Documentation/trace/rv/deterministic_automata.rst 6 + */ 7 + 8 + enum states_sco { 9 + thread_context_sco = 0, 10 + scheduling_context_sco, 11 + state_max_sco 12 + }; 13 + 14 + #define INVALID_STATE state_max_sco 15 + 16 + enum events_sco { 17 + sched_set_state_sco = 0, 18 + schedule_entry_sco, 19 + schedule_exit_sco, 20 + event_max_sco 21 + }; 22 + 23 + struct automaton_sco { 24 + char *state_names[state_max_sco]; 25 + char *event_names[event_max_sco]; 26 + unsigned char function[state_max_sco][event_max_sco]; 27 + unsigned char initial_state; 28 + bool final_states[state_max_sco]; 29 + }; 30 + 31 + static const struct automaton_sco automaton_sco = { 32 + .state_names = { 33 + "thread_context", 34 + "scheduling_context" 35 + }, 36 + .event_names = { 37 + "sched_set_state", 38 + "schedule_entry", 39 + "schedule_exit" 40 + }, 41 + .function = { 42 + { thread_context_sco, scheduling_context_sco, INVALID_STATE }, 43 + { INVALID_STATE, INVALID_STATE, thread_context_sco }, 44 + }, 45 + .initial_state = thread_context_sco, 46 + .final_states = { 1, 0 }, 47 + };
+15
kernel/trace/rv/monitors/sco/sco_trace.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + /* 4 + * Snippet to be included in rv_trace.h 5 + */ 6 + 7 + #ifdef CONFIG_RV_MON_SCO 8 + DEFINE_EVENT(event_da_monitor, event_sco, 9 + TP_PROTO(char *state, char *event, char *next_state, bool final_state), 10 + TP_ARGS(state, event, next_state, final_state)); 11 + 12 + DEFINE_EVENT(error_da_monitor, error_sco, 13 + TP_PROTO(char *state, char *event), 14 + TP_ARGS(state, event)); 15 + #endif /* CONFIG_RV_MON_SCO */
+15
kernel/trace/rv/monitors/scpd/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 3 + config RV_MON_SCPD 4 + depends on RV 5 + depends on PREEMPT_TRACER 6 + depends on RV_MON_SCHED 7 + default y 8 + select DA_MON_EVENTS_IMPLICIT 9 + bool "scpd monitor" 10 + help 11 + Monitor to ensure schedule is called with preemption disabled. 12 + This monitor is part of the sched monitors collection. 13 + 14 + For further information, see: 15 + Documentation/trace/rv/monitor_sched.rst
+96
kernel/trace/rv/monitors/scpd/scpd.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/ftrace.h> 3 + #include <linux/tracepoint.h> 4 + #include <linux/kernel.h> 5 + #include <linux/module.h> 6 + #include <linux/init.h> 7 + #include <linux/rv.h> 8 + #include <rv/instrumentation.h> 9 + #include <rv/da_monitor.h> 10 + 11 + #define MODULE_NAME "scpd" 12 + 13 + #include <trace/events/sched.h> 14 + #include <trace/events/preemptirq.h> 15 + #include <rv_trace.h> 16 + #include <monitors/sched/sched.h> 17 + 18 + #include "scpd.h" 19 + 20 + static struct rv_monitor rv_scpd; 21 + DECLARE_DA_MON_PER_CPU(scpd, unsigned char); 22 + 23 + static void handle_preempt_disable(void *data, unsigned long ip, unsigned long parent_ip) 24 + { 25 + da_handle_event_scpd(preempt_disable_scpd); 26 + } 27 + 28 + static void handle_preempt_enable(void *data, unsigned long ip, unsigned long parent_ip) 29 + { 30 + da_handle_start_event_scpd(preempt_enable_scpd); 31 + } 32 + 33 + static void handle_schedule_entry(void *data, bool preempt, unsigned long ip) 34 + { 35 + da_handle_event_scpd(schedule_entry_scpd); 36 + } 37 + 38 + static void handle_schedule_exit(void *data, bool is_switch, unsigned long ip) 39 + { 40 + da_handle_event_scpd(schedule_exit_scpd); 41 + } 42 + 43 + static int enable_scpd(void) 44 + { 45 + int retval; 46 + 47 + retval = da_monitor_init_scpd(); 48 + if (retval) 49 + return retval; 50 + 51 + rv_attach_trace_probe("scpd", preempt_disable, handle_preempt_disable); 52 + rv_attach_trace_probe("scpd", preempt_enable, handle_preempt_enable); 53 + rv_attach_trace_probe("scpd", sched_entry_tp, handle_schedule_entry); 54 + rv_attach_trace_probe("scpd", sched_exit_tp, handle_schedule_exit); 55 + 56 + return 0; 57 + } 58 + 59 + static void disable_scpd(void) 60 + { 61 + rv_scpd.enabled = 0; 62 + 63 + rv_detach_trace_probe("scpd", preempt_disable, handle_preempt_disable); 64 + rv_detach_trace_probe("scpd", preempt_enable, handle_preempt_enable); 65 + rv_detach_trace_probe("scpd", sched_entry_tp, handle_schedule_entry); 66 + rv_detach_trace_probe("scpd", sched_exit_tp, handle_schedule_exit); 67 + 68 + da_monitor_destroy_scpd(); 69 + } 70 + 71 + static struct rv_monitor rv_scpd = { 72 + .name = "scpd", 73 + .description = "schedule called with preemption disabled.", 74 + .enable = enable_scpd, 75 + .disable = disable_scpd, 76 + .reset = da_monitor_reset_all_scpd, 77 + .enabled = 0, 78 + }; 79 + 80 + static int __init register_scpd(void) 81 + { 82 + rv_register_monitor(&rv_scpd, &rv_sched); 83 + return 0; 84 + } 85 + 86 + static void __exit unregister_scpd(void) 87 + { 88 + rv_unregister_monitor(&rv_scpd); 89 + } 90 + 91 + module_init(register_scpd); 92 + module_exit(unregister_scpd); 93 + 94 + MODULE_LICENSE("GPL"); 95 + MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>"); 96 + MODULE_DESCRIPTION("scpd: schedule called with preemption disabled.");
+49
kernel/trace/rv/monitors/scpd/scpd.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Automatically generated C representation of scpd automaton 4 + * For further information about this format, see kernel documentation: 5 + * Documentation/trace/rv/deterministic_automata.rst 6 + */ 7 + 8 + enum states_scpd { 9 + cant_sched_scpd = 0, 10 + can_sched_scpd, 11 + state_max_scpd 12 + }; 13 + 14 + #define INVALID_STATE state_max_scpd 15 + 16 + enum events_scpd { 17 + preempt_disable_scpd = 0, 18 + preempt_enable_scpd, 19 + schedule_entry_scpd, 20 + schedule_exit_scpd, 21 + event_max_scpd 22 + }; 23 + 24 + struct automaton_scpd { 25 + char *state_names[state_max_scpd]; 26 + char *event_names[event_max_scpd]; 27 + unsigned char function[state_max_scpd][event_max_scpd]; 28 + unsigned char initial_state; 29 + bool final_states[state_max_scpd]; 30 + }; 31 + 32 + static const struct automaton_scpd automaton_scpd = { 33 + .state_names = { 34 + "cant_sched", 35 + "can_sched" 36 + }, 37 + .event_names = { 38 + "preempt_disable", 39 + "preempt_enable", 40 + "schedule_entry", 41 + "schedule_exit" 42 + }, 43 + .function = { 44 + { can_sched_scpd, INVALID_STATE, INVALID_STATE, INVALID_STATE }, 45 + { INVALID_STATE, cant_sched_scpd, can_sched_scpd, can_sched_scpd }, 46 + }, 47 + .initial_state = cant_sched_scpd, 48 + .final_states = { 1, 0 }, 49 + };
+15
kernel/trace/rv/monitors/scpd/scpd_trace.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + /* 4 + * Snippet to be included in rv_trace.h 5 + */ 6 + 7 + #ifdef CONFIG_RV_MON_SCPD 8 + DEFINE_EVENT(event_da_monitor, event_scpd, 9 + TP_PROTO(char *state, char *event, char *next_state, bool final_state), 10 + TP_ARGS(state, event, next_state, final_state)); 11 + 12 + DEFINE_EVENT(error_da_monitor, error_scpd, 13 + TP_PROTO(char *state, char *event), 14 + TP_ARGS(state, event)); 15 + #endif /* CONFIG_RV_MON_SCPD */
+15
kernel/trace/rv/monitors/sncid/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 3 + config RV_MON_SNCID 4 + depends on RV 5 + depends on IRQSOFF_TRACER 6 + depends on RV_MON_SCHED 7 + default y 8 + select DA_MON_EVENTS_IMPLICIT 9 + bool "sncid monitor" 10 + help 11 + Monitor to ensure schedule is not called with interrupt disabled. 12 + This monitor is part of the sched monitors collection. 13 + 14 + For further information, see: 15 + Documentation/trace/rv/monitor_sched.rst
+96
kernel/trace/rv/monitors/sncid/sncid.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/ftrace.h> 3 + #include <linux/tracepoint.h> 4 + #include <linux/kernel.h> 5 + #include <linux/module.h> 6 + #include <linux/init.h> 7 + #include <linux/rv.h> 8 + #include <rv/instrumentation.h> 9 + #include <rv/da_monitor.h> 10 + 11 + #define MODULE_NAME "sncid" 12 + 13 + #include <trace/events/sched.h> 14 + #include <trace/events/preemptirq.h> 15 + #include <rv_trace.h> 16 + #include <monitors/sched/sched.h> 17 + 18 + #include "sncid.h" 19 + 20 + static struct rv_monitor rv_sncid; 21 + DECLARE_DA_MON_PER_CPU(sncid, unsigned char); 22 + 23 + static void handle_irq_disable(void *data, unsigned long ip, unsigned long parent_ip) 24 + { 25 + da_handle_event_sncid(irq_disable_sncid); 26 + } 27 + 28 + static void handle_irq_enable(void *data, unsigned long ip, unsigned long parent_ip) 29 + { 30 + da_handle_start_event_sncid(irq_enable_sncid); 31 + } 32 + 33 + static void handle_schedule_entry(void *data, bool preempt, unsigned long ip) 34 + { 35 + da_handle_start_event_sncid(schedule_entry_sncid); 36 + } 37 + 38 + static void handle_schedule_exit(void *data, bool is_switch, unsigned long ip) 39 + { 40 + da_handle_start_event_sncid(schedule_exit_sncid); 41 + } 42 + 43 + static int enable_sncid(void) 44 + { 45 + int retval; 46 + 47 + retval = da_monitor_init_sncid(); 48 + if (retval) 49 + return retval; 50 + 51 + rv_attach_trace_probe("sncid", irq_disable, handle_irq_disable); 52 + rv_attach_trace_probe("sncid", irq_enable, handle_irq_enable); 53 + rv_attach_trace_probe("sncid", sched_entry_tp, handle_schedule_entry); 54 + rv_attach_trace_probe("sncid", sched_exit_tp, handle_schedule_exit); 55 + 56 + return 0; 57 + } 58 + 59 + static void disable_sncid(void) 60 + { 61 + rv_sncid.enabled = 0; 62 + 63 + rv_detach_trace_probe("sncid", irq_disable, handle_irq_disable); 64 + rv_detach_trace_probe("sncid", irq_enable, handle_irq_enable); 65 + rv_detach_trace_probe("sncid", sched_entry_tp, handle_schedule_entry); 66 + rv_detach_trace_probe("sncid", sched_exit_tp, handle_schedule_exit); 67 + 68 + da_monitor_destroy_sncid(); 69 + } 70 + 71 + static struct rv_monitor rv_sncid = { 72 + .name = "sncid", 73 + .description = "schedule not called with interrupt disabled.", 74 + .enable = enable_sncid, 75 + .disable = disable_sncid, 76 + .reset = da_monitor_reset_all_sncid, 77 + .enabled = 0, 78 + }; 79 + 80 + static int __init register_sncid(void) 81 + { 82 + rv_register_monitor(&rv_sncid, &rv_sched); 83 + return 0; 84 + } 85 + 86 + static void __exit unregister_sncid(void) 87 + { 88 + rv_unregister_monitor(&rv_sncid); 89 + } 90 + 91 + module_init(register_sncid); 92 + module_exit(unregister_sncid); 93 + 94 + MODULE_LICENSE("GPL"); 95 + MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>"); 96 + MODULE_DESCRIPTION("sncid: schedule not called with interrupt disabled.");
+49
kernel/trace/rv/monitors/sncid/sncid.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Automatically generated C representation of sncid automaton 4 + * For further information about this format, see kernel documentation: 5 + * Documentation/trace/rv/deterministic_automata.rst 6 + */ 7 + 8 + enum states_sncid { 9 + can_sched_sncid = 0, 10 + cant_sched_sncid, 11 + state_max_sncid 12 + }; 13 + 14 + #define INVALID_STATE state_max_sncid 15 + 16 + enum events_sncid { 17 + irq_disable_sncid = 0, 18 + irq_enable_sncid, 19 + schedule_entry_sncid, 20 + schedule_exit_sncid, 21 + event_max_sncid 22 + }; 23 + 24 + struct automaton_sncid { 25 + char *state_names[state_max_sncid]; 26 + char *event_names[event_max_sncid]; 27 + unsigned char function[state_max_sncid][event_max_sncid]; 28 + unsigned char initial_state; 29 + bool final_states[state_max_sncid]; 30 + }; 31 + 32 + static const struct automaton_sncid automaton_sncid = { 33 + .state_names = { 34 + "can_sched", 35 + "cant_sched" 36 + }, 37 + .event_names = { 38 + "irq_disable", 39 + "irq_enable", 40 + "schedule_entry", 41 + "schedule_exit" 42 + }, 43 + .function = { 44 + { cant_sched_sncid, INVALID_STATE, can_sched_sncid, can_sched_sncid }, 45 + { INVALID_STATE, can_sched_sncid, INVALID_STATE, INVALID_STATE }, 46 + }, 47 + .initial_state = can_sched_sncid, 48 + .final_states = { 1, 0 }, 49 + };
+15
kernel/trace/rv/monitors/sncid/sncid_trace.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + /* 4 + * Snippet to be included in rv_trace.h 5 + */ 6 + 7 + #ifdef CONFIG_RV_MON_SNCID 8 + DEFINE_EVENT(event_da_monitor, event_sncid, 9 + TP_PROTO(char *state, char *event, char *next_state, bool final_state), 10 + TP_ARGS(state, event, next_state, final_state)); 11 + 12 + DEFINE_EVENT(error_da_monitor, error_sncid, 13 + TP_PROTO(char *state, char *event), 14 + TP_ARGS(state, event)); 15 + #endif /* CONFIG_RV_MON_SNCID */
+15
kernel/trace/rv/monitors/snep/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 3 + config RV_MON_SNEP 4 + depends on RV 5 + depends on PREEMPT_TRACER 6 + depends on RV_MON_SCHED 7 + default y 8 + select DA_MON_EVENTS_IMPLICIT 9 + bool "snep monitor" 10 + help 11 + Monitor to ensure schedule does not enable preempt. 12 + This monitor is part of the sched monitors collection. 13 + 14 + For further information, see: 15 + Documentation/trace/rv/monitor_sched.rst
+96
kernel/trace/rv/monitors/snep/snep.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/ftrace.h> 3 + #include <linux/tracepoint.h> 4 + #include <linux/kernel.h> 5 + #include <linux/module.h> 6 + #include <linux/init.h> 7 + #include <linux/rv.h> 8 + #include <rv/instrumentation.h> 9 + #include <rv/da_monitor.h> 10 + 11 + #define MODULE_NAME "snep" 12 + 13 + #include <trace/events/sched.h> 14 + #include <trace/events/preemptirq.h> 15 + #include <rv_trace.h> 16 + #include <monitors/sched/sched.h> 17 + 18 + #include "snep.h" 19 + 20 + static struct rv_monitor rv_snep; 21 + DECLARE_DA_MON_PER_CPU(snep, unsigned char); 22 + 23 + static void handle_preempt_disable(void *data, unsigned long ip, unsigned long parent_ip) 24 + { 25 + da_handle_start_event_snep(preempt_disable_snep); 26 + } 27 + 28 + static void handle_preempt_enable(void *data, unsigned long ip, unsigned long parent_ip) 29 + { 30 + da_handle_start_event_snep(preempt_enable_snep); 31 + } 32 + 33 + static void handle_schedule_entry(void *data, bool preempt, unsigned long ip) 34 + { 35 + da_handle_event_snep(schedule_entry_snep); 36 + } 37 + 38 + static void handle_schedule_exit(void *data, bool is_switch, unsigned long ip) 39 + { 40 + da_handle_start_event_snep(schedule_exit_snep); 41 + } 42 + 43 + static int enable_snep(void) 44 + { 45 + int retval; 46 + 47 + retval = da_monitor_init_snep(); 48 + if (retval) 49 + return retval; 50 + 51 + rv_attach_trace_probe("snep", preempt_disable, handle_preempt_disable); 52 + rv_attach_trace_probe("snep", preempt_enable, handle_preempt_enable); 53 + rv_attach_trace_probe("snep", sched_entry_tp, handle_schedule_entry); 54 + rv_attach_trace_probe("snep", sched_exit_tp, handle_schedule_exit); 55 + 56 + return 0; 57 + } 58 + 59 + static void disable_snep(void) 60 + { 61 + rv_snep.enabled = 0; 62 + 63 + rv_detach_trace_probe("snep", preempt_disable, handle_preempt_disable); 64 + rv_detach_trace_probe("snep", preempt_enable, handle_preempt_enable); 65 + rv_detach_trace_probe("snep", sched_entry_tp, handle_schedule_entry); 66 + rv_detach_trace_probe("snep", sched_exit_tp, handle_schedule_exit); 67 + 68 + da_monitor_destroy_snep(); 69 + } 70 + 71 + static struct rv_monitor rv_snep = { 72 + .name = "snep", 73 + .description = "schedule does not enable preempt.", 74 + .enable = enable_snep, 75 + .disable = disable_snep, 76 + .reset = da_monitor_reset_all_snep, 77 + .enabled = 0, 78 + }; 79 + 80 + static int __init register_snep(void) 81 + { 82 + rv_register_monitor(&rv_snep, &rv_sched); 83 + return 0; 84 + } 85 + 86 + static void __exit unregister_snep(void) 87 + { 88 + rv_unregister_monitor(&rv_snep); 89 + } 90 + 91 + module_init(register_snep); 92 + module_exit(unregister_snep); 93 + 94 + MODULE_LICENSE("GPL"); 95 + MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>"); 96 + MODULE_DESCRIPTION("snep: schedule does not enable preempt.");
+49
kernel/trace/rv/monitors/snep/snep.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Automatically generated C representation of snep automaton 4 + * For further information about this format, see kernel documentation: 5 + * Documentation/trace/rv/deterministic_automata.rst 6 + */ 7 + 8 + enum states_snep { 9 + non_scheduling_context_snep = 0, 10 + scheduling_contex_snep, 11 + state_max_snep 12 + }; 13 + 14 + #define INVALID_STATE state_max_snep 15 + 16 + enum events_snep { 17 + preempt_disable_snep = 0, 18 + preempt_enable_snep, 19 + schedule_entry_snep, 20 + schedule_exit_snep, 21 + event_max_snep 22 + }; 23 + 24 + struct automaton_snep { 25 + char *state_names[state_max_snep]; 26 + char *event_names[event_max_snep]; 27 + unsigned char function[state_max_snep][event_max_snep]; 28 + unsigned char initial_state; 29 + bool final_states[state_max_snep]; 30 + }; 31 + 32 + static const struct automaton_snep automaton_snep = { 33 + .state_names = { 34 + "non_scheduling_context", 35 + "scheduling_contex" 36 + }, 37 + .event_names = { 38 + "preempt_disable", 39 + "preempt_enable", 40 + "schedule_entry", 41 + "schedule_exit" 42 + }, 43 + .function = { 44 + { non_scheduling_context_snep, non_scheduling_context_snep, scheduling_contex_snep, INVALID_STATE }, 45 + { INVALID_STATE, INVALID_STATE, INVALID_STATE, non_scheduling_context_snep }, 46 + }, 47 + .initial_state = non_scheduling_context_snep, 48 + .final_states = { 1, 0 }, 49 + };
+15
kernel/trace/rv/monitors/snep/snep_trace.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + /* 4 + * Snippet to be included in rv_trace.h 5 + */ 6 + 7 + #ifdef CONFIG_RV_MON_SNEP 8 + DEFINE_EVENT(event_da_monitor, event_snep, 9 + TP_PROTO(char *state, char *event, char *next_state, bool final_state), 10 + TP_ARGS(state, event, next_state, final_state)); 11 + 12 + DEFINE_EVENT(error_da_monitor, error_snep, 13 + TP_PROTO(char *state, char *event), 14 + TP_ARGS(state, event)); 15 + #endif /* CONFIG_RV_MON_SNEP */
+14
kernel/trace/rv/monitors/snroc/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 3 + config RV_MON_SNROC 4 + depends on RV 5 + depends on RV_MON_SCHED 6 + default y 7 + select DA_MON_EVENTS_ID 8 + bool "snroc monitor" 9 + help 10 + Monitor to ensure sched_set_state happens only in the respective task's context. 11 + This monitor is part of the sched monitors collection. 12 + 13 + For further information, see: 14 + Documentation/trace/rv/monitor_sched.rst
+85
kernel/trace/rv/monitors/snroc/snroc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/ftrace.h> 3 + #include <linux/tracepoint.h> 4 + #include <linux/kernel.h> 5 + #include <linux/module.h> 6 + #include <linux/init.h> 7 + #include <linux/rv.h> 8 + #include <rv/instrumentation.h> 9 + #include <rv/da_monitor.h> 10 + 11 + #define MODULE_NAME "snroc" 12 + 13 + #include <trace/events/sched.h> 14 + #include <rv_trace.h> 15 + #include <monitors/sched/sched.h> 16 + 17 + #include "snroc.h" 18 + 19 + static struct rv_monitor rv_snroc; 20 + DECLARE_DA_MON_PER_TASK(snroc, unsigned char); 21 + 22 + static void handle_sched_set_state(void *data, struct task_struct *tsk, int state) 23 + { 24 + da_handle_event_snroc(tsk, sched_set_state_snroc); 25 + } 26 + 27 + static void handle_sched_switch(void *data, bool preempt, 28 + struct task_struct *prev, 29 + struct task_struct *next, 30 + unsigned int prev_state) 31 + { 32 + da_handle_start_event_snroc(prev, sched_switch_out_snroc); 33 + da_handle_event_snroc(next, sched_switch_in_snroc); 34 + } 35 + 36 + static int enable_snroc(void) 37 + { 38 + int retval; 39 + 40 + retval = da_monitor_init_snroc(); 41 + if (retval) 42 + return retval; 43 + 44 + rv_attach_trace_probe("snroc", sched_set_state_tp, handle_sched_set_state); 45 + rv_attach_trace_probe("snroc", sched_switch, handle_sched_switch); 46 + 47 + return 0; 48 + } 49 + 50 + static void disable_snroc(void) 51 + { 52 + rv_snroc.enabled = 0; 53 + 54 + rv_detach_trace_probe("snroc", sched_set_state_tp, handle_sched_set_state); 55 + rv_detach_trace_probe("snroc", sched_switch, handle_sched_switch); 56 + 57 + da_monitor_destroy_snroc(); 58 + } 59 + 60 + static struct rv_monitor rv_snroc = { 61 + .name = "snroc", 62 + .description = "set non runnable on its own context.", 63 + .enable = enable_snroc, 64 + .disable = disable_snroc, 65 + .reset = da_monitor_reset_all_snroc, 66 + .enabled = 0, 67 + }; 68 + 69 + static int __init register_snroc(void) 70 + { 71 + rv_register_monitor(&rv_snroc, &rv_sched); 72 + return 0; 73 + } 74 + 75 + static void __exit unregister_snroc(void) 76 + { 77 + rv_unregister_monitor(&rv_snroc); 78 + } 79 + 80 + module_init(register_snroc); 81 + module_exit(unregister_snroc); 82 + 83 + MODULE_LICENSE("GPL"); 84 + MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>"); 85 + MODULE_DESCRIPTION("snroc: set non runnable on its own context.");
+47
kernel/trace/rv/monitors/snroc/snroc.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Automatically generated C representation of snroc automaton 4 + * For further information about this format, see kernel documentation: 5 + * Documentation/trace/rv/deterministic_automata.rst 6 + */ 7 + 8 + enum states_snroc { 9 + other_context_snroc = 0, 10 + own_context_snroc, 11 + state_max_snroc 12 + }; 13 + 14 + #define INVALID_STATE state_max_snroc 15 + 16 + enum events_snroc { 17 + sched_set_state_snroc = 0, 18 + sched_switch_in_snroc, 19 + sched_switch_out_snroc, 20 + event_max_snroc 21 + }; 22 + 23 + struct automaton_snroc { 24 + char *state_names[state_max_snroc]; 25 + char *event_names[event_max_snroc]; 26 + unsigned char function[state_max_snroc][event_max_snroc]; 27 + unsigned char initial_state; 28 + bool final_states[state_max_snroc]; 29 + }; 30 + 31 + static const struct automaton_snroc automaton_snroc = { 32 + .state_names = { 33 + "other_context", 34 + "own_context" 35 + }, 36 + .event_names = { 37 + "sched_set_state", 38 + "sched_switch_in", 39 + "sched_switch_out" 40 + }, 41 + .function = { 42 + { INVALID_STATE, own_context_snroc, INVALID_STATE }, 43 + { own_context_snroc, INVALID_STATE, other_context_snroc }, 44 + }, 45 + .initial_state = other_context_snroc, 46 + .final_states = { 1, 0 }, 47 + };
+15
kernel/trace/rv/monitors/snroc/snroc_trace.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + /* 4 + * Snippet to be included in rv_trace.h 5 + */ 6 + 7 + #ifdef CONFIG_RV_MON_SNROC 8 + DEFINE_EVENT(event_da_monitor_id, event_snroc, 9 + TP_PROTO(int id, char *state, char *event, char *next_state, bool final_state), 10 + TP_ARGS(id, state, event, next_state, final_state)); 11 + 12 + DEFINE_EVENT(error_da_monitor_id, error_snroc, 13 + TP_PROTO(int id, char *state, char *event), 14 + TP_ARGS(id, state, event)); 15 + #endif /* CONFIG_RV_MON_SNROC */
+14
kernel/trace/rv/monitors/tss/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 3 + config RV_MON_TSS 4 + depends on RV 5 + depends on RV_MON_SCHED 6 + default y 7 + select DA_MON_EVENTS_IMPLICIT 8 + bool "tss monitor" 9 + help 10 + Monitor to ensure sched_switch happens only in scheduling context. 11 + This monitor is part of the sched monitors collection. 12 + 13 + For further information, see: 14 + Documentation/trace/rv/monitor_sched.rst
+91
kernel/trace/rv/monitors/tss/tss.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/ftrace.h> 3 + #include <linux/tracepoint.h> 4 + #include <linux/kernel.h> 5 + #include <linux/module.h> 6 + #include <linux/init.h> 7 + #include <linux/rv.h> 8 + #include <rv/instrumentation.h> 9 + #include <rv/da_monitor.h> 10 + 11 + #define MODULE_NAME "tss" 12 + 13 + #include <trace/events/sched.h> 14 + #include <rv_trace.h> 15 + #include <monitors/sched/sched.h> 16 + 17 + #include "tss.h" 18 + 19 + static struct rv_monitor rv_tss; 20 + DECLARE_DA_MON_PER_CPU(tss, unsigned char); 21 + 22 + static void handle_sched_switch(void *data, bool preempt, 23 + struct task_struct *prev, 24 + struct task_struct *next, 25 + unsigned int prev_state) 26 + { 27 + da_handle_event_tss(sched_switch_tss); 28 + } 29 + 30 + static void handle_schedule_entry(void *data, bool preempt, unsigned long ip) 31 + { 32 + da_handle_event_tss(schedule_entry_tss); 33 + } 34 + 35 + static void handle_schedule_exit(void *data, bool is_switch, unsigned long ip) 36 + { 37 + da_handle_start_event_tss(schedule_exit_tss); 38 + } 39 + 40 + static int enable_tss(void) 41 + { 42 + int retval; 43 + 44 + retval = da_monitor_init_tss(); 45 + if (retval) 46 + return retval; 47 + 48 + rv_attach_trace_probe("tss", sched_switch, handle_sched_switch); 49 + rv_attach_trace_probe("tss", sched_entry_tp, handle_schedule_entry); 50 + rv_attach_trace_probe("tss", sched_exit_tp, handle_schedule_exit); 51 + 52 + return 0; 53 + } 54 + 55 + static void disable_tss(void) 56 + { 57 + rv_tss.enabled = 0; 58 + 59 + rv_detach_trace_probe("tss", sched_switch, handle_sched_switch); 60 + rv_detach_trace_probe("tss", sched_entry_tp, handle_schedule_entry); 61 + rv_detach_trace_probe("tss", sched_exit_tp, handle_schedule_exit); 62 + 63 + da_monitor_destroy_tss(); 64 + } 65 + 66 + static struct rv_monitor rv_tss = { 67 + .name = "tss", 68 + .description = "task switch while scheduling.", 69 + .enable = enable_tss, 70 + .disable = disable_tss, 71 + .reset = da_monitor_reset_all_tss, 72 + .enabled = 0, 73 + }; 74 + 75 + static int __init register_tss(void) 76 + { 77 + rv_register_monitor(&rv_tss, &rv_sched); 78 + return 0; 79 + } 80 + 81 + static void __exit unregister_tss(void) 82 + { 83 + rv_unregister_monitor(&rv_tss); 84 + } 85 + 86 + module_init(register_tss); 87 + module_exit(unregister_tss); 88 + 89 + MODULE_LICENSE("GPL"); 90 + MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>"); 91 + MODULE_DESCRIPTION("tss: task switch while scheduling.");
+47
kernel/trace/rv/monitors/tss/tss.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Automatically generated C representation of tss automaton 4 + * For further information about this format, see kernel documentation: 5 + * Documentation/trace/rv/deterministic_automata.rst 6 + */ 7 + 8 + enum states_tss { 9 + thread_tss = 0, 10 + sched_tss, 11 + state_max_tss 12 + }; 13 + 14 + #define INVALID_STATE state_max_tss 15 + 16 + enum events_tss { 17 + sched_switch_tss = 0, 18 + schedule_entry_tss, 19 + schedule_exit_tss, 20 + event_max_tss 21 + }; 22 + 23 + struct automaton_tss { 24 + char *state_names[state_max_tss]; 25 + char *event_names[event_max_tss]; 26 + unsigned char function[state_max_tss][event_max_tss]; 27 + unsigned char initial_state; 28 + bool final_states[state_max_tss]; 29 + }; 30 + 31 + static const struct automaton_tss automaton_tss = { 32 + .state_names = { 33 + "thread", 34 + "sched" 35 + }, 36 + .event_names = { 37 + "sched_switch", 38 + "schedule_entry", 39 + "schedule_exit" 40 + }, 41 + .function = { 42 + { INVALID_STATE, sched_tss, INVALID_STATE }, 43 + { sched_tss, INVALID_STATE, thread_tss }, 44 + }, 45 + .initial_state = thread_tss, 46 + .final_states = { 1, 0 }, 47 + };
+15
kernel/trace/rv/monitors/tss/tss_trace.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + /* 4 + * Snippet to be included in rv_trace.h 5 + */ 6 + 7 + #ifdef CONFIG_RV_MON_TSS 8 + DEFINE_EVENT(event_da_monitor, event_tss, 9 + TP_PROTO(char *state, char *event, char *next_state, bool final_state), 10 + TP_ARGS(state, event, next_state, final_state)); 11 + 12 + DEFINE_EVENT(error_da_monitor, error_tss, 13 + TP_PROTO(char *state, char *event), 14 + TP_ARGS(state, event)); 15 + #endif /* CONFIG_RV_MON_TSS */
+2
kernel/trace/rv/monitors/wip/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 1 3 config RV_MON_WIP 2 4 depends on RV 3 5 depends on PREEMPT_TRACER
+1 -1
kernel/trace/rv/monitors/wip/wip.c
··· 71 71 72 72 static int __init register_wip(void) 73 73 { 74 - rv_register_monitor(&rv_wip); 74 + rv_register_monitor(&rv_wip, NULL); 75 75 return 0; 76 76 } 77 77
+1
kernel/trace/rv/monitors/wip/wip.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 1 2 /* 2 3 * Automatically generated C representation of wip automaton 3 4 * For further information about this format, see kernel documentation:
+2
kernel/trace/rv/monitors/wwnr/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 1 3 config RV_MON_WWNR 2 4 depends on RV 3 5 select DA_MON_EVENTS_ID
+1 -1
kernel/trace/rv/monitors/wwnr/wwnr.c
··· 70 70 71 71 static int __init register_wwnr(void) 72 72 { 73 - rv_register_monitor(&rv_wwnr); 73 + rv_register_monitor(&rv_wwnr, NULL); 74 74 return 0; 75 75 } 76 76
+1
kernel/trace/rv/monitors/wwnr/wwnr.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 1 2 /* 2 3 * Automatically generated C representation of wwnr automaton 3 4 * For further information about this format, see kernel documentation:
+131 -23
kernel/trace/rv/rv.c
··· 162 162 /* 163 163 * Interface for the monitor register. 164 164 */ 165 - static LIST_HEAD(rv_monitors_list); 165 + LIST_HEAD(rv_monitors_list); 166 166 167 167 static int task_monitor_count; 168 168 static bool task_monitor_slots[RV_PER_TASK_MONITORS]; ··· 207 207 } 208 208 209 209 /* 210 + * Monitors with a parent are nested, 211 + * Monitors without a parent could be standalone or containers. 212 + */ 213 + bool rv_is_nested_monitor(struct rv_monitor_def *mdef) 214 + { 215 + return mdef->parent != NULL; 216 + } 217 + 218 + /* 219 + * We set our list to have nested monitors listed after their parent 220 + * if a monitor has a child element its a container. 221 + * Containers can be also identified based on their function pointers: 222 + * as they are not real monitors they do not need function definitions 223 + * for enable()/disable(). Use this condition to find empty containers. 224 + * Keep both conditions in case we have some non-compliant containers. 225 + */ 226 + bool rv_is_container_monitor(struct rv_monitor_def *mdef) 227 + { 228 + struct rv_monitor_def *next = list_next_entry(mdef, list); 229 + 230 + return next->parent == mdef->monitor || !mdef->monitor->enable; 231 + } 232 + 233 + /* 210 234 * This section collects the monitor/ files and folders. 211 235 */ 212 236 static ssize_t monitor_enable_read_data(struct file *filp, char __user *user_buf, size_t count, ··· 253 229 254 230 if (mdef->monitor->enabled) { 255 231 mdef->monitor->enabled = 0; 256 - mdef->monitor->disable(); 232 + if (mdef->monitor->disable) 233 + mdef->monitor->disable(); 257 234 258 235 /* 259 236 * Wait for the execution of all events to finish. ··· 268 243 return 0; 269 244 } 270 245 246 + static void rv_disable_single(struct rv_monitor_def *mdef) 247 + { 248 + __rv_disable_monitor(mdef, true); 249 + } 250 + 251 + static int rv_enable_single(struct rv_monitor_def *mdef) 252 + { 253 + int retval; 254 + 255 + lockdep_assert_held(&rv_interface_lock); 256 + 257 + if (mdef->monitor->enabled) 258 + return 0; 259 + 260 + retval = mdef->monitor->enable(); 261 + 262 + if (!retval) 263 + mdef->monitor->enabled = 1; 264 + 265 + return retval; 266 + } 267 + 268 + static void rv_disable_container(struct rv_monitor_def *mdef) 269 + { 270 + struct rv_monitor_def *p = mdef; 271 + int enabled = 0; 272 + 273 + list_for_each_entry_continue(p, &rv_monitors_list, list) { 274 + if (p->parent != mdef->monitor) 275 + break; 276 + enabled += __rv_disable_monitor(p, false); 277 + } 278 + if (enabled) 279 + tracepoint_synchronize_unregister(); 280 + mdef->monitor->enabled = 0; 281 + } 282 + 283 + static int rv_enable_container(struct rv_monitor_def *mdef) 284 + { 285 + struct rv_monitor_def *p = mdef; 286 + int retval = 0; 287 + 288 + list_for_each_entry_continue(p, &rv_monitors_list, list) { 289 + if (retval || p->parent != mdef->monitor) 290 + break; 291 + retval = rv_enable_single(p); 292 + } 293 + if (retval) 294 + rv_disable_container(mdef); 295 + else 296 + mdef->monitor->enabled = 1; 297 + return retval; 298 + } 299 + 271 300 /** 272 301 * rv_disable_monitor - disable a given runtime monitor 273 302 * @mdef: Pointer to the monitor definition structure. ··· 330 251 */ 331 252 int rv_disable_monitor(struct rv_monitor_def *mdef) 332 253 { 333 - __rv_disable_monitor(mdef, true); 254 + if (rv_is_container_monitor(mdef)) 255 + rv_disable_container(mdef); 256 + else 257 + rv_disable_single(mdef); 258 + 334 259 return 0; 335 260 } 336 261 ··· 348 265 { 349 266 int retval; 350 267 351 - lockdep_assert_held(&rv_interface_lock); 352 - 353 - if (mdef->monitor->enabled) 354 - return 0; 355 - 356 - retval = mdef->monitor->enable(); 357 - 358 - if (!retval) 359 - mdef->monitor->enabled = 1; 268 + if (rv_is_container_monitor(mdef)) 269 + retval = rv_enable_container(mdef); 270 + else 271 + retval = rv_enable_single(mdef); 360 272 361 273 return retval; 362 274 } ··· 414 336 * the monitor dir, where the specific options of the monitor 415 337 * are exposed. 416 338 */ 417 - static int create_monitor_dir(struct rv_monitor_def *mdef) 339 + static int create_monitor_dir(struct rv_monitor_def *mdef, struct rv_monitor_def *parent) 418 340 { 419 - struct dentry *root = get_monitors_root(); 341 + struct dentry *root = parent ? parent->root_d : get_monitors_root(); 420 342 const char *name = mdef->monitor->name; 421 343 struct dentry *tmp; 422 344 int retval; ··· 455 377 { 456 378 struct rv_monitor_def *mon_def = p; 457 379 458 - seq_printf(m, "%s\n", mon_def->monitor->name); 380 + if (mon_def->parent) 381 + seq_printf(m, "%s:%s\n", mon_def->parent->name, 382 + mon_def->monitor->name); 383 + else 384 + seq_printf(m, "%s\n", mon_def->monitor->name); 459 385 return 0; 460 386 } 461 387 ··· 596 514 struct rv_monitor_def *mdef; 597 515 int retval = -EINVAL; 598 516 bool enable = true; 599 - char *ptr; 517 + char *ptr, *tmp; 600 518 int len; 601 519 602 520 if (count < 1 || count > MAX_RV_MONITOR_NAME_SIZE + 1) ··· 622 540 mutex_lock(&rv_interface_lock); 623 541 624 542 retval = -EINVAL; 543 + 544 + /* we support 1 nesting level, trim the parent */ 545 + tmp = strstr(ptr, ":"); 546 + if (tmp) 547 + ptr = tmp+1; 625 548 626 549 list_for_each_entry(mdef, &rv_monitors_list, list) { 627 550 if (strcmp(ptr, mdef->monitor->name) != 0) ··· 700 613 struct rv_monitor_def *mdef; 701 614 702 615 list_for_each_entry(mdef, &rv_monitors_list, list) { 703 - if (mdef->monitor->enabled) 616 + if (mdef->monitor->enabled && mdef->monitor->reset) 704 617 mdef->monitor->reset(); 705 618 } 706 619 } ··· 772 685 /** 773 686 * rv_register_monitor - register a rv monitor. 774 687 * @monitor: The rv_monitor to be registered. 688 + * @parent: The parent of the monitor to be registered, NULL if not nested. 775 689 * 776 690 * Returns 0 if successful, error otherwise. 777 691 */ 778 - int rv_register_monitor(struct rv_monitor *monitor) 692 + int rv_register_monitor(struct rv_monitor *monitor, struct rv_monitor *parent) 779 693 { 780 - struct rv_monitor_def *r; 694 + struct rv_monitor_def *r, *p = NULL; 781 695 int retval = 0; 782 696 783 697 if (strlen(monitor->name) >= MAX_RV_MONITOR_NAME_SIZE) { 784 698 pr_info("Monitor %s has a name longer than %d\n", monitor->name, 785 699 MAX_RV_MONITOR_NAME_SIZE); 786 - return -1; 700 + return -EINVAL; 787 701 } 788 702 789 703 mutex_lock(&rv_interface_lock); ··· 792 704 list_for_each_entry(r, &rv_monitors_list, list) { 793 705 if (strcmp(monitor->name, r->monitor->name) == 0) { 794 706 pr_info("Monitor %s is already registered\n", monitor->name); 795 - retval = -1; 707 + retval = -EEXIST; 796 708 goto out_unlock; 797 709 } 710 + } 711 + 712 + if (parent) { 713 + list_for_each_entry(r, &rv_monitors_list, list) { 714 + if (strcmp(parent->name, r->monitor->name) == 0) { 715 + p = r; 716 + break; 717 + } 718 + } 719 + } 720 + 721 + if (p && rv_is_nested_monitor(p)) { 722 + pr_info("Parent monitor %s is already nested, cannot nest further\n", 723 + parent->name); 724 + return -EINVAL; 798 725 } 799 726 800 727 r = kzalloc(sizeof(struct rv_monitor_def), GFP_KERNEL); ··· 819 716 } 820 717 821 718 r->monitor = monitor; 719 + r->parent = parent; 822 720 823 - retval = create_monitor_dir(r); 721 + retval = create_monitor_dir(r, p); 824 722 if (retval) { 825 723 kfree(r); 826 724 goto out_unlock; 827 725 } 828 726 829 - list_add_tail(&r->list, &rv_monitors_list); 727 + /* keep children close to the parent for easier visualisation */ 728 + if (p) 729 + list_add(&r->list, &p->list); 730 + else 731 + list_add_tail(&r->list, &rv_monitors_list); 830 732 831 733 out_unlock: 832 734 mutex_unlock(&rv_interface_lock);
+4
kernel/trace/rv/rv.h
··· 21 21 #define MAX_RV_REACTOR_NAME_SIZE 32 22 22 23 23 extern struct mutex rv_interface_lock; 24 + extern struct list_head rv_monitors_list; 24 25 25 26 #ifdef CONFIG_RV_REACTORS 26 27 struct rv_reactor_def { ··· 35 34 struct rv_monitor_def { 36 35 struct list_head list; 37 36 struct rv_monitor *monitor; 37 + struct rv_monitor *parent; 38 38 struct dentry *root_d; 39 39 #ifdef CONFIG_RV_REACTORS 40 40 struct rv_reactor_def *rdef; ··· 47 45 struct dentry *get_monitors_root(void); 48 46 int rv_disable_monitor(struct rv_monitor_def *mdef); 49 47 int rv_enable_monitor(struct rv_monitor_def *mdef); 48 + bool rv_is_container_monitor(struct rv_monitor_def *mdef); 49 + bool rv_is_nested_monitor(struct rv_monitor_def *mdef); 50 50 51 51 #ifdef CONFIG_RV_REACTORS 52 52 int reactor_populate_monitor(struct rv_monitor_def *mdef);
+25 -3
kernel/trace/rv/rv_reactors.c
··· 158 158 .show = monitor_reactor_show 159 159 }; 160 160 161 - static void monitor_swap_reactors(struct rv_monitor_def *mdef, struct rv_reactor_def *rdef, 162 - bool reacting) 161 + static void monitor_swap_reactors_single(struct rv_monitor_def *mdef, 162 + struct rv_reactor_def *rdef, 163 + bool reacting, bool nested) 163 164 { 164 165 bool monitor_enabled; 165 166 ··· 180 179 mdef->reacting = reacting; 181 180 mdef->monitor->react = rdef->reactor->react; 182 181 183 - if (monitor_enabled) 182 + /* enable only once if iterating through a container */ 183 + if (monitor_enabled && !nested) 184 184 rv_enable_monitor(mdef); 185 + } 186 + 187 + static void monitor_swap_reactors(struct rv_monitor_def *mdef, 188 + struct rv_reactor_def *rdef, bool reacting) 189 + { 190 + struct rv_monitor_def *p = mdef; 191 + 192 + if (rv_is_container_monitor(mdef)) 193 + list_for_each_entry_continue(p, &rv_monitors_list, list) { 194 + if (p->parent != mdef->monitor) 195 + break; 196 + monitor_swap_reactors_single(p, rdef, reacting, true); 197 + } 198 + /* 199 + * This call enables and disables the monitor if they were active. 200 + * In case of a container, we already disabled all and will enable all. 201 + * All nested monitors are enabled also if they were off, we may refine 202 + * this logic in the future. 203 + */ 204 + monitor_swap_reactors_single(mdef, rdef, reacting, false); 185 205 } 186 206 187 207 static ssize_t
+6
kernel/trace/rv/rv_trace.h
··· 58 58 ); 59 59 60 60 #include <monitors/wip/wip_trace.h> 61 + #include <monitors/tss/tss_trace.h> 62 + #include <monitors/sco/sco_trace.h> 63 + #include <monitors/scpd/scpd_trace.h> 64 + #include <monitors/snep/snep_trace.h> 65 + #include <monitors/sncid/sncid_trace.h> 61 66 // Add new monitors based on CONFIG_DA_MON_EVENTS_IMPLICIT here 62 67 63 68 #endif /* CONFIG_DA_MON_EVENTS_IMPLICIT */ ··· 123 118 ); 124 119 125 120 #include <monitors/wwnr/wwnr_trace.h> 121 + #include <monitors/snroc/snroc_trace.h> 126 122 // Add new monitors based on CONFIG_DA_MON_EVENTS_ID here 127 123 128 124 #endif /* CONFIG_DA_MON_EVENTS_ID */
+16 -39
kernel/trace/trace_osnoise.c
··· 316 316 bool trace_osnoise_callback_enabled; 317 317 318 318 /* 319 - * osnoise sample structure definition. Used to store the statistics of a 320 - * sample run. 321 - */ 322 - struct osnoise_sample { 323 - u64 runtime; /* runtime */ 324 - u64 noise; /* noise */ 325 - u64 max_sample; /* max single noise sample */ 326 - int hw_count; /* # HW (incl. hypervisor) interference */ 327 - int nmi_count; /* # NMIs during this sample */ 328 - int irq_count; /* # IRQs during this sample */ 329 - int softirq_count; /* # softirqs during this sample */ 330 - int thread_count; /* # threads during this sample */ 331 - }; 332 - 333 - #ifdef CONFIG_TIMERLAT_TRACER 334 - /* 335 - * timerlat sample structure definition. Used to store the statistics of 336 - * a sample run. 337 - */ 338 - struct timerlat_sample { 339 - u64 timer_latency; /* timer_latency */ 340 - unsigned int seqnum; /* unique sequence */ 341 - int context; /* timer context */ 342 - }; 343 - #endif 344 - 345 - /* 346 319 * Tracer data. 347 320 */ 348 321 static struct osnoise_data { ··· 470 497 * Record an osnoise_sample into the tracer buffer. 471 498 */ 472 499 static void 473 - __trace_osnoise_sample(struct osnoise_sample *sample, struct trace_buffer *buffer) 500 + __record_osnoise_sample(struct osnoise_sample *sample, struct trace_buffer *buffer) 474 501 { 475 502 struct ring_buffer_event *event; 476 503 struct osnoise_entry *entry; ··· 493 520 } 494 521 495 522 /* 496 - * Record an osnoise_sample on all osnoise instances. 523 + * Record an osnoise_sample on all osnoise instances and fire trace event. 497 524 */ 498 - static void trace_osnoise_sample(struct osnoise_sample *sample) 525 + static void record_osnoise_sample(struct osnoise_sample *sample) 499 526 { 500 527 struct osnoise_instance *inst; 501 528 struct trace_buffer *buffer; 502 529 530 + trace_osnoise_sample(sample); 531 + 503 532 rcu_read_lock(); 504 533 list_for_each_entry_rcu(inst, &osnoise_instances, list) { 505 534 buffer = inst->tr->array_buffer.buffer; 506 - __trace_osnoise_sample(sample, buffer); 535 + __record_osnoise_sample(sample, buffer); 507 536 } 508 537 rcu_read_unlock(); 509 538 } ··· 549 574 #endif /* CONFIG_PREEMPT_RT */ 550 575 551 576 static void 552 - __trace_timerlat_sample(struct timerlat_sample *sample, struct trace_buffer *buffer) 577 + __record_timerlat_sample(struct timerlat_sample *sample, struct trace_buffer *buffer) 553 578 { 554 579 struct ring_buffer_event *event; 555 580 struct timerlat_entry *entry; ··· 569 594 /* 570 595 * Record an timerlat_sample into the tracer buffer. 571 596 */ 572 - static void trace_timerlat_sample(struct timerlat_sample *sample) 597 + static void record_timerlat_sample(struct timerlat_sample *sample) 573 598 { 574 599 struct osnoise_instance *inst; 575 600 struct trace_buffer *buffer; 576 601 602 + trace_timerlat_sample(sample); 603 + 577 604 rcu_read_lock(); 578 605 list_for_each_entry_rcu(inst, &osnoise_instances, list) { 579 606 buffer = inst->tr->array_buffer.buffer; 580 - __trace_timerlat_sample(sample, buffer); 607 + __record_timerlat_sample(sample, buffer); 581 608 } 582 609 rcu_read_unlock(); 583 610 } ··· 1583 1606 /* Save interference stats info */ 1584 1607 diff_osn_sample_stats(osn_var, &s); 1585 1608 1586 - trace_osnoise_sample(&s); 1609 + record_osnoise_sample(&s); 1587 1610 1588 1611 notify_new_max_latency(max_noise); 1589 1612 ··· 1778 1801 s.timer_latency = diff; 1779 1802 s.context = IRQ_CONTEXT; 1780 1803 1781 - trace_timerlat_sample(&s); 1804 + record_timerlat_sample(&s); 1782 1805 1783 1806 if (osnoise_data.stop_tracing) { 1784 1807 if (time_to_us(diff) >= osnoise_data.stop_tracing) { ··· 1897 1920 s.timer_latency = diff; 1898 1921 s.context = THREAD_CONTEXT; 1899 1922 1900 - trace_timerlat_sample(&s); 1923 + record_timerlat_sample(&s); 1901 1924 1902 1925 notify_new_max_latency(diff); 1903 1926 ··· 2502 2525 s.timer_latency = diff; 2503 2526 s.context = THREAD_URET; 2504 2527 2505 - trace_timerlat_sample(&s); 2528 + record_timerlat_sample(&s); 2506 2529 2507 2530 notify_new_max_latency(diff); 2508 2531 ··· 2537 2560 s.timer_latency = diff; 2538 2561 s.context = THREAD_CONTEXT; 2539 2562 2540 - trace_timerlat_sample(&s); 2563 + record_timerlat_sample(&s); 2541 2564 2542 2565 if (osnoise_data.stop_tracing_total) { 2543 2566 if (time_to_us(diff) >= osnoise_data.stop_tracing_total) {
+18 -9
tools/verification/dot2/dot2k
··· 11 11 if __name__ == '__main__': 12 12 from dot2.dot2k import dot2k 13 13 import argparse 14 - import ntpath 15 - import os 16 - import platform 17 14 import sys 18 15 16 + def is_container(): 17 + """Should work even before parsing the arguments""" 18 + return "-c" in sys.argv or "--container" in sys.argv 19 + 19 20 parser = argparse.ArgumentParser(description='transform .dot file into kernel rv monitor') 20 - parser.add_argument('-d', "--dot", dest="dot_file", required=True) 21 - parser.add_argument('-t', "--monitor_type", dest="monitor_type", required=True) 22 - parser.add_argument('-n', "--model_name", dest="model_name", required=False) 21 + parser.add_argument('-d', "--dot", dest="dot_file", required=not is_container()) 22 + parser.add_argument('-t', "--monitor_type", dest="monitor_type", required=not is_container(), 23 + help=f"Available options: {', '.join(dot2k.monitor_types.keys())}") 24 + parser.add_argument('-n', "--model_name", dest="model_name", required=is_container()) 23 25 parser.add_argument("-D", "--description", dest="description", required=False) 24 26 parser.add_argument("-a", "--auto_patch", dest="auto_patch", 25 27 action="store_true", required=False, 26 28 help="Patch the kernel in place") 29 + parser.add_argument("-p", "--parent", dest="parent", 30 + required=False, help="Create a monitor nested to parent") 31 + parser.add_argument("-c", "--container", dest="container", 32 + action="store_true", required=False, 33 + help="Create an empty monitor to be used as a container") 27 34 params = parser.parse_args() 28 35 29 - print("Opening and parsing the dot file %s" % params.dot_file) 36 + if not is_container(): 37 + print("Opening and parsing the dot file %s" % params.dot_file) 30 38 try: 31 39 monitor=dot2k(params.dot_file, params.monitor_type, vars(params)) 32 40 except Exception as e: ··· 45 37 print("Writing the monitor into the directory %s" % monitor.name) 46 38 monitor.print_files() 47 39 print("Almost done, checklist") 48 - print(" - Edit the %s/%s.c to add the instrumentation" % (monitor.name, monitor.name)) 49 - print(monitor.fill_tracepoint_tooltip()) 40 + if not is_container(): 41 + print(" - Edit the %s/%s.c to add the instrumentation" % (monitor.name, monitor.name)) 42 + print(monitor.fill_tracepoint_tooltip()) 50 43 print(monitor.fill_makefile_tooltip()) 51 44 print(monitor.fill_kconfig_tooltip()) 52 45 print(monitor.fill_monitor_tooltip())
+63 -15
tools/verification/dot2/dot2k.py
··· 19 19 monitor_type = "per_cpu" 20 20 21 21 def __init__(self, file_path, MonitorType, extra_params={}): 22 - super().__init__(file_path, extra_params.get("model_name")) 23 - 24 - self.monitor_type = self.monitor_types.get(MonitorType) 25 - if self.monitor_type is None: 26 - raise ValueError("Unknown monitor type: %s" % MonitorType) 27 - 28 - self.monitor_type = MonitorType 22 + self.container = extra_params.get("container") 23 + self.parent = extra_params.get("parent") 29 24 self.__fill_rv_templates_dir() 30 - self.main_c = self.__read_file(self.monitor_templates_dir + "main.c") 31 - self.trace_h = self.__read_file(self.monitor_templates_dir + "trace.h") 25 + 26 + if self.container: 27 + if file_path: 28 + raise ValueError("A container does not require a dot file") 29 + if MonitorType: 30 + raise ValueError("A container does not require a monitor type") 31 + if self.parent: 32 + raise ValueError("A container cannot have a parent") 33 + self.name = extra_params.get("model_name") 34 + self.events = [] 35 + self.states = [] 36 + self.main_c = self.__read_file(self.monitor_templates_dir + "main_container.c") 37 + self.main_h = self.__read_file(self.monitor_templates_dir + "main_container.h") 38 + else: 39 + super().__init__(file_path, extra_params.get("model_name")) 40 + 41 + self.monitor_type = self.monitor_types.get(MonitorType) 42 + if self.monitor_type is None: 43 + raise ValueError("Unknown monitor type: %s" % MonitorType) 44 + self.monitor_type = MonitorType 45 + self.main_c = self.__read_file(self.monitor_templates_dir + "main.c") 46 + self.trace_h = self.__read_file(self.monitor_templates_dir + "trace.h") 32 47 self.kconfig = self.__read_file(self.monitor_templates_dir + "Kconfig") 33 48 self.enum_suffix = "_%s" % self.name 34 49 self.description = extra_params.get("description", self.name) or "auto-generated" ··· 120 105 def fill_monitor_type(self): 121 106 return self.monitor_type.upper() 122 107 108 + def fill_parent(self): 109 + return "&rv_%s" % self.parent if self.parent else "NULL" 110 + 111 + def fill_include_parent(self): 112 + if self.parent: 113 + return "#include <monitors/%s/%s.h>\n" % (self.parent, self.parent) 114 + return "" 115 + 123 116 def fill_tracepoint_handlers_skel(self): 124 117 buff = [] 125 118 for event in self.events: ··· 169 146 tracepoint_handlers = self.fill_tracepoint_handlers_skel() 170 147 tracepoint_attach = self.fill_tracepoint_attach_probe() 171 148 tracepoint_detach = self.fill_tracepoint_detach_helper() 149 + parent = self.fill_parent() 150 + parent_include = self.fill_include_parent() 172 151 173 152 main_c = main_c.replace("%%MONITOR_TYPE%%", monitor_type) 174 153 main_c = main_c.replace("%%MIN_TYPE%%", min_type) ··· 180 155 main_c = main_c.replace("%%TRACEPOINT_ATTACH%%", tracepoint_attach) 181 156 main_c = main_c.replace("%%TRACEPOINT_DETACH%%", tracepoint_detach) 182 157 main_c = main_c.replace("%%DESCRIPTION%%", self.description) 158 + main_c = main_c.replace("%%PARENT%%", parent) 159 + main_c = main_c.replace("%%INCLUDE_PARENT%%", parent_include) 183 160 184 161 return main_c 185 162 186 163 def fill_model_h_header(self): 187 164 buff = [] 165 + buff.append("/* SPDX-License-Identifier: GPL-2.0 */") 188 166 buff.append("/*") 189 167 buff.append(" * Automatically generated C representation of %s automaton" % (self.name)) 190 168 buff.append(" * For further information about this format, see kernel documentation:") ··· 243 215 buff.append(" TP_ARGS(%s)" % tp_args_c) 244 216 return self.__buff_to_string(buff) 245 217 218 + def fill_monitor_deps(self): 219 + buff = [] 220 + buff.append(" # XXX: add dependencies if there") 221 + if self.parent: 222 + buff.append(" depends on RV_MON_%s" % self.parent.upper()) 223 + buff.append(" default y") 224 + return self.__buff_to_string(buff) 225 + 246 226 def fill_trace_h(self): 247 227 trace_h = self.trace_h 248 228 monitor_class = self.fill_monitor_class() ··· 268 232 def fill_kconfig(self): 269 233 kconfig = self.kconfig 270 234 monitor_class_type = self.fill_monitor_class_type() 235 + monitor_deps = self.fill_monitor_deps() 271 236 kconfig = kconfig.replace("%%MODEL_NAME%%", self.name) 272 237 kconfig = kconfig.replace("%%MODEL_NAME_UP%%", self.name.upper()) 273 238 kconfig = kconfig.replace("%%MONITOR_CLASS_TYPE%%", monitor_class_type) 274 239 kconfig = kconfig.replace("%%DESCRIPTION%%", self.description) 240 + kconfig = kconfig.replace("%%MONITOR_DEPS%%", monitor_deps) 275 241 return kconfig 242 + 243 + def fill_main_container_h(self): 244 + main_h = self.main_h 245 + main_h = main_h.replace("%%MODEL_NAME%%", self.name) 246 + return main_h 276 247 277 248 def __patch_file(self, file, marker, line): 278 249 file_to_patch = os.path.join(self.rv_dir, file) ··· 366 323 367 324 def print_files(self): 368 325 main_c = self.fill_main_c() 369 - model_h = self.fill_model_h() 370 326 371 327 self.__create_directory() 372 328 373 329 path = "%s.c" % self.name 374 330 self.__create_file(path, main_c) 375 331 376 - path = "%s.h" % self.name 377 - self.__create_file(path, model_h) 332 + if self.container: 333 + main_h = self.fill_main_container_h() 334 + path = "%s.h" % self.name 335 + self.__create_file(path, main_h) 336 + else: 337 + model_h = self.fill_model_h() 338 + path = "%s.h" % self.name 339 + self.__create_file(path, model_h) 378 340 379 - trace_h = self.fill_trace_h() 380 - path = "%s_trace.h" % self.name 381 - self.__create_file(path, trace_h) 341 + trace_h = self.fill_trace_h() 342 + path = "%s_trace.h" % self.name 343 + self.__create_file(path, trace_h) 382 344 383 345 kconfig = self.fill_kconfig() 384 346 self.__create_file("Kconfig", kconfig)
+3
tools/verification/dot2/dot2k_templates/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 1 3 config RV_MON_%%MODEL_NAME_UP%% 2 4 depends on RV 5 + %%MONITOR_DEPS%% 3 6 select %%MONITOR_CLASS_TYPE%% 4 7 bool "%%MODEL_NAME%% monitor" 5 8 help
+2 -2
tools/verification/dot2/dot2k_templates/main.c
··· 15 15 * #include <trace/events/sched.h> 16 16 */ 17 17 #include <rv_trace.h> 18 - 18 + %%INCLUDE_PARENT%% 19 19 /* 20 20 * This is the self-generated part of the monitor. Generally, there is no need 21 21 * to touch this section. ··· 74 74 75 75 static int __init register_%%MODEL_NAME%%(void) 76 76 { 77 - rv_register_monitor(&rv_%%MODEL_NAME%%); 77 + rv_register_monitor(&rv_%%MODEL_NAME%%, %%PARENT%%); 78 78 return 0; 79 79 } 80 80
+38
tools/verification/dot2/dot2k_templates/main_container.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/kernel.h> 3 + #include <linux/module.h> 4 + #include <linux/init.h> 5 + #include <linux/rv.h> 6 + 7 + #define MODULE_NAME "%%MODEL_NAME%%" 8 + 9 + #include "%%MODEL_NAME%%.h" 10 + 11 + struct rv_monitor rv_%%MODEL_NAME%%; 12 + 13 + struct rv_monitor rv_%%MODEL_NAME%% = { 14 + .name = "%%MODEL_NAME%%", 15 + .description = "%%DESCRIPTION%%", 16 + .enable = NULL, 17 + .disable = NULL, 18 + .reset = NULL, 19 + .enabled = 0, 20 + }; 21 + 22 + static int __init register_%%MODEL_NAME%%(void) 23 + { 24 + rv_register_monitor(&rv_%%MODEL_NAME%%, NULL); 25 + return 0; 26 + } 27 + 28 + static void __exit unregister_%%MODEL_NAME%%(void) 29 + { 30 + rv_unregister_monitor(&rv_%%MODEL_NAME%%); 31 + } 32 + 33 + module_init(register_%%MODEL_NAME%%); 34 + module_exit(unregister_%%MODEL_NAME%%); 35 + 36 + MODULE_LICENSE("GPL"); 37 + MODULE_AUTHOR("dot2k: auto-generated"); 38 + MODULE_DESCRIPTION("%%MODEL_NAME%%: %%DESCRIPTION%%");
+3
tools/verification/dot2/dot2k_templates/main_container.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + extern struct rv_monitor rv_%%MODEL_NAME%%;
+18
tools/verification/models/sched/sco.dot
··· 1 + digraph state_automaton { 2 + center = true; 3 + size = "7,11"; 4 + {node [shape = plaintext] "scheduling_context"}; 5 + {node [shape = plaintext, style=invis, label=""] "__init_thread_context"}; 6 + {node [shape = ellipse] "thread_context"}; 7 + {node [shape = plaintext] "thread_context"}; 8 + "__init_thread_context" -> "thread_context"; 9 + "scheduling_context" [label = "scheduling_context"]; 10 + "scheduling_context" -> "thread_context" [ label = "schedule_exit" ]; 11 + "thread_context" [label = "thread_context", color = green3]; 12 + "thread_context" -> "scheduling_context" [ label = "schedule_entry" ]; 13 + "thread_context" -> "thread_context" [ label = "sched_set_state" ]; 14 + { rank = min ; 15 + "__init_thread_context"; 16 + "thread_context"; 17 + } 18 + }
+18
tools/verification/models/sched/scpd.dot
··· 1 + digraph state_automaton { 2 + center = true; 3 + size = "7,11"; 4 + {node [shape = plaintext] "can_sched"}; 5 + {node [shape = plaintext, style=invis, label=""] "__init_cant_sched"}; 6 + {node [shape = ellipse] "cant_sched"}; 7 + {node [shape = plaintext] "cant_sched"}; 8 + "__init_cant_sched" -> "cant_sched"; 9 + "can_sched" [label = "can_sched"]; 10 + "can_sched" -> "can_sched" [ label = "schedule_entry\nschedule_exit" ]; 11 + "can_sched" -> "cant_sched" [ label = "preempt_enable" ]; 12 + "cant_sched" [label = "cant_sched", color = green3]; 13 + "cant_sched" -> "can_sched" [ label = "preempt_disable" ]; 14 + { rank = min ; 15 + "__init_cant_sched"; 16 + "cant_sched"; 17 + } 18 + }
+18
tools/verification/models/sched/sncid.dot
··· 1 + digraph state_automaton { 2 + center = true; 3 + size = "7,11"; 4 + {node [shape = plaintext, style=invis, label=""] "__init_can_sched"}; 5 + {node [shape = ellipse] "can_sched"}; 6 + {node [shape = plaintext] "can_sched"}; 7 + {node [shape = plaintext] "cant_sched"}; 8 + "__init_can_sched" -> "can_sched"; 9 + "can_sched" [label = "can_sched", color = green3]; 10 + "can_sched" -> "can_sched" [ label = "schedule_entry\nschedule_exit" ]; 11 + "can_sched" -> "cant_sched" [ label = "irq_disable" ]; 12 + "cant_sched" [label = "cant_sched"]; 13 + "cant_sched" -> "can_sched" [ label = "irq_enable" ]; 14 + { rank = min ; 15 + "__init_can_sched"; 16 + "can_sched"; 17 + } 18 + }
+18
tools/verification/models/sched/snep.dot
··· 1 + digraph state_automaton { 2 + center = true; 3 + size = "7,11"; 4 + {node [shape = plaintext, style=invis, label=""] "__init_non_scheduling_context"}; 5 + {node [shape = ellipse] "non_scheduling_context"}; 6 + {node [shape = plaintext] "non_scheduling_context"}; 7 + {node [shape = plaintext] "scheduling_contex"}; 8 + "__init_non_scheduling_context" -> "non_scheduling_context"; 9 + "non_scheduling_context" [label = "non_scheduling_context", color = green3]; 10 + "non_scheduling_context" -> "non_scheduling_context" [ label = "preempt_disable\npreempt_enable" ]; 11 + "non_scheduling_context" -> "scheduling_contex" [ label = "schedule_entry" ]; 12 + "scheduling_contex" [label = "scheduling_contex"]; 13 + "scheduling_contex" -> "non_scheduling_context" [ label = "schedule_exit" ]; 14 + { rank = min ; 15 + "__init_non_scheduling_context"; 16 + "non_scheduling_context"; 17 + } 18 + }
+18
tools/verification/models/sched/snroc.dot
··· 1 + digraph state_automaton { 2 + center = true; 3 + size = "7,11"; 4 + {node [shape = plaintext, style=invis, label=""] "__init_other_context"}; 5 + {node [shape = ellipse] "other_context"}; 6 + {node [shape = plaintext] "other_context"}; 7 + {node [shape = plaintext] "own_context"}; 8 + "__init_other_context" -> "other_context"; 9 + "other_context" [label = "other_context", color = green3]; 10 + "other_context" -> "own_context" [ label = "sched_switch_in" ]; 11 + "own_context" [label = "own_context"]; 12 + "own_context" -> "other_context" [ label = "sched_switch_out" ]; 13 + "own_context" -> "own_context" [ label = "sched_set_state" ]; 14 + { rank = min ; 15 + "__init_other_context"; 16 + "other_context"; 17 + } 18 + }
+18
tools/verification/models/sched/tss.dot
··· 1 + digraph state_automaton { 2 + center = true; 3 + size = "7,11"; 4 + {node [shape = plaintext] "sched"}; 5 + {node [shape = plaintext, style=invis, label=""] "__init_thread"}; 6 + {node [shape = ellipse] "thread"}; 7 + {node [shape = plaintext] "thread"}; 8 + "__init_thread" -> "thread"; 9 + "sched" [label = "sched"]; 10 + "sched" -> "sched" [ label = "sched_switch" ]; 11 + "sched" -> "thread" [ label = "schedule_exit" ]; 12 + "thread" [label = "thread", color = green3]; 13 + "thread" -> "sched" [ label = "schedule_entry" ]; 14 + { rank = min ; 15 + "__init_thread"; 16 + "thread"; 17 + } 18 + }
+1 -1
tools/verification/rv/include/in_kernel.h
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 - int ikm_list_monitors(void); 2 + int ikm_list_monitors(char *container); 3 3 int ikm_run_monitor(char *monitor, int argc, char **argv);
+2 -1
tools/verification/rv/include/rv.h
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 3 3 #define MAX_DESCRIPTION 1024 4 - #define MAX_DA_NAME_LEN 24 4 + #define MAX_DA_NAME_LEN 32 5 5 6 6 struct monitor { 7 7 char name[MAX_DA_NAME_LEN]; 8 8 char desc[MAX_DESCRIPTION]; 9 9 int enabled; 10 + int nested; 10 11 }; 11 12 12 13 int should_stop(void);
+203 -55
tools/verification/rv/src/in_kernel.c
··· 6 6 */ 7 7 #include <getopt.h> 8 8 #include <stdlib.h> 9 + #include <stdio.h> 9 10 #include <string.h> 10 11 #include <errno.h> 11 12 #include <unistd.h> 13 + #include <dirent.h> 12 14 13 15 #include <trace.h> 14 16 #include <utils.h> 15 17 #include <rv.h> 16 18 17 19 static int config_has_id; 20 + static int config_is_container; 18 21 static int config_my_pid; 19 22 static int config_trace; 20 23 ··· 45 42 return -1; 46 43 47 44 return enabled; 45 + } 46 + 47 + /* 48 + * __ikm_find_monitor - find the full name of a possibly nested module 49 + * 50 + * __does not log errors. 51 + * 52 + * Returns 1 if we found the monitor, -1 on error and 0 if it does not exist. 53 + * The string out_name is populated with the full name, which can be 54 + * equal to monitor_name or container/monitor_name if nested 55 + */ 56 + static int __ikm_find_monitor_name(char *monitor_name, char *out_name) 57 + { 58 + char *available_monitors, container[MAX_DA_NAME_LEN+1], *cursor, *end; 59 + int retval = 1; 60 + 61 + available_monitors = tracefs_instance_file_read(NULL, "rv/available_monitors", NULL); 62 + if (!available_monitors) 63 + return -1; 64 + 65 + cursor = strstr(available_monitors, monitor_name); 66 + if (!cursor) { 67 + retval = 0; 68 + goto out_free; 69 + } 70 + 71 + for (; cursor > available_monitors; cursor--) 72 + if (*(cursor-1) == '\n') 73 + break; 74 + end = strstr(cursor, "\n"); 75 + memcpy(out_name, cursor, end-cursor); 76 + out_name[end-cursor] = '\0'; 77 + 78 + cursor = strstr(out_name, ":"); 79 + if (cursor) 80 + *cursor = '/'; 81 + else { 82 + sprintf(container, "%s:", monitor_name); 83 + if (strstr(available_monitors, container)) 84 + config_is_container = 1; 85 + } 86 + 87 + out_free: 88 + free(available_monitors); 89 + return retval; 48 90 } 49 91 50 92 /* ··· 180 132 /* 181 133 * ikm_fill_monitor_definition - fill monitor's definition 182 134 * 183 - * Returns -1 on error, 0 otherwise. 135 + * Returns -1 on error, 1 if the monitor does not belong in the container, 0 otherwise. 136 + * container can be NULL 184 137 */ 185 - static int ikm_fill_monitor_definition(char *name, struct monitor *ikm) 138 + static int ikm_fill_monitor_definition(char *name, struct monitor *ikm, char *container) 186 139 { 187 140 int enabled; 188 - char *desc; 141 + char *desc, *nested_name; 142 + 143 + nested_name = strstr(name, ":"); 144 + if (nested_name) { 145 + /* it belongs in container if it starts with "container:" */ 146 + if (container && strstr(name, container) != name) 147 + return 1; 148 + *nested_name = '/'; 149 + ++nested_name; 150 + ikm->nested = 1; 151 + } else { 152 + if (container) 153 + return 1; 154 + nested_name = name; 155 + ikm->nested = 0; 156 + } 189 157 190 158 enabled = ikm_read_enable(name); 191 159 if (enabled < 0) { ··· 215 151 return -1; 216 152 } 217 153 218 - strncpy(ikm->name, name, MAX_DA_NAME_LEN); 154 + strncpy(ikm->name, nested_name, MAX_DA_NAME_LEN); 219 155 ikm->enabled = enabled; 220 156 strncpy(ikm->desc, desc, MAX_DESCRIPTION); 221 157 ··· 334 270 * 335 271 * Returns 0 on success, -1 otherwise. 336 272 */ 337 - int ikm_list_monitors(void) 273 + int ikm_list_monitors(char *container) 338 274 { 339 275 char *available_monitors; 340 - struct monitor ikm; 276 + struct monitor ikm = {0}; 341 277 char *curr, *next; 342 - int retval; 278 + int retval, list_monitor = 0; 343 279 344 280 available_monitors = tracefs_instance_file_read(NULL, "rv/available_monitors", NULL); 345 281 ··· 353 289 next = strstr(curr, "\n"); 354 290 *next = '\0'; 355 291 356 - retval = ikm_fill_monitor_definition(curr, &ikm); 357 - if (retval) 292 + retval = ikm_fill_monitor_definition(curr, &ikm, container); 293 + if (retval < 0) 358 294 err_msg("ikm: error reading %d in kernel monitor, skipping\n", curr); 359 295 360 - printf("%-24s %s %s\n", ikm.name, ikm.desc, ikm.enabled ? "[ON]" : "[OFF]"); 296 + if (!retval) { 297 + int indent = ikm.nested && !container; 298 + 299 + list_monitor = 1; 300 + printf("%s%-*s %s %s\n", indent ? " - " : "", 301 + indent ? MAX_DA_NAME_LEN - 3 : MAX_DA_NAME_LEN, 302 + ikm.name, ikm.desc, ikm.enabled ? "[ON]" : "[OFF]"); 303 + } 361 304 curr = ++next; 362 305 363 306 } while (strlen(curr)); 307 + 308 + if (!list_monitor) { 309 + if (container) 310 + printf("-- No monitor found in container %s --\n", container); 311 + else 312 + printf("-- No monitor found --\n"); 313 + } 364 314 365 315 free(available_monitors); 366 316 ··· 421 343 unsigned long long final_state; 422 344 unsigned long long pid; 423 345 unsigned long long id; 424 - int cpu = record->cpu; 425 346 int val; 347 + bool missing_id; 426 348 427 349 if (config_has_id) 428 - tep_get_field_val(s, trace_event, "id", record, &id, 1); 350 + missing_id = tep_get_field_val(s, trace_event, "id", record, &id, 1); 429 351 430 352 tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1); 431 353 ··· 434 356 else if (config_my_pid && (config_my_pid == pid)) 435 357 return 0; 436 358 437 - tep_print_event(trace_event->tep, s, record, "%16s-%-8d ", TEP_PRINT_COMM, TEP_PRINT_PID); 359 + tep_print_event(trace_event->tep, s, record, "%16s-%-8d [%.3d] ", 360 + TEP_PRINT_COMM, TEP_PRINT_PID, TEP_PRINT_CPU); 438 361 439 - trace_seq_printf(s, "[%.3d] event ", cpu); 362 + if (config_is_container) 363 + tep_print_event(trace_event->tep, s, record, "%s ", TEP_PRINT_NAME); 364 + else 365 + trace_seq_printf(s, "event "); 440 366 441 - if (config_has_id) 442 - trace_seq_printf(s, "%8llu ", id); 367 + if (config_has_id) { 368 + if (missing_id) 369 + /* placeholder if we are dealing with a mixed-type container*/ 370 + trace_seq_printf(s, " "); 371 + else 372 + trace_seq_printf(s, "%8llu ", id); 373 + } 443 374 444 375 state = tep_get_field_raw(s, trace_event, "state", record, &val, 0); 445 376 event = tep_get_field_raw(s, trace_event, "event", record, &val, 0); ··· 481 394 int cpu = record->cpu; 482 395 char *state, *event; 483 396 int val; 397 + bool missing_id; 484 398 485 399 if (config_has_id) 486 - tep_get_field_val(s, trace_event, "id", record, &id, 1); 400 + missing_id = tep_get_field_val(s, trace_event, "id", record, &id, 1); 487 401 488 402 tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1); 489 403 ··· 493 405 else if (config_my_pid == pid) 494 406 return 0; 495 407 496 - trace_seq_printf(s, "%8lld [%03d] error ", pid, cpu); 408 + trace_seq_printf(s, "%8lld [%03d] ", pid, cpu); 497 409 498 - if (config_has_id) 499 - trace_seq_printf(s, "%8llu ", id); 410 + if (config_is_container) 411 + tep_print_event(trace_event->tep, s, record, "%s ", TEP_PRINT_NAME); 412 + else 413 + trace_seq_printf(s, "error "); 414 + 415 + if (config_has_id) { 416 + if (missing_id) 417 + /* placeholder if we are dealing with a mixed-type container*/ 418 + trace_seq_printf(s, " "); 419 + else 420 + trace_seq_printf(s, "%8llu ", id); 421 + } 500 422 501 423 state = tep_get_field_raw(s, trace_event, "state", record, &val, 0); 502 424 event = tep_get_field_raw(s, trace_event, "event", record, &val, 0); ··· 519 421 return 0; 520 422 } 521 423 424 + static int ikm_enable_trace_events(char *monitor_name, struct trace_instance *inst) 425 + { 426 + char event[MAX_DA_NAME_LEN + 7]; /* max(error_,event_) + '0' = 7 */ 427 + int retval; 428 + 429 + snprintf(event, sizeof(event), "event_%s", monitor_name); 430 + retval = tracefs_event_enable(inst->inst, "rv", event); 431 + if (retval) 432 + return -1; 433 + 434 + tep_register_event_handler(inst->tep, -1, "rv", event, 435 + ikm_event_handler, NULL); 436 + 437 + snprintf(event, sizeof(event), "error_%s", monitor_name); 438 + retval = tracefs_event_enable(inst->inst, "rv", event); 439 + if (retval) 440 + return -1; 441 + 442 + tep_register_event_handler(inst->tep, -1, "rv", event, 443 + ikm_error_handler, NULL); 444 + 445 + /* set if at least 1 monitor has id in case of a container */ 446 + config_has_id = ikm_has_id(monitor_name); 447 + if (config_has_id < 0) 448 + return -1; 449 + 450 + 451 + return 0; 452 + } 453 + 454 + static int ikm_enable_trace_container(char *monitor_name, 455 + struct trace_instance *inst) 456 + { 457 + DIR *dp; 458 + char *abs_path, rv_path[MAX_PATH]; 459 + struct dirent *ep; 460 + int retval = 0; 461 + 462 + snprintf(rv_path, MAX_PATH, "rv/monitors/%s", monitor_name); 463 + abs_path = tracefs_instance_get_file(NULL, rv_path); 464 + if (!abs_path) 465 + return -1; 466 + dp = opendir(abs_path); 467 + if (!dp) 468 + goto out_free; 469 + 470 + while (!retval && (ep = readdir(dp))) { 471 + if (ep->d_type != DT_DIR || ep->d_name[0] == '.') 472 + continue; 473 + retval = ikm_enable_trace_events(ep->d_name, inst); 474 + } 475 + 476 + closedir(dp); 477 + out_free: 478 + free(abs_path); 479 + return retval; 480 + } 481 + 522 482 /* 523 483 * ikm_setup_trace_instance - set up a tracing instance to collect data 524 484 * ··· 586 430 */ 587 431 static struct trace_instance *ikm_setup_trace_instance(char *monitor_name) 588 432 { 589 - char event[MAX_DA_NAME_LEN + 7]; /* max(error_,event_) + '0' = 7 */ 590 433 struct trace_instance *inst; 591 434 int retval; 592 435 593 436 if (!config_trace) 594 437 return NULL; 595 - 596 - config_has_id = ikm_has_id(monitor_name); 597 - if (config_has_id < 0) { 598 - err_msg("ikm: failed to read monitor %s event format\n", monitor_name); 599 - goto out_err; 600 - } 601 438 602 439 /* alloc data */ 603 440 inst = calloc(1, sizeof(*inst)); ··· 603 454 if (retval) 604 455 goto out_free; 605 456 606 - /* enable events */ 607 - snprintf(event, sizeof(event), "event_%s", monitor_name); 608 - retval = tracefs_event_enable(inst->inst, "rv", event); 457 + if (config_is_container) 458 + retval = ikm_enable_trace_container(monitor_name, inst); 459 + else 460 + retval = ikm_enable_trace_events(monitor_name, inst); 609 461 if (retval) 610 462 goto out_inst; 611 - 612 - tep_register_event_handler(inst->tep, -1, "rv", event, 613 - ikm_event_handler, NULL); 614 - 615 - snprintf(event, sizeof(event), "error_%s", monitor_name); 616 - retval = tracefs_event_enable(inst->inst, "rv", event); 617 - if (retval) 618 - goto out_inst; 619 - 620 - tep_register_event_handler(inst->tep, -1, "rv", event, 621 - ikm_error_handler, NULL); 622 463 623 464 /* ready to enable */ 624 465 tracefs_trace_on(inst->inst); ··· 772 633 int ikm_run_monitor(char *monitor_name, int argc, char **argv) 773 634 { 774 635 struct trace_instance *inst = NULL; 636 + char *nested_name, full_name[2*MAX_DA_NAME_LEN]; 775 637 int retval; 776 638 777 - /* 778 - * Check if monitor exists by seeing it is enabled. 779 - */ 780 - retval = __ikm_read_enable(monitor_name); 781 - if (retval < 0) 782 - return 0; 639 + nested_name = strstr(monitor_name, ":"); 640 + if (nested_name) 641 + ++nested_name; 642 + else 643 + nested_name = monitor_name; 783 644 645 + retval = __ikm_find_monitor_name(monitor_name, full_name); 646 + if (!retval) 647 + return 0; 648 + if (retval < 0) { 649 + err_msg("ikm: error finding monitor %s\n", nested_name); 650 + return -1; 651 + } 652 + 653 + retval = __ikm_read_enable(full_name); 784 654 if (retval) { 785 - err_msg("ikm: monitor %s (in-kernel) is already enabled\n", monitor_name); 655 + err_msg("ikm: monitor %s (in-kernel) is already enabled\n", nested_name); 786 656 return -1; 787 657 } 788 658 789 659 /* we should be good to go */ 790 - retval = parse_arguments(monitor_name, argc, argv); 660 + retval = parse_arguments(full_name, argc, argv); 791 661 if (retval) 792 - ikm_usage(1, monitor_name, "ikm: failed parsing arguments"); 662 + ikm_usage(1, nested_name, "ikm: failed parsing arguments"); 793 663 794 664 if (config_trace) { 795 - inst = ikm_setup_trace_instance(monitor_name); 665 + inst = ikm_setup_trace_instance(nested_name); 796 666 if (!inst) 797 667 return -1; 798 668 } 799 669 800 - retval = ikm_enable(monitor_name); 670 + retval = ikm_enable(full_name); 801 671 if (retval < 0) 802 672 goto out_free_instance; 803 673 ··· 830 682 sleep(1); 831 683 } 832 684 833 - ikm_disable(monitor_name); 685 + ikm_disable(full_name); 834 686 ikm_destroy_trace_instance(inst); 835 687 836 688 if (config_reactor && config_initial_reactor) 837 - ikm_write_reactor(monitor_name, config_initial_reactor); 689 + ikm_write_reactor(full_name, config_initial_reactor); 838 690 839 691 return 1; 840 692 841 693 out_free_instance: 842 694 ikm_destroy_trace_instance(inst); 843 695 if (config_reactor && config_initial_reactor) 844 - ikm_write_reactor(monitor_name, config_initial_reactor); 696 + ikm_write_reactor(full_name, config_initial_reactor); 845 697 return -1; 846 698 }
+24 -12
tools/verification/rv/src/rv.c
··· 41 41 { 42 42 static const char *const usage[] = { 43 43 "", 44 - " usage: rv list [-h]", 44 + " usage: rv list [-h] [container]", 45 45 "", 46 46 " list all available monitors", 47 47 "", 48 48 " -h/--help: print this menu", 49 + "", 50 + " [container]: list only monitors in this container", 49 51 NULL, 50 52 }; 51 - int i; 53 + int i, print_help = 0, retval = 0; 54 + char *container = NULL; 52 55 53 - if (argc > 1) { 56 + if (argc == 2) { 57 + if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { 58 + print_help = 1; 59 + retval = 0; 60 + } else if (argv[1][0] == '-') { 61 + /* assume invalid option */ 62 + print_help = 1; 63 + retval = 1; 64 + } else 65 + container = argv[1]; 66 + } else if (argc > 2) { 67 + /* more than 2 is always usage */ 68 + print_help = 1; 69 + retval = 1; 70 + } 71 + if (print_help) { 54 72 fprintf(stderr, "rv version %s\n", VERSION); 55 - 56 - /* more than 1 is always usage */ 57 73 for (i = 0; usage[i]; i++) 58 74 fprintf(stderr, "%s\n", usage[i]); 59 - 60 - /* but only -h is valid */ 61 - if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) 62 - exit(0); 63 - else 64 - exit(1); 75 + exit(retval); 65 76 } 66 77 67 - ikm_list_monitors(); 78 + ikm_list_monitors(container); 79 + 68 80 exit(0); 69 81 } 70 82