Skip to content

Commit cb85c66

Browse files
glemcorostedt
authored andcommitted
rv: Add option for nested monitors and include sched
Monitors describing complex systems, such as the scheduler, can easily grow to the point where they are just hard to understand because of the many possible state transitions. Often it is possible to break such descriptions into smaller monitors, sharing some or all events. Enabling those smaller monitors concurrently is, in fact, testing the system as if we had one single larger monitor. Splitting models into multiple specification is not only easier to understand, but gives some more clues when we see errors. Add the possibility to create container monitors, whose only purpose is to host other nested monitors. Enabling a container monitor enables all nested ones, but it's still possible to enable nested monitors independently. Add the sched monitor as first container, for now empty. Cc: Ingo Molnar <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Juri Lelli <[email protected]> Link: https://lore.kernel.org/[email protected] Signed-off-by: Gabriele Monaco <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent 26f8068 commit cb85c66

File tree

11 files changed

+217
-29
lines changed

11 files changed

+217
-29
lines changed

include/linux/rv.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ struct rv_monitor {
5656

5757
bool rv_monitoring_on(void);
5858
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);
6060
int rv_get_task_monitor_slot(void);
6161
void rv_put_task_monitor_slot(int slot);
6262

kernel/trace/rv/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ menuconfig RV
2727

2828
source "kernel/trace/rv/monitors/wip/Kconfig"
2929
source "kernel/trace/rv/monitors/wwnr/Kconfig"
30+
source "kernel/trace/rv/monitors/sched/Kconfig"
3031
# Add new monitors here
3132

3233
config RV_REACTORS

kernel/trace/rv/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ ccflags-y += -I $(src) # needed for trace events
55
obj-$(CONFIG_RV) += rv.o
66
obj-$(CONFIG_RV_MON_WIP) += monitors/wip/wip.o
77
obj-$(CONFIG_RV_MON_WWNR) += monitors/wwnr/wwnr.o
8+
obj-$(CONFIG_RV_MON_SCHED) += monitors/sched/sched.o
89
# Add new monitors here
910
obj-$(CONFIG_RV_REACTORS) += rv_reactors.o
1011
obj-$(CONFIG_RV_REACT_PRINTK) += reactor_printk.o
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
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
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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 <[email protected]>");
38+
MODULE_DESCRIPTION("sched: container for several scheduler monitor specifications.");
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
extern struct rv_monitor rv_sched;

kernel/trace/rv/monitors/wip/wip.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ static struct rv_monitor rv_wip = {
7171

7272
static int __init register_wip(void)
7373
{
74-
rv_register_monitor(&rv_wip);
74+
rv_register_monitor(&rv_wip, NULL);
7575
return 0;
7676
}
7777

kernel/trace/rv/monitors/wwnr/wwnr.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ static struct rv_monitor rv_wwnr = {
7070

7171
static int __init register_wwnr(void)
7272
{
73-
rv_register_monitor(&rv_wwnr);
73+
rv_register_monitor(&rv_wwnr, NULL);
7474
return 0;
7575
}
7676

kernel/trace/rv/rv.c

Lines changed: 131 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ struct dentry *get_monitors_root(void)
162162
/*
163163
* Interface for the monitor register.
164164
*/
165-
static LIST_HEAD(rv_monitors_list);
165+
LIST_HEAD(rv_monitors_list);
166166

167167
static int task_monitor_count;
168168
static bool task_monitor_slots[RV_PER_TASK_MONITORS];
@@ -206,6 +206,30 @@ void rv_put_task_monitor_slot(int slot)
206206
task_monitor_slots[slot] = false;
207207
}
208208

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+
209233
/*
210234
* This section collects the monitor/ files and folders.
211235
*/
@@ -229,7 +253,8 @@ static int __rv_disable_monitor(struct rv_monitor_def *mdef, bool sync)
229253

230254
if (mdef->monitor->enabled) {
231255
mdef->monitor->enabled = 0;
232-
mdef->monitor->disable();
256+
if (mdef->monitor->disable)
257+
mdef->monitor->disable();
233258

234259
/*
235260
* Wait for the execution of all events to finish.
@@ -243,6 +268,60 @@ static int __rv_disable_monitor(struct rv_monitor_def *mdef, bool sync)
243268
return 0;
244269
}
245270

271+
static void rv_disable_single(struct rv_monitor_def *mdef)
272+
{
273+
__rv_disable_monitor(mdef, true);
274+
}
275+
276+
static int rv_enable_single(struct rv_monitor_def *mdef)
277+
{
278+
int retval;
279+
280+
lockdep_assert_held(&rv_interface_lock);
281+
282+
if (mdef->monitor->enabled)
283+
return 0;
284+
285+
retval = mdef->monitor->enable();
286+
287+
if (!retval)
288+
mdef->monitor->enabled = 1;
289+
290+
return retval;
291+
}
292+
293+
static void rv_disable_container(struct rv_monitor_def *mdef)
294+
{
295+
struct rv_monitor_def *p = mdef;
296+
int enabled = 0;
297+
298+
list_for_each_entry_continue(p, &rv_monitors_list, list) {
299+
if (p->parent != mdef->monitor)
300+
break;
301+
enabled += __rv_disable_monitor(p, false);
302+
}
303+
if (enabled)
304+
tracepoint_synchronize_unregister();
305+
mdef->monitor->enabled = 0;
306+
}
307+
308+
static int rv_enable_container(struct rv_monitor_def *mdef)
309+
{
310+
struct rv_monitor_def *p = mdef;
311+
int retval = 0;
312+
313+
list_for_each_entry_continue(p, &rv_monitors_list, list) {
314+
if (retval || p->parent != mdef->monitor)
315+
break;
316+
retval = rv_enable_single(p);
317+
}
318+
if (retval)
319+
rv_disable_container(mdef);
320+
else
321+
mdef->monitor->enabled = 1;
322+
return retval;
323+
}
324+
246325
/**
247326
* rv_disable_monitor - disable a given runtime monitor
248327
* @mdef: Pointer to the monitor definition structure.
@@ -251,7 +330,11 @@ static int __rv_disable_monitor(struct rv_monitor_def *mdef, bool sync)
251330
*/
252331
int rv_disable_monitor(struct rv_monitor_def *mdef)
253332
{
254-
__rv_disable_monitor(mdef, true);
333+
if (rv_is_container_monitor(mdef))
334+
rv_disable_container(mdef);
335+
else
336+
rv_disable_single(mdef);
337+
255338
return 0;
256339
}
257340

@@ -265,15 +348,10 @@ int rv_enable_monitor(struct rv_monitor_def *mdef)
265348
{
266349
int retval;
267350

268-
lockdep_assert_held(&rv_interface_lock);
269-
270-
if (mdef->monitor->enabled)
271-
return 0;
272-
273-
retval = mdef->monitor->enable();
274-
275-
if (!retval)
276-
mdef->monitor->enabled = 1;
351+
if (rv_is_container_monitor(mdef))
352+
retval = rv_enable_container(mdef);
353+
else
354+
retval = rv_enable_single(mdef);
277355

278356
return retval;
279357
}
@@ -336,9 +414,9 @@ static const struct file_operations interface_desc_fops = {
336414
* the monitor dir, where the specific options of the monitor
337415
* are exposed.
338416
*/
339-
static int create_monitor_dir(struct rv_monitor_def *mdef)
417+
static int create_monitor_dir(struct rv_monitor_def *mdef, struct rv_monitor_def *parent)
340418
{
341-
struct dentry *root = get_monitors_root();
419+
struct dentry *root = parent ? parent->root_d : get_monitors_root();
342420
const char *name = mdef->monitor->name;
343421
struct dentry *tmp;
344422
int retval;
@@ -377,7 +455,11 @@ static int monitors_show(struct seq_file *m, void *p)
377455
{
378456
struct rv_monitor_def *mon_def = p;
379457

380-
seq_printf(m, "%s\n", mon_def->monitor->name);
458+
if (mon_def->parent)
459+
seq_printf(m, "%s:%s\n", mon_def->parent->name,
460+
mon_def->monitor->name);
461+
else
462+
seq_printf(m, "%s\n", mon_def->monitor->name);
381463
return 0;
382464
}
383465

@@ -514,7 +596,7 @@ static ssize_t enabled_monitors_write(struct file *filp, const char __user *user
514596
struct rv_monitor_def *mdef;
515597
int retval = -EINVAL;
516598
bool enable = true;
517-
char *ptr;
599+
char *ptr, *tmp;
518600
int len;
519601

520602
if (count < 1 || count > MAX_RV_MONITOR_NAME_SIZE + 1)
@@ -541,6 +623,11 @@ static ssize_t enabled_monitors_write(struct file *filp, const char __user *user
541623

542624
retval = -EINVAL;
543625

626+
/* we support 1 nesting level, trim the parent */
627+
tmp = strstr(ptr, ":");
628+
if (tmp)
629+
ptr = tmp+1;
630+
544631
list_for_each_entry(mdef, &rv_monitors_list, list) {
545632
if (strcmp(ptr, mdef->monitor->name) != 0)
546633
continue;
@@ -613,7 +700,7 @@ static void reset_all_monitors(void)
613700
struct rv_monitor_def *mdef;
614701

615702
list_for_each_entry(mdef, &rv_monitors_list, list) {
616-
if (mdef->monitor->enabled)
703+
if (mdef->monitor->enabled && mdef->monitor->reset)
617704
mdef->monitor->reset();
618705
}
619706
}
@@ -685,45 +772,66 @@ static void destroy_monitor_dir(struct rv_monitor_def *mdef)
685772
/**
686773
* rv_register_monitor - register a rv monitor.
687774
* @monitor: The rv_monitor to be registered.
775+
* @parent: The parent of the monitor to be registered, NULL if not nested.
688776
*
689777
* Returns 0 if successful, error otherwise.
690778
*/
691-
int rv_register_monitor(struct rv_monitor *monitor)
779+
int rv_register_monitor(struct rv_monitor *monitor, struct rv_monitor *parent)
692780
{
693-
struct rv_monitor_def *r;
781+
struct rv_monitor_def *r, *p = NULL;
694782
int retval = 0;
695783

696784
if (strlen(monitor->name) >= MAX_RV_MONITOR_NAME_SIZE) {
697785
pr_info("Monitor %s has a name longer than %d\n", monitor->name,
698786
MAX_RV_MONITOR_NAME_SIZE);
699-
return -1;
787+
return -EINVAL;
700788
}
701789

702790
mutex_lock(&rv_interface_lock);
703791

704792
list_for_each_entry(r, &rv_monitors_list, list) {
705793
if (strcmp(monitor->name, r->monitor->name) == 0) {
706794
pr_info("Monitor %s is already registered\n", monitor->name);
707-
retval = -1;
795+
retval = -EEXIST;
708796
goto out_unlock;
709797
}
710798
}
711799

800+
if (parent) {
801+
list_for_each_entry(r, &rv_monitors_list, list) {
802+
if (strcmp(parent->name, r->monitor->name) == 0) {
803+
p = r;
804+
break;
805+
}
806+
}
807+
}
808+
809+
if (p && rv_is_nested_monitor(p)) {
810+
pr_info("Parent monitor %s is already nested, cannot nest further\n",
811+
parent->name);
812+
return -EINVAL;
813+
}
814+
712815
r = kzalloc(sizeof(struct rv_monitor_def), GFP_KERNEL);
713816
if (!r) {
714817
retval = -ENOMEM;
715818
goto out_unlock;
716819
}
717820

718821
r->monitor = monitor;
822+
r->parent = parent;
719823

720-
retval = create_monitor_dir(r);
824+
retval = create_monitor_dir(r, p);
721825
if (retval) {
722826
kfree(r);
723827
goto out_unlock;
724828
}
725829

726-
list_add_tail(&r->list, &rv_monitors_list);
830+
/* keep children close to the parent for easier visualisation */
831+
if (p)
832+
list_add(&r->list, &p->list);
833+
else
834+
list_add_tail(&r->list, &rv_monitors_list);
727835

728836
out_unlock:
729837
mutex_unlock(&rv_interface_lock);

kernel/trace/rv/rv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ struct rv_interface {
2121
#define MAX_RV_REACTOR_NAME_SIZE 32
2222

2323
extern struct mutex rv_interface_lock;
24+
extern struct list_head rv_monitors_list;
2425

2526
#ifdef CONFIG_RV_REACTORS
2627
struct rv_reactor_def {
@@ -34,6 +35,7 @@ struct rv_reactor_def {
3435
struct rv_monitor_def {
3536
struct list_head list;
3637
struct rv_monitor *monitor;
38+
struct rv_monitor *parent;
3739
struct dentry *root_d;
3840
#ifdef CONFIG_RV_REACTORS
3941
struct rv_reactor_def *rdef;
@@ -45,6 +47,8 @@ struct rv_monitor_def {
4547
struct dentry *get_monitors_root(void);
4648
int rv_disable_monitor(struct rv_monitor_def *mdef);
4749
int rv_enable_monitor(struct rv_monitor_def *mdef);
50+
bool rv_is_container_monitor(struct rv_monitor_def *mdef);
51+
bool rv_is_nested_monitor(struct rv_monitor_def *mdef);
4852

4953
#ifdef CONFIG_RV_REACTORS
5054
int reactor_populate_monitor(struct rv_monitor_def *mdef);

0 commit comments

Comments
 (0)