Skip to content

Commit

Permalink
verification/dot2k: Add support for nested monitors
Browse files Browse the repository at this point in the history
RV now supports nested monitors, this functionality requires a container
monitor, which has virtually no functionality besides holding other
monitors, and nested monitors, that have a container as parent.

Add the -p flag to pass a parent to a monitor, this sets it up while
registering the monitor and adds necessary includes and configurations.
Add the -c flag to create a container, since containers are empty, we
don't allow supplying a dot model or a monitor type, the template is
also different since functions to enable and disable the monitor are not
defined, nor any tracepoint. The generated header file only allows to
include the rv_monitor structure in children monitors.

Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Juri Lelli <juri.lelli@redhat.com>
Link: https://lore.kernel.org/20250305140406.350227-8-gmonaco@redhat.com
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
  • Loading branch information
Gabriele Monaco authored and Steven Rostedt (Google) committed Mar 24, 2025
1 parent eba321a commit 2334cf7
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 27 deletions.
27 changes: 18 additions & 9 deletions tools/verification/dot2/dot2k
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,30 @@
if __name__ == '__main__':
from dot2.dot2k import dot2k
import argparse
import ntpath
import os
import platform
import sys

def is_container():
"""Should work even before parsing the arguments"""
return "-c" in sys.argv or "--container" in sys.argv

parser = argparse.ArgumentParser(description='transform .dot file into kernel rv monitor')
parser.add_argument('-d', "--dot", dest="dot_file", required=True)
parser.add_argument('-t', "--monitor_type", dest="monitor_type", required=True)
parser.add_argument('-n', "--model_name", dest="model_name", required=False)
parser.add_argument('-d', "--dot", dest="dot_file", required=not is_container())
parser.add_argument('-t', "--monitor_type", dest="monitor_type", required=not is_container(),
help=f"Available options: {', '.join(dot2k.monitor_types.keys())}")
parser.add_argument('-n', "--model_name", dest="model_name", required=is_container())
parser.add_argument("-D", "--description", dest="description", required=False)
parser.add_argument("-a", "--auto_patch", dest="auto_patch",
action="store_true", required=False,
help="Patch the kernel in place")
parser.add_argument("-p", "--parent", dest="parent",
required=False, help="Create a monitor nested to parent")
parser.add_argument("-c", "--container", dest="container",
action="store_true", required=False,
help="Create an empty monitor to be used as a container")
params = parser.parse_args()

print("Opening and parsing the dot file %s" % params.dot_file)
if not is_container():
print("Opening and parsing the dot file %s" % params.dot_file)
try:
monitor=dot2k(params.dot_file, params.monitor_type, vars(params))
except Exception as e:
Expand All @@ -37,8 +45,9 @@ if __name__ == '__main__':
print("Writing the monitor into the directory %s" % monitor.name)
monitor.print_files()
print("Almost done, checklist")
print(" - Edit the %s/%s.c to add the instrumentation" % (monitor.name, monitor.name))
print(monitor.fill_tracepoint_tooltip())
if not is_container():
print(" - Edit the %s/%s.c to add the instrumentation" % (monitor.name, monitor.name))
print(monitor.fill_tracepoint_tooltip())
print(monitor.fill_makefile_tooltip())
print(monitor.fill_kconfig_tooltip())
print(monitor.fill_monitor_tooltip())
79 changes: 63 additions & 16 deletions tools/verification/dot2/dot2k.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,31 @@ class dot2k(Dot2c):
monitor_type = "per_cpu"

def __init__(self, file_path, MonitorType, extra_params={}):
super().__init__(file_path, extra_params.get("model_name"))

self.monitor_type = self.monitor_types.get(MonitorType)
if self.monitor_type is None:
raise ValueError("Unknown monitor type: %s" % MonitorType)

self.monitor_type = MonitorType
self.container = extra_params.get("container")
self.parent = extra_params.get("parent")
self.__fill_rv_templates_dir()
self.main_c = self.__read_file(self.monitor_templates_dir + "main.c")
self.trace_h = self.__read_file(self.monitor_templates_dir + "trace.h")

if self.container:
if file_path:
raise ValueError("A container does not require a dot file")
if MonitorType:
raise ValueError("A container does not require a monitor type")
if self.parent:
raise ValueError("A container cannot have a parent")
self.name = extra_params.get("model_name")
self.events = []
self.states = []
self.main_c = self.__read_file(self.monitor_templates_dir + "main_container.c")
self.main_h = self.__read_file(self.monitor_templates_dir + "main_container.h")
else:
super().__init__(file_path, extra_params.get("model_name"))

self.monitor_type = self.monitor_types.get(MonitorType)
if self.monitor_type is None:
raise ValueError("Unknown monitor type: %s" % MonitorType)
self.monitor_type = MonitorType
self.main_c = self.__read_file(self.monitor_templates_dir + "main.c")
self.trace_h = self.__read_file(self.monitor_templates_dir + "trace.h")
self.kconfig = self.__read_file(self.monitor_templates_dir + "Kconfig")
self.enum_suffix = "_%s" % self.name
self.description = extra_params.get("description", self.name) or "auto-generated"
Expand Down Expand Up @@ -105,6 +120,14 @@ def __buff_to_string(self, buff):
def fill_monitor_type(self):
return self.monitor_type.upper()

def fill_parent(self):
return "&rv_%s" % self.parent if self.parent else "NULL"

def fill_include_parent(self):
if self.parent:
return "#include <monitors/%s/%s.h>\n" % (self.parent, self.parent)
return ""

def fill_tracepoint_handlers_skel(self):
buff = []
for event in self.events:
Expand Down Expand Up @@ -146,6 +169,8 @@ def fill_main_c(self):
tracepoint_handlers = self.fill_tracepoint_handlers_skel()
tracepoint_attach = self.fill_tracepoint_attach_probe()
tracepoint_detach = self.fill_tracepoint_detach_helper()
parent = self.fill_parent()
parent_include = self.fill_include_parent()

main_c = main_c.replace("%%MONITOR_TYPE%%", monitor_type)
main_c = main_c.replace("%%MIN_TYPE%%", min_type)
Expand All @@ -155,6 +180,8 @@ def fill_main_c(self):
main_c = main_c.replace("%%TRACEPOINT_ATTACH%%", tracepoint_attach)
main_c = main_c.replace("%%TRACEPOINT_DETACH%%", tracepoint_detach)
main_c = main_c.replace("%%DESCRIPTION%%", self.description)
main_c = main_c.replace("%%PARENT%%", parent)
main_c = main_c.replace("%%INCLUDE_PARENT%%", parent_include)

return main_c

Expand Down Expand Up @@ -216,6 +243,14 @@ def fill_tracepoint_args_skel(self, tp_type):
buff.append(" TP_ARGS(%s)" % tp_args_c)
return self.__buff_to_string(buff)

def fill_monitor_deps(self):
buff = []
buff.append(" # XXX: add dependencies if there")
if self.parent:
buff.append(" depends on RV_MON_%s" % self.parent.upper())
buff.append(" default y")
return self.__buff_to_string(buff)

def fill_trace_h(self):
trace_h = self.trace_h
monitor_class = self.fill_monitor_class()
Expand All @@ -233,12 +268,19 @@ def fill_trace_h(self):
def fill_kconfig(self):
kconfig = self.kconfig
monitor_class_type = self.fill_monitor_class_type()
monitor_deps = self.fill_monitor_deps()
kconfig = kconfig.replace("%%MODEL_NAME%%", self.name)
kconfig = kconfig.replace("%%MODEL_NAME_UP%%", self.name.upper())
kconfig = kconfig.replace("%%MONITOR_CLASS_TYPE%%", monitor_class_type)
kconfig = kconfig.replace("%%DESCRIPTION%%", self.description)
kconfig = kconfig.replace("%%MONITOR_DEPS%%", monitor_deps)
return kconfig

def fill_main_container_h(self):
main_h = self.main_h
main_h = main_h.replace("%%MODEL_NAME%%", self.name)
return main_h

def __patch_file(self, file, marker, line):
file_to_patch = os.path.join(self.rv_dir, file)
content = self.__read_file(file_to_patch)
Expand Down Expand Up @@ -324,19 +366,24 @@ def __get_main_name(self):

def print_files(self):
main_c = self.fill_main_c()
model_h = self.fill_model_h()

self.__create_directory()

path = "%s.c" % self.name
self.__create_file(path, main_c)

path = "%s.h" % self.name
self.__create_file(path, model_h)

trace_h = self.fill_trace_h()
path = "%s_trace.h" % self.name
self.__create_file(path, trace_h)
if self.container:
main_h = self.fill_main_container_h()
path = "%s.h" % self.name
self.__create_file(path, main_h)
else:
model_h = self.fill_model_h()
path = "%s.h" % self.name
self.__create_file(path, model_h)

trace_h = self.fill_trace_h()
path = "%s_trace.h" % self.name
self.__create_file(path, trace_h)

kconfig = self.fill_kconfig()
self.__create_file("Kconfig", kconfig)
1 change: 1 addition & 0 deletions tools/verification/dot2/dot2k_templates/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#
config RV_MON_%%MODEL_NAME_UP%%
depends on RV
%%MONITOR_DEPS%%
select %%MONITOR_CLASS_TYPE%%
bool "%%MODEL_NAME%% monitor"
help
Expand Down
4 changes: 2 additions & 2 deletions tools/verification/dot2/dot2k_templates/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* #include <trace/events/sched.h>
*/
#include <rv_trace.h>

%%INCLUDE_PARENT%%
/*
* This is the self-generated part of the monitor. Generally, there is no need
* to touch this section.
Expand Down Expand Up @@ -74,7 +74,7 @@ static struct rv_monitor rv_%%MODEL_NAME%% = {

static int __init register_%%MODEL_NAME%%(void)
{
rv_register_monitor(&rv_%%MODEL_NAME%%);
rv_register_monitor(&rv_%%MODEL_NAME%%, %%PARENT%%);
return 0;
}

Expand Down
38 changes: 38 additions & 0 deletions tools/verification/dot2/dot2k_templates/main_container.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/rv.h>

#define MODULE_NAME "%%MODEL_NAME%%"

#include "%%MODEL_NAME%%.h"

struct rv_monitor rv_%%MODEL_NAME%%;

struct rv_monitor rv_%%MODEL_NAME%% = {
.name = "%%MODEL_NAME%%",
.description = "%%DESCRIPTION%%",
.enable = NULL,
.disable = NULL,
.reset = NULL,
.enabled = 0,
};

static int __init register_%%MODEL_NAME%%(void)
{
rv_register_monitor(&rv_%%MODEL_NAME%%, NULL);
return 0;
}

static void __exit unregister_%%MODEL_NAME%%(void)
{
rv_unregister_monitor(&rv_%%MODEL_NAME%%);
}

module_init(register_%%MODEL_NAME%%);
module_exit(unregister_%%MODEL_NAME%%);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("dot2k: auto-generated");
MODULE_DESCRIPTION("%%MODEL_NAME%%: %%DESCRIPTION%%");
3 changes: 3 additions & 0 deletions tools/verification/dot2/dot2k_templates/main_container.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* SPDX-License-Identifier: GPL-2.0 */

extern struct rv_monitor rv_%%MODEL_NAME%%;

0 comments on commit 2334cf7

Please sign in to comment.