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

verification/dot2k: Add support for nested monitors

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: default avatarGabriele Monaco <gmonaco@redhat.com>
Signed-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
parent eba321a1
Loading
Loading
Loading
Loading
+18 −9
Original line number Diff line number Diff line
@@ -11,21 +11,29 @@
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()

    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))
@@ -37,6 +45,7 @@ if __name__ == '__main__':
    print("Writing the monitor into the directory %s" % monitor.name)
    monitor.print_files()
    print("Almost done, checklist")
    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())
+63 −16
Original line number Diff line number Diff line
@@ -19,14 +19,29 @@ class dot2k(Dot2c):
    monitor_type = "per_cpu"

    def __init__(self, file_path, MonitorType, extra_params={}):
        self.container = extra_params.get("container")
        self.parent = extra_params.get("parent")
        self.__fill_rv_templates_dir()

        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.__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")
        self.kconfig = self.__read_file(self.monitor_templates_dir + "Kconfig")
@@ -105,6 +120,14 @@ class dot2k(Dot2c):
    def fill_monitor_type(self):
        return self.monitor_type.upper()

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

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

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

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

        return main_c

@@ -216,6 +243,14 @@ class dot2k(Dot2c):
        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()
@@ -233,12 +268,19 @@ class dot2k(Dot2c):
    def fill_kconfig(self):
        kconfig = self.kconfig
        monitor_class_type = self.fill_monitor_class_type()
        monitor_deps = self.fill_monitor_deps()
        kconfig = kconfig.replace("%%MODEL_NAME%%", self.name)
        kconfig = kconfig.replace("%%MODEL_NAME_UP%%", self.name.upper())
        kconfig = kconfig.replace("%%MONITOR_CLASS_TYPE%%", monitor_class_type)
        kconfig = kconfig.replace("%%DESCRIPTION%%", self.description)
        kconfig = kconfig.replace("%%MONITOR_DEPS%%", monitor_deps)
        return kconfig

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

    def __patch_file(self, file, marker, line):
        file_to_patch = os.path.join(self.rv_dir, file)
        content = self.__read_file(file_to_patch)
@@ -324,13 +366,18 @@ obj-$(CONFIG_RV_MON_%s) += monitors/%s/%s.o

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

        self.__create_directory()

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

        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)

+1 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@
#
config RV_MON_%%MODEL_NAME_UP%%
	depends on RV
%%MONITOR_DEPS%%
	select %%MONITOR_CLASS_TYPE%%
	bool "%%MODEL_NAME%% monitor"
	help
+2 −2
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@
 * #include <trace/events/sched.h>
 */
#include <rv_trace.h>

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

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

+38 −0
Original line number Diff line number Diff line
// 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%%");
Loading