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

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: Gabriele Monaco <gmonaco@redhat.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

authored by

Gabriele Monaco and committed by
Steven Rostedt (Google)
2334cf7d eba321a1

+124 -26
+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())
+62 -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 ··· 243 216 buff.append(" TP_ARGS(%s)" % tp_args_c) 244 217 return self.__buff_to_string(buff) 245 218 219 + def fill_monitor_deps(self): 220 + buff = [] 221 + buff.append(" # XXX: add dependencies if there") 222 + if self.parent: 223 + buff.append(" depends on RV_MON_%s" % self.parent.upper()) 224 + buff.append(" default y") 225 + return self.__buff_to_string(buff) 226 + 246 227 def fill_trace_h(self): 247 228 trace_h = self.trace_h 248 229 monitor_class = self.fill_monitor_class() ··· 268 233 def fill_kconfig(self): 269 234 kconfig = self.kconfig 270 235 monitor_class_type = self.fill_monitor_class_type() 236 + monitor_deps = self.fill_monitor_deps() 271 237 kconfig = kconfig.replace("%%MODEL_NAME%%", self.name) 272 238 kconfig = kconfig.replace("%%MODEL_NAME_UP%%", self.name.upper()) 273 239 kconfig = kconfig.replace("%%MONITOR_CLASS_TYPE%%", monitor_class_type) 274 240 kconfig = kconfig.replace("%%DESCRIPTION%%", self.description) 241 + kconfig = kconfig.replace("%%MONITOR_DEPS%%", monitor_deps) 275 242 return kconfig 243 + 244 + def fill_main_container_h(self): 245 + main_h = self.main_h 246 + main_h = main_h.replace("%%MODEL_NAME%%", self.name) 247 + return main_h 276 248 277 249 def __patch_file(self, file, marker, line): 278 250 file_to_patch = os.path.join(self.rv_dir, file) ··· 366 324 367 325 def print_files(self): 368 326 main_c = self.fill_main_c() 369 - model_h = self.fill_model_h() 370 327 371 328 self.__create_directory() 372 329 373 330 path = "%s.c" % self.name 374 331 self.__create_file(path, main_c) 375 332 376 - path = "%s.h" % self.name 377 - self.__create_file(path, model_h) 333 + if self.container: 334 + main_h = self.fill_main_container_h() 335 + path = "%s.h" % self.name 336 + self.__create_file(path, main_h) 337 + else: 338 + model_h = self.fill_model_h() 339 + path = "%s.h" % self.name 340 + self.__create_file(path, model_h) 378 341 379 - trace_h = self.fill_trace_h() 380 - path = "%s_trace.h" % self.name 381 - self.__create_file(path, trace_h) 342 + trace_h = self.fill_trace_h() 343 + path = "%s_trace.h" % self.name 344 + self.__create_file(path, trace_h) 382 345 383 346 kconfig = self.fill_kconfig() 384 347 self.__create_file("Kconfig", kconfig)
+1
tools/verification/dot2/dot2k_templates/Kconfig
··· 2 2 # 3 3 config RV_MON_%%MODEL_NAME_UP%% 4 4 depends on RV 5 + %%MONITOR_DEPS%% 5 6 select %%MONITOR_CLASS_TYPE%% 6 7 bool "%%MODEL_NAME%% monitor" 7 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%%;