rv: tools/rtla: Updates for 6.14
- Add a test suite to test the tool Add a small test suite that can be used to test rtla's basic features to at least have something to test when applying changes. - Automate manual steps in monitor creation While creating a new monitor in RV, besides generating code from dot2k, there are a few manual steps which can be tedious and error prone, like adding the tracepoints, makefile lines and kconfig, or selecting events that start the monitor in the initial state. Updates were made to try and automate as much as possible among those steps to make creating a new RV monitor much quicker. It is still requires to select proper tracepoints, this step is harder to automate in a general way and, in several cases, would still need user intervention. - Have rtla timerlat hist and top set OSNOISE_WORKLOAD flag Have both rtla-timerlat-hist and rtla-timerlat-top set OSNOISE_WORKLOAD to the proper value ("on" when running with -k, "off" when running with -u) every time the option is available instead of setting it only when running with -u. This prevents rtla timerlat -k from giving no results when NO_OSNOISE_WORKLOAD is set, either manually or by an abnormally exited earlier run of rtla timerlat -u. - Stop rtla timerlat on signal properly when overloaded There is an issue where if rtla is run on machines with a high number of CPUs (100+), timerlat can generate more samples than rtla is able to process via tracefs_iterate_raw_events. This is especially common when the interval is set to 100us (rteval and cyclictest default) as opposed to the rtla default of 1000us, but also happens with the rtla default. Currently, this leads to rtla hanging and having to be terminated with SIGTERM. SIGINT setting stop_tracing is not enough, since more and more events are coming and tracefs_iterate_raw_events never exits. To fix this: Stop the timerlat tracer on SIGINT/SIGALRM to ensure no more events are generated when rtla is supposed to exit. Also on receiving SIGINT/SIGALRM twice, abort iteration immediately with tracefs_iterate_stop, making rtla exit right away instead of waiting for all events to be processed. - Account for missed events Due to tracefs buffer overflow, it can happen that rtla misses events, making the tracing results inaccurate. Count both the number of missed events and the total number of processed events, and display missed events as well as their percentage. The numbers are displayed for both osnoise and timerlat, even though for the earlier, missed events are generally not expected. For hist, the number is displayed at the end of the run; for top, it is displayed on each printing of the top table. - Changes to make osnoise more robust There was a dependency in the code that the first field of the osnoise_tool structure was the trace field. If that that ever changed, then the code work break. Change the code to encapsulate this dependency where the code that uses the structure does not have this dependency. -----BEGIN PGP SIGNATURE----- iIoEABYIADIWIQRRSw7ePDh/lE+zeZMp5XQQmuv6qgUCZ5UQ4BQccm9zdGVkdEBn b29kbWlzLm9yZwAKCRAp5XQQmuv6qktFAQD2px6MyoOVTssB5Iw3aTWGUfTFoDEc bfng5JsBxlVJkQEA+2UUvP8FJlLTOQvVEwJiscX7CCJxl5bYkV6GWuGRxQU= =h//9 -----END PGP SIGNATURE----- Merge tag 'trace-tools-v6.14' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace Pull rv and tools/rtla updates from Steven Rostedt: - Add a test suite to test the tool Add a small test suite that can be used to test rtla's basic features to at least have something to test when applying changes. - Automate manual steps in monitor creation While creating a new monitor in RV, besides generating code from dot2k, there are a few manual steps which can be tedious and error prone, like adding the tracepoints, makefile lines and kconfig, or selecting events that start the monitor in the initial state. Updates were made to try and automate as much as possible among those steps to make creating a new RV monitor much quicker. It is still requires to select proper tracepoints, this step is harder to automate in a general way and, in several cases, would still need user intervention. - Have rtla timerlat hist and top set OSNOISE_WORKLOAD flag Have both rtla-timerlat-hist and rtla-timerlat-top set OSNOISE_WORKLOAD to the proper value ("on" when running with -k, "off" when running with -u) every time the option is available instead of setting it only when running with -u. This prevents rtla timerlat -k from giving no results when NO_OSNOISE_WORKLOAD is set, either manually or by an abnormally exited earlier run of rtla timerlat -u. - Stop rtla timerlat on signal properly when overloaded There is an issue where if rtla is run on machines with a high number of CPUs (100+), timerlat can generate more samples than rtla is able to process via tracefs_iterate_raw_events. This is especially common when the interval is set to 100us (rteval and cyclictest default) as opposed to the rtla default of 1000us, but also happens with the rtla default. Currently, this leads to rtla hanging and having to be terminated with SIGTERM. SIGINT setting stop_tracing is not enough, since more and more events are coming and tracefs_iterate_raw_events never exits. To fix this: Stop the timerlat tracer on SIGINT/SIGALRM to ensure no more events are generated when rtla is supposed to exit. Also on receiving SIGINT/SIGALRM twice, abort iteration immediately with tracefs_iterate_stop, making rtla exit right away instead of waiting for all events to be processed. - Account for missed events Due to tracefs buffer overflow, it can happen that rtla misses events, making the tracing results inaccurate. Count both the number of missed events and the total number of processed events, and display missed events as well as their percentage. The numbers are displayed for both osnoise and timerlat, even though for the earlier, missed events are generally not expected. For hist, the number is displayed at the end of the run; for top, it is displayed on each printing of the top table. - Changes to make osnoise more robust There was a dependency in the code that the first field of the osnoise_tool structure was the trace field. If that that ever changed, then the code work break. Change the code to encapsulate this dependency where the code that uses the structure does not have this dependency. * tag 'trace-tools-v6.14' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: (22 commits) rtla: Report missed event count rtla: Add function to report missed events rtla: Count all processed events rtla: Count missed trace events tools/rtla: Add osnoise_trace_is_off() rtla/timerlat_top: Set OSNOISE_WORKLOAD for kernel threads rtla/timerlat_hist: Set OSNOISE_WORKLOAD for kernel threads rtla/osnoise: Distinguish missing workload option rtla/timerlat_top: Abort event processing on second signal rtla/timerlat_hist: Abort event processing on second signal rtla/timerlat_top: Stop timerlat tracer on signal rtla/timerlat_hist: Stop timerlat tracer on signal rtla: Add trace_instance_stop tools/rtla: Add basic test suite verification/dot2k: Implement event type detection verification/dot2k: Auto patch current kernel source verification/dot2k: Simplify manual steps in monitor creation rv: Simplify manual steps in monitor creation verification/dot2k: Add support for name and description options verification/dot2k: More robust template variables ...
This commit is contained in:
commit
40648d246f
33 changed files with 690 additions and 405 deletions
kernel/trace/rv
tools
|
@ -25,30 +25,9 @@ menuconfig RV
|
|||
For further information, see:
|
||||
Documentation/trace/rv/runtime-verification.rst
|
||||
|
||||
config RV_MON_WIP
|
||||
depends on RV
|
||||
depends on PREEMPT_TRACER
|
||||
select DA_MON_EVENTS_IMPLICIT
|
||||
bool "wip monitor"
|
||||
help
|
||||
Enable wip (wakeup in preemptive) sample monitor that illustrates
|
||||
the usage of per-cpu monitors, and one limitation of the
|
||||
preempt_disable/enable events.
|
||||
|
||||
For further information, see:
|
||||
Documentation/trace/rv/monitor_wip.rst
|
||||
|
||||
config RV_MON_WWNR
|
||||
depends on RV
|
||||
select DA_MON_EVENTS_ID
|
||||
bool "wwnr monitor"
|
||||
help
|
||||
Enable wwnr (wakeup while not running) sample monitor, this is a
|
||||
sample monitor that illustrates the usage of per-task monitor.
|
||||
The model is borken on purpose: it serves to test reactors.
|
||||
|
||||
For further information, see:
|
||||
Documentation/trace/rv/monitor_wwnr.rst
|
||||
source "kernel/trace/rv/monitors/wip/Kconfig"
|
||||
source "kernel/trace/rv/monitors/wwnr/Kconfig"
|
||||
# Add new monitors here
|
||||
|
||||
config RV_REACTORS
|
||||
bool "Runtime verification reactors"
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
ccflags-y += -I $(src) # needed for trace events
|
||||
|
||||
obj-$(CONFIG_RV) += rv.o
|
||||
obj-$(CONFIG_RV_MON_WIP) += monitors/wip/wip.o
|
||||
obj-$(CONFIG_RV_MON_WWNR) += monitors/wwnr/wwnr.o
|
||||
# Add new monitors here
|
||||
obj-$(CONFIG_RV_REACTORS) += rv_reactors.o
|
||||
obj-$(CONFIG_RV_REACT_PRINTK) += reactor_printk.o
|
||||
obj-$(CONFIG_RV_REACT_PANIC) += reactor_panic.o
|
||||
|
|
12
kernel/trace/rv/monitors/wip/Kconfig
Normal file
12
kernel/trace/rv/monitors/wip/Kconfig
Normal file
|
@ -0,0 +1,12 @@
|
|||
config RV_MON_WIP
|
||||
depends on RV
|
||||
depends on PREEMPT_TRACER
|
||||
select DA_MON_EVENTS_IMPLICIT
|
||||
bool "wip monitor"
|
||||
help
|
||||
Enable wip (wakeup in preemptive) sample monitor that illustrates
|
||||
the usage of per-cpu monitors, and one limitation of the
|
||||
preempt_disable/enable events.
|
||||
|
||||
For further information, see:
|
||||
Documentation/trace/rv/monitor_wip.rst
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#define MODULE_NAME "wip"
|
||||
|
||||
#include <trace/events/rv.h>
|
||||
#include <rv_trace.h>
|
||||
#include <trace/events/sched.h>
|
||||
#include <trace/events/preemptirq.h>
|
||||
|
||||
|
|
15
kernel/trace/rv/monitors/wip/wip_trace.h
Normal file
15
kernel/trace/rv/monitors/wip/wip_trace.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
/*
|
||||
* Snippet to be included in rv_trace.h
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_RV_MON_WIP
|
||||
DEFINE_EVENT(event_da_monitor, event_wip,
|
||||
TP_PROTO(char *state, char *event, char *next_state, bool final_state),
|
||||
TP_ARGS(state, event, next_state, final_state));
|
||||
|
||||
DEFINE_EVENT(error_da_monitor, error_wip,
|
||||
TP_PROTO(char *state, char *event),
|
||||
TP_ARGS(state, event));
|
||||
#endif /* CONFIG_RV_MON_WIP */
|
11
kernel/trace/rv/monitors/wwnr/Kconfig
Normal file
11
kernel/trace/rv/monitors/wwnr/Kconfig
Normal file
|
@ -0,0 +1,11 @@
|
|||
config RV_MON_WWNR
|
||||
depends on RV
|
||||
select DA_MON_EVENTS_ID
|
||||
bool "wwnr monitor"
|
||||
help
|
||||
Enable wwnr (wakeup while not running) sample monitor, this is a
|
||||
sample monitor that illustrates the usage of per-task monitor.
|
||||
The model is borken on purpose: it serves to test reactors.
|
||||
|
||||
For further information, see:
|
||||
Documentation/trace/rv/monitor_wwnr.rst
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#define MODULE_NAME "wwnr"
|
||||
|
||||
#include <trace/events/rv.h>
|
||||
#include <rv_trace.h>
|
||||
#include <trace/events/sched.h>
|
||||
|
||||
#include "wwnr.h"
|
||||
|
|
16
kernel/trace/rv/monitors/wwnr/wwnr_trace.h
Normal file
16
kernel/trace/rv/monitors/wwnr/wwnr_trace.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
/*
|
||||
* Snippet to be included in rv_trace.h
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_RV_MON_WWNR
|
||||
/* id is the pid of the task */
|
||||
DEFINE_EVENT(event_da_monitor_id, event_wwnr,
|
||||
TP_PROTO(int id, char *state, char *event, char *next_state, bool final_state),
|
||||
TP_ARGS(id, state, event, next_state, final_state));
|
||||
|
||||
DEFINE_EVENT(error_da_monitor_id, error_wwnr,
|
||||
TP_PROTO(int id, char *state, char *event),
|
||||
TP_ARGS(id, state, event));
|
||||
#endif /* CONFIG_RV_MON_WWNR */
|
|
@ -145,7 +145,7 @@
|
|||
|
||||
#ifdef CONFIG_DA_MON_EVENTS
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/rv.h>
|
||||
#include <rv_trace.h>
|
||||
#endif
|
||||
|
||||
#include "rv.h"
|
||||
|
|
|
@ -57,15 +57,9 @@ DECLARE_EVENT_CLASS(error_da_monitor,
|
|||
__entry->state)
|
||||
);
|
||||
|
||||
#ifdef CONFIG_RV_MON_WIP
|
||||
DEFINE_EVENT(event_da_monitor, event_wip,
|
||||
TP_PROTO(char *state, char *event, char *next_state, bool final_state),
|
||||
TP_ARGS(state, event, next_state, final_state));
|
||||
#include <monitors/wip/wip_trace.h>
|
||||
// Add new monitors based on CONFIG_DA_MON_EVENTS_IMPLICIT here
|
||||
|
||||
DEFINE_EVENT(error_da_monitor, error_wip,
|
||||
TP_PROTO(char *state, char *event),
|
||||
TP_ARGS(state, event));
|
||||
#endif /* CONFIG_RV_MON_WIP */
|
||||
#endif /* CONFIG_DA_MON_EVENTS_IMPLICIT */
|
||||
|
||||
#ifdef CONFIG_DA_MON_EVENTS_ID
|
||||
|
@ -123,20 +117,14 @@ DECLARE_EVENT_CLASS(error_da_monitor_id,
|
|||
__entry->state)
|
||||
);
|
||||
|
||||
#ifdef CONFIG_RV_MON_WWNR
|
||||
/* id is the pid of the task */
|
||||
DEFINE_EVENT(event_da_monitor_id, event_wwnr,
|
||||
TP_PROTO(int id, char *state, char *event, char *next_state, bool final_state),
|
||||
TP_ARGS(id, state, event, next_state, final_state));
|
||||
|
||||
DEFINE_EVENT(error_da_monitor_id, error_wwnr,
|
||||
TP_PROTO(int id, char *state, char *event),
|
||||
TP_ARGS(id, state, event));
|
||||
#endif /* CONFIG_RV_MON_WWNR */
|
||||
#include <monitors/wwnr/wwnr_trace.h>
|
||||
// Add new monitors based on CONFIG_DA_MON_EVENTS_ID here
|
||||
|
||||
#endif /* CONFIG_DA_MON_EVENTS_ID */
|
||||
#endif /* _TRACE_RV_H */
|
||||
|
||||
/* This part ust be outside protection */
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
#define TRACE_INCLUDE_PATH .
|
||||
#define TRACE_INCLUDE_FILE rv_trace
|
||||
#include <trace/define_trace.h>
|
|
@ -85,4 +85,6 @@ clean: doc_clean fixdep-clean
|
|||
$(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
|
||||
$(Q)rm -f rtla rtla-static fixdep FEATURE-DUMP rtla-*
|
||||
$(Q)rm -rf feature
|
||||
.PHONY: FORCE clean
|
||||
check: $(RTLA)
|
||||
RTLA=$(RTLA) prove -o -f tests/
|
||||
.PHONY: FORCE clean check
|
||||
|
|
|
@ -867,7 +867,7 @@ int osnoise_set_workload(struct osnoise_context *context, bool onoff)
|
|||
|
||||
retval = osnoise_options_set_option("OSNOISE_WORKLOAD", onoff);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
return -2;
|
||||
|
||||
context->opt_workload = onoff;
|
||||
|
||||
|
@ -1079,6 +1079,42 @@ out_err:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
bool osnoise_trace_is_off(struct osnoise_tool *tool, struct osnoise_tool *record)
|
||||
{
|
||||
/*
|
||||
* The tool instance is always present, it is the one used to collect
|
||||
* data.
|
||||
*/
|
||||
if (!tracefs_trace_is_on(tool->trace.inst))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* The trace record instance is only enabled when -t is set. IOW, when the system
|
||||
* is tracing.
|
||||
*/
|
||||
return record && !tracefs_trace_is_on(record->trace.inst);
|
||||
}
|
||||
|
||||
/*
|
||||
* osnoise_report_missed_events - report number of events dropped by trace
|
||||
* buffer
|
||||
*/
|
||||
void
|
||||
osnoise_report_missed_events(struct osnoise_tool *tool)
|
||||
{
|
||||
unsigned long long total_events;
|
||||
|
||||
if (tool->trace.missed_events == UINT64_MAX)
|
||||
printf("unknown number of events missed, results might not be accurate\n");
|
||||
else if (tool->trace.missed_events > 0) {
|
||||
total_events = tool->trace.processed_events + tool->trace.missed_events;
|
||||
|
||||
printf("%lld (%.2f%%) events missed, results might not be accurate\n",
|
||||
tool->trace.missed_events,
|
||||
(double) tool->trace.missed_events / total_events * 100.0);
|
||||
}
|
||||
}
|
||||
|
||||
static void osnoise_usage(int err)
|
||||
{
|
||||
int i;
|
||||
|
|
|
@ -104,6 +104,8 @@ struct osnoise_tool {
|
|||
void osnoise_destroy_tool(struct osnoise_tool *top);
|
||||
struct osnoise_tool *osnoise_init_tool(char *tool_name);
|
||||
struct osnoise_tool *osnoise_init_trace_tool(char *tracer);
|
||||
void osnoise_report_missed_events(struct osnoise_tool *tool);
|
||||
bool osnoise_trace_is_off(struct osnoise_tool *tool, struct osnoise_tool *record);
|
||||
|
||||
int osnoise_hist_main(int argc, char *argv[]);
|
||||
int osnoise_top_main(int argc, char **argv);
|
||||
|
|
|
@ -440,6 +440,7 @@ osnoise_print_stats(struct osnoise_hist_params *params, struct osnoise_tool *too
|
|||
trace_seq_reset(trace->seq);
|
||||
|
||||
osnoise_print_summary(params, trace, data);
|
||||
osnoise_report_missed_events(tool);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -970,7 +971,7 @@ int osnoise_hist_main(int argc, char *argv[])
|
|||
goto out_hist;
|
||||
}
|
||||
|
||||
if (trace_is_off(&tool->trace, &record->trace))
|
||||
if (osnoise_trace_is_off(tool, record))
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -980,7 +981,7 @@ int osnoise_hist_main(int argc, char *argv[])
|
|||
|
||||
return_value = 0;
|
||||
|
||||
if (trace_is_off(&tool->trace, &record->trace)) {
|
||||
if (osnoise_trace_is_off(tool, record)) {
|
||||
printf("rtla osnoise hit stop tracing\n");
|
||||
if (params->trace_output) {
|
||||
printf(" Saving trace to %s\n", params->trace_output);
|
||||
|
|
|
@ -280,6 +280,7 @@ osnoise_print_stats(struct osnoise_top_params *params, struct osnoise_tool *top)
|
|||
|
||||
trace_seq_do_printf(trace->seq);
|
||||
trace_seq_reset(trace->seq);
|
||||
osnoise_report_missed_events(top);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -801,7 +802,7 @@ int osnoise_top_main(int argc, char **argv)
|
|||
if (!params->quiet)
|
||||
osnoise_print_stats(params, tool);
|
||||
|
||||
if (trace_is_off(&tool->trace, &record->trace))
|
||||
if (osnoise_trace_is_off(tool, record))
|
||||
break;
|
||||
|
||||
}
|
||||
|
@ -810,7 +811,7 @@ int osnoise_top_main(int argc, char **argv)
|
|||
|
||||
return_value = 0;
|
||||
|
||||
if (trace_is_off(&tool->trace, &record->trace)) {
|
||||
if (osnoise_trace_is_off(tool, record)) {
|
||||
printf("osnoise hit stop tracing\n");
|
||||
if (params->trace_output) {
|
||||
printf(" Saving trace to %s\n", params->trace_output);
|
||||
|
|
|
@ -656,6 +656,7 @@ timerlat_print_stats(struct timerlat_hist_params *params, struct osnoise_tool *t
|
|||
|
||||
timerlat_print_summary(params, trace, data);
|
||||
timerlat_print_stats_all(params, trace, data);
|
||||
osnoise_report_missed_events(tool);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1100,13 +1101,16 @@ timerlat_hist_apply_config(struct osnoise_tool *tool, struct timerlat_hist_param
|
|||
}
|
||||
}
|
||||
|
||||
if (params->user_hist) {
|
||||
retval = osnoise_set_workload(tool->context, 0);
|
||||
if (retval) {
|
||||
/*
|
||||
* Set workload according to type of thread if the kernel supports it.
|
||||
* On kernels without support, user threads will have already failed
|
||||
* on missing timerlat_fd, and kernel threads do not need it.
|
||||
*/
|
||||
retval = osnoise_set_workload(tool->context, params->kernel_workload);
|
||||
if (retval < -1) {
|
||||
err_msg("Failed to set OSNOISE_WORKLOAD option\n");
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -1146,9 +1150,20 @@ out_err:
|
|||
}
|
||||
|
||||
static int stop_tracing;
|
||||
static struct trace_instance *hist_inst = NULL;
|
||||
static void stop_hist(int sig)
|
||||
{
|
||||
if (stop_tracing) {
|
||||
/*
|
||||
* Stop requested twice in a row; abort event processing and
|
||||
* exit immediately
|
||||
*/
|
||||
tracefs_iterate_stop(hist_inst->inst);
|
||||
return;
|
||||
}
|
||||
stop_tracing = 1;
|
||||
if (hist_inst)
|
||||
trace_instance_stop(hist_inst);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1195,6 +1210,12 @@ int timerlat_hist_main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
trace = &tool->trace;
|
||||
/*
|
||||
* Save trace instance into global variable so that SIGINT can stop
|
||||
* the timerlat tracer.
|
||||
* Otherwise, rtla could loop indefinitely when overloaded.
|
||||
*/
|
||||
hist_inst = trace;
|
||||
|
||||
retval = enable_timerlat(trace);
|
||||
if (retval) {
|
||||
|
@ -1342,7 +1363,7 @@ int timerlat_hist_main(int argc, char *argv[])
|
|||
goto out_hist;
|
||||
}
|
||||
|
||||
if (trace_is_off(&tool->trace, &record->trace))
|
||||
if (osnoise_trace_is_off(tool, record))
|
||||
break;
|
||||
|
||||
/* is there still any user-threads ? */
|
||||
|
@ -1363,7 +1384,7 @@ int timerlat_hist_main(int argc, char *argv[])
|
|||
|
||||
return_value = 0;
|
||||
|
||||
if (trace_is_off(&tool->trace, &record->trace)) {
|
||||
if (osnoise_trace_is_off(tool, record) && !stop_tracing) {
|
||||
printf("rtla timerlat hit stop tracing\n");
|
||||
|
||||
if (!params->no_aa)
|
||||
|
|
|
@ -435,6 +435,7 @@ timerlat_print_stats(struct timerlat_top_params *params, struct osnoise_tool *to
|
|||
|
||||
trace_seq_do_printf(trace->seq);
|
||||
trace_seq_reset(trace->seq);
|
||||
osnoise_report_missed_events(top);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -851,13 +852,16 @@ timerlat_top_apply_config(struct osnoise_tool *top, struct timerlat_top_params *
|
|||
}
|
||||
}
|
||||
|
||||
if (params->user_top) {
|
||||
retval = osnoise_set_workload(top->context, 0);
|
||||
if (retval) {
|
||||
/*
|
||||
* Set workload according to type of thread if the kernel supports it.
|
||||
* On kernels without support, user threads will have already failed
|
||||
* on missing timerlat_fd, and kernel threads do not need it.
|
||||
*/
|
||||
retval = osnoise_set_workload(top->context, params->kernel_workload);
|
||||
if (retval < -1) {
|
||||
err_msg("Failed to set OSNOISE_WORKLOAD option\n");
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
|
||||
if (isatty(STDOUT_FILENO) && !params->quiet)
|
||||
params->pretty_output = 1;
|
||||
|
@ -900,9 +904,20 @@ out_err:
|
|||
}
|
||||
|
||||
static int stop_tracing;
|
||||
static struct trace_instance *top_inst = NULL;
|
||||
static void stop_top(int sig)
|
||||
{
|
||||
if (stop_tracing) {
|
||||
/*
|
||||
* Stop requested twice in a row; abort event processing and
|
||||
* exit immediately
|
||||
*/
|
||||
tracefs_iterate_stop(top_inst->inst);
|
||||
return;
|
||||
}
|
||||
stop_tracing = 1;
|
||||
if (top_inst)
|
||||
trace_instance_stop(top_inst);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -950,6 +965,13 @@ int timerlat_top_main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
trace = &top->trace;
|
||||
/*
|
||||
* Save trace instance into global variable so that SIGINT can stop
|
||||
* the timerlat tracer.
|
||||
* Otherwise, rtla could loop indefinitely when overloaded.
|
||||
*/
|
||||
top_inst = trace;
|
||||
|
||||
|
||||
retval = enable_timerlat(trace);
|
||||
if (retval) {
|
||||
|
@ -1093,7 +1115,7 @@ int timerlat_top_main(int argc, char *argv[])
|
|||
while (!stop_tracing) {
|
||||
sleep(params->sleep_time);
|
||||
|
||||
if (params->aa_only && !trace_is_off(&top->trace, &record->trace))
|
||||
if (params->aa_only && !osnoise_trace_is_off(top, record))
|
||||
continue;
|
||||
|
||||
retval = tracefs_iterate_raw_events(trace->tep,
|
||||
|
@ -1110,7 +1132,7 @@ int timerlat_top_main(int argc, char *argv[])
|
|||
if (!params->quiet)
|
||||
timerlat_print_stats(params, top);
|
||||
|
||||
if (trace_is_off(&top->trace, &record->trace))
|
||||
if (osnoise_trace_is_off(top, record))
|
||||
break;
|
||||
|
||||
/* is there still any user-threads ? */
|
||||
|
@ -1131,7 +1153,7 @@ int timerlat_top_main(int argc, char *argv[])
|
|||
|
||||
return_value = 0;
|
||||
|
||||
if (trace_is_off(&top->trace, &record->trace)) {
|
||||
if (osnoise_trace_is_off(top, record) && !stop_tracing) {
|
||||
printf("rtla timerlat hit stop tracing\n");
|
||||
|
||||
if (!params->no_aa)
|
||||
|
|
|
@ -118,6 +118,8 @@ collect_registered_events(struct tep_event *event, struct tep_record *record,
|
|||
struct trace_instance *trace = context;
|
||||
struct trace_seq *s = trace->seq;
|
||||
|
||||
trace->processed_events++;
|
||||
|
||||
if (!event->handler)
|
||||
return 0;
|
||||
|
||||
|
@ -126,6 +128,31 @@ collect_registered_events(struct tep_event *event, struct tep_record *record,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* collect_missed_events - record number of missed events
|
||||
*
|
||||
* If rtla cannot keep up with events generated by tracer, events are going
|
||||
* to fall out of the ring buffer.
|
||||
* Collect how many events were missed so it can be reported to the user.
|
||||
*/
|
||||
static int
|
||||
collect_missed_events(struct tep_event *event, struct tep_record *record,
|
||||
int cpu, void *context)
|
||||
{
|
||||
struct trace_instance *trace = context;
|
||||
|
||||
if (trace->missed_events == UINT64_MAX)
|
||||
return 0;
|
||||
|
||||
if (record->missed_events > 0)
|
||||
trace->missed_events += record->missed_events;
|
||||
else
|
||||
/* Events missed but no data on how many */
|
||||
trace->missed_events = UINT64_MAX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* trace_instance_destroy - destroy and free a rtla trace instance
|
||||
*/
|
||||
|
@ -181,6 +208,17 @@ int trace_instance_init(struct trace_instance *trace, char *tool_name)
|
|||
*/
|
||||
tracefs_trace_off(trace->inst);
|
||||
|
||||
/*
|
||||
* Collect the number of events missed due to tracefs buffer
|
||||
* overflow.
|
||||
*/
|
||||
trace->missed_events = 0;
|
||||
tracefs_follow_missed_events(trace->inst,
|
||||
collect_missed_events,
|
||||
trace);
|
||||
|
||||
trace->processed_events = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
|
@ -196,6 +234,14 @@ int trace_instance_start(struct trace_instance *trace)
|
|||
return tracefs_trace_on(trace->inst);
|
||||
}
|
||||
|
||||
/*
|
||||
* trace_instance_stop - stop tracing a given rtla instance
|
||||
*/
|
||||
int trace_instance_stop(struct trace_instance *trace)
|
||||
{
|
||||
return tracefs_trace_off(trace->inst);
|
||||
}
|
||||
|
||||
/*
|
||||
* trace_events_free - free a list of trace events
|
||||
*/
|
||||
|
@ -522,25 +568,6 @@ void trace_events_destroy(struct trace_instance *instance,
|
|||
trace_events_free(events);
|
||||
}
|
||||
|
||||
int trace_is_off(struct trace_instance *tool, struct trace_instance *trace)
|
||||
{
|
||||
/*
|
||||
* The tool instance is always present, it is the one used to collect
|
||||
* data.
|
||||
*/
|
||||
if (!tracefs_trace_is_on(tool->inst))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* The trace instance is only enabled when -t is set. IOW, when the system
|
||||
* is tracing.
|
||||
*/
|
||||
if (trace && !tracefs_trace_is_on(trace->inst))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* trace_set_buffer_size - set the per-cpu tracing buffer size.
|
||||
*/
|
||||
|
|
|
@ -17,10 +17,13 @@ struct trace_instance {
|
|||
struct tracefs_instance *inst;
|
||||
struct tep_handle *tep;
|
||||
struct trace_seq *seq;
|
||||
unsigned long long missed_events;
|
||||
unsigned long long processed_events;
|
||||
};
|
||||
|
||||
int trace_instance_init(struct trace_instance *trace, char *tool_name);
|
||||
int trace_instance_start(struct trace_instance *trace);
|
||||
int trace_instance_stop(struct trace_instance *trace);
|
||||
void trace_instance_destroy(struct trace_instance *trace);
|
||||
|
||||
struct trace_seq *get_trace_seq(void);
|
||||
|
@ -47,5 +50,4 @@ int trace_events_enable(struct trace_instance *instance,
|
|||
|
||||
int trace_event_add_filter(struct trace_events *event, char *filter);
|
||||
int trace_event_add_trigger(struct trace_events *event, char *trigger);
|
||||
int trace_is_off(struct trace_instance *tool, struct trace_instance *trace);
|
||||
int trace_set_buffer_size(struct trace_instance *trace, int size);
|
||||
|
|
48
tools/tracing/rtla/tests/engine.sh
Normal file
48
tools/tracing/rtla/tests/engine.sh
Normal file
|
@ -0,0 +1,48 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
test_begin() {
|
||||
# Count tests to allow the test harness to double-check if all were
|
||||
# included correctly.
|
||||
ctr=0
|
||||
[ -z "$RTLA" ] && RTLA="./rtla"
|
||||
[ -n "$TEST_COUNT" ] && echo "1..$TEST_COUNT"
|
||||
}
|
||||
|
||||
check() {
|
||||
# Simple check: run rtla with given arguments and test exit code.
|
||||
# If TEST_COUNT is set, run the test. Otherwise, just count.
|
||||
ctr=$(($ctr + 1))
|
||||
if [ -n "$TEST_COUNT" ]
|
||||
then
|
||||
# Run rtla; in case of failure, include its output as comment
|
||||
# in the test results.
|
||||
result=$(stdbuf -oL $TIMEOUT "$RTLA" $2 2>&1); exitcode=$?
|
||||
if [ $exitcode -eq 0 ]
|
||||
then
|
||||
echo "ok $ctr - $1"
|
||||
else
|
||||
echo "not ok $ctr - $1"
|
||||
# Add rtla output and exit code as comments in case of failure
|
||||
echo "$result" | col -b | while read line; do echo "# $line"; done
|
||||
printf "#\n# exit code %s\n" $exitcode
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
set_timeout() {
|
||||
TIMEOUT="timeout -v -k 15s $1"
|
||||
}
|
||||
|
||||
unset_timeout() {
|
||||
unset TIMEOUT
|
||||
}
|
||||
|
||||
test_end() {
|
||||
# If running without TEST_COUNT, tests are not actually run, just
|
||||
# counted. In that case, re-run the test with the correct count.
|
||||
[ -z "$TEST_COUNT" ] && TEST_COUNT=$ctr exec bash $0 || true
|
||||
}
|
||||
|
||||
# Avoid any environmental discrepancies
|
||||
export LC_ALL=C
|
||||
unset_timeout
|
21
tools/tracing/rtla/tests/hwnoise.t
Normal file
21
tools/tracing/rtla/tests/hwnoise.t
Normal file
|
@ -0,0 +1,21 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
source tests/engine.sh
|
||||
test_begin
|
||||
|
||||
set_timeout 2m
|
||||
|
||||
check "verify help page" \
|
||||
"hwnoise --help"
|
||||
check "detect noise higher than one microsecond" \
|
||||
"hwnoise -c 0 -T 1 -d 5s -q"
|
||||
check "set the automatic trace mode" \
|
||||
"hwnoise -a 5 -d 30s"
|
||||
check "set scheduling param to the osnoise tracer threads" \
|
||||
"hwnoise -P F:1 -c 0 -r 900000 -d 1M -q"
|
||||
check "stop the trace if a single sample is higher than 1 us" \
|
||||
"hwnoise -s 1 -T 1 -t -d 30s"
|
||||
check "enable a trace event trigger" \
|
||||
"hwnoise -t -e osnoise:irq_noise trigger=\"hist:key=desc,duration:sort=desc,duration:vals=hitcount\" -d 1m"
|
||||
|
||||
test_end
|
19
tools/tracing/rtla/tests/osnoise.t
Normal file
19
tools/tracing/rtla/tests/osnoise.t
Normal file
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
source tests/engine.sh
|
||||
test_begin
|
||||
|
||||
set_timeout 2m
|
||||
|
||||
check "verify help page" \
|
||||
"osnoise --help"
|
||||
check "verify the --priority/-P param" \
|
||||
"osnoise top -P F:1 -c 0 -r 900000 -d 1M -q"
|
||||
check "verify the --stop/-s param" \
|
||||
"osnoise top -s 30 -T 1 -t"
|
||||
check "verify the --trace param" \
|
||||
"osnoise hist -s 30 -T 1 -t"
|
||||
check "verify the --entries/-E param" \
|
||||
"osnoise hist -P F:1 -c 0 -r 900000 -d 1M -b 10 -E 25"
|
||||
|
||||
test_end
|
27
tools/tracing/rtla/tests/timerlat.t
Normal file
27
tools/tracing/rtla/tests/timerlat.t
Normal file
|
@ -0,0 +1,27 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
source tests/engine.sh
|
||||
test_begin
|
||||
|
||||
set_timeout 2m
|
||||
|
||||
check "verify help page" \
|
||||
"timerlat --help"
|
||||
check "verify -s/--stack" \
|
||||
"timerlat top -s 3 -T 10 -t"
|
||||
check "verify -P/--priority" \
|
||||
"timerlat top -P F:1 -c 0 -d 1M -q"
|
||||
check "test in nanoseconds" \
|
||||
"timerlat top -i 2 -c 0 -n -d 30s"
|
||||
check "set the automatic trace mode" \
|
||||
"timerlat top -a 5 --dump-tasks"
|
||||
check "print the auto-analysis if hits the stop tracing condition" \
|
||||
"timerlat top --aa-only 5"
|
||||
check "disable auto-analysis" \
|
||||
"timerlat top -s 3 -T 10 -t --no-aa"
|
||||
check "verify -c/--cpus" \
|
||||
"timerlat hist -c 0 -d 30s"
|
||||
check "hist test in nanoseconds" \
|
||||
"timerlat hist -i 2 -c 0 -n -d 30s"
|
||||
|
||||
test_end
|
|
@ -19,13 +19,14 @@ class Automata:
|
|||
|
||||
invalid_state_str = "INVALID_STATE"
|
||||
|
||||
def __init__(self, file_path):
|
||||
def __init__(self, file_path, model_name=None):
|
||||
self.__dot_path = file_path
|
||||
self.name = self.__get_model_name()
|
||||
self.name = model_name or self.__get_model_name()
|
||||
self.__dot_lines = self.__open_dot()
|
||||
self.states, self.initial_state, self.final_states = self.__get_state_variables()
|
||||
self.events = self.__get_event_variables()
|
||||
self.function = self.__create_matrix()
|
||||
self.events_start, self.events_start_run = self.__store_init_events()
|
||||
|
||||
def __get_model_name(self):
|
||||
basename = ntpath.basename(self.__dot_path)
|
||||
|
@ -172,3 +173,34 @@ class Automata:
|
|||
cursor += 1
|
||||
|
||||
return matrix
|
||||
|
||||
def __store_init_events(self):
|
||||
events_start = [False] * len(self.events)
|
||||
events_start_run = [False] * len(self.events)
|
||||
for i, _ in enumerate(self.events):
|
||||
curr_event_will_init = 0
|
||||
curr_event_from_init = False
|
||||
curr_event_used = 0
|
||||
for j, _ in enumerate(self.states):
|
||||
if self.function[j][i] != self.invalid_state_str:
|
||||
curr_event_used += 1
|
||||
if self.function[j][i] == self.initial_state:
|
||||
curr_event_will_init += 1
|
||||
if self.function[0][i] != self.invalid_state_str:
|
||||
curr_event_from_init = True
|
||||
# this event always leads to init
|
||||
if curr_event_will_init and curr_event_used == curr_event_will_init:
|
||||
events_start[i] = True
|
||||
# this event is only called from init
|
||||
if curr_event_from_init and curr_event_used == 1:
|
||||
events_start_run[i] = True
|
||||
return events_start, events_start_run
|
||||
|
||||
def is_start_event(self, event):
|
||||
return self.events_start[self.events.index(event)]
|
||||
|
||||
def is_start_run_event(self, event):
|
||||
# prefer handle_start_event if there
|
||||
if any(self.events_start):
|
||||
return False
|
||||
return self.events_start_run[self.events.index(event)]
|
||||
|
|
|
@ -22,8 +22,8 @@ class Dot2c(Automata):
|
|||
struct_automaton_def = "automaton"
|
||||
var_automaton_def = "aut"
|
||||
|
||||
def __init__(self, file_path):
|
||||
super().__init__(file_path)
|
||||
def __init__(self, file_path, model_name=None):
|
||||
super().__init__(file_path, model_name)
|
||||
self.line_length = 100
|
||||
|
||||
def __buff_to_string(self, buff):
|
||||
|
|
|
@ -21,25 +21,24 @@ if __name__ == '__main__':
|
|||
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", "--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")
|
||||
params = parser.parse_args()
|
||||
|
||||
print("Opening and parsing the dot file %s" % params.dot_file)
|
||||
try:
|
||||
monitor=dot2k(params.dot_file, params.monitor_type)
|
||||
monitor=dot2k(params.dot_file, params.monitor_type, vars(params))
|
||||
except Exception as e:
|
||||
print('Error: '+ str(e))
|
||||
print("Sorry : :-(")
|
||||
sys.exit(1)
|
||||
|
||||
# easier than using argparse action.
|
||||
if params.model_name != None:
|
||||
print(params.model_name)
|
||||
|
||||
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(" - Edit include/trace/events/rv.h to add the tracepoint entry")
|
||||
print(" - Move it to the kernel's monitor directory")
|
||||
print(" - Edit kernel/trace/rv/Makefile")
|
||||
print(" - Edit kernel/trace/rv/Kconfig")
|
||||
print(monitor.fill_tracepoint_tooltip())
|
||||
print(monitor.fill_makefile_tooltip())
|
||||
print(monitor.fill_kconfig_tooltip())
|
||||
print(monitor.fill_monitor_tooltip())
|
||||
|
|
|
@ -14,50 +14,83 @@ import os
|
|||
|
||||
class dot2k(Dot2c):
|
||||
monitor_types = { "global" : 1, "per_cpu" : 2, "per_task" : 3 }
|
||||
monitor_templates_dir = "dot2k/rv_templates/"
|
||||
monitor_templates_dir = "dot2/dot2k_templates/"
|
||||
rv_dir = "kernel/trace/rv"
|
||||
monitor_type = "per_cpu"
|
||||
|
||||
def __init__(self, file_path, MonitorType):
|
||||
super().__init__(file_path)
|
||||
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 == None:
|
||||
raise Exception("Unknown monitor type: %s" % 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.__open_file(self.monitor_templates_dir + "main_" + MonitorType + ".c")
|
||||
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"
|
||||
self.auto_patch = extra_params.get("auto_patch")
|
||||
if self.auto_patch:
|
||||
self.__fill_rv_kernel_dir()
|
||||
|
||||
def __fill_rv_templates_dir(self):
|
||||
|
||||
if os.path.exists(self.monitor_templates_dir) == True:
|
||||
if os.path.exists(self.monitor_templates_dir):
|
||||
return
|
||||
|
||||
if platform.system() != "Linux":
|
||||
raise Exception("I can only run on Linux.")
|
||||
raise OSError("I can only run on Linux.")
|
||||
|
||||
kernel_path = "/lib/modules/%s/build/tools/verification/dot2/dot2k_templates/" % (platform.release())
|
||||
|
||||
if os.path.exists(kernel_path) == True:
|
||||
if os.path.exists(kernel_path):
|
||||
self.monitor_templates_dir = kernel_path
|
||||
return
|
||||
|
||||
if os.path.exists("/usr/share/dot2/dot2k_templates/") == True:
|
||||
if os.path.exists("/usr/share/dot2/dot2k_templates/"):
|
||||
self.monitor_templates_dir = "/usr/share/dot2/dot2k_templates/"
|
||||
return
|
||||
|
||||
raise Exception("Could not find the template directory, do you have the kernel source installed?")
|
||||
raise FileNotFoundError("Could not find the template directory, do you have the kernel source installed?")
|
||||
|
||||
def __fill_rv_kernel_dir(self):
|
||||
|
||||
def __open_file(self, path):
|
||||
# first try if we are running in the kernel tree root
|
||||
if os.path.exists(self.rv_dir):
|
||||
return
|
||||
|
||||
# offset if we are running inside the kernel tree from verification/dot2
|
||||
kernel_path = os.path.join("../..", self.rv_dir)
|
||||
|
||||
if os.path.exists(kernel_path):
|
||||
self.rv_dir = kernel_path
|
||||
return
|
||||
|
||||
if platform.system() != "Linux":
|
||||
raise OSError("I can only run on Linux.")
|
||||
|
||||
kernel_path = os.path.join("/lib/modules/%s/build" % platform.release(), self.rv_dir)
|
||||
|
||||
# if the current kernel is from a distro this may not be a full kernel tree
|
||||
# verify that one of the files we are going to modify is available
|
||||
if os.path.exists(os.path.join(kernel_path, "rv_trace.h")):
|
||||
self.rv_dir = kernel_path
|
||||
return
|
||||
|
||||
raise FileNotFoundError("Could not find the rv directory, do you have the kernel source installed?")
|
||||
|
||||
def __read_file(self, path):
|
||||
try:
|
||||
fd = open(path)
|
||||
fd = open(path, 'r')
|
||||
except OSError:
|
||||
raise Exception("Cannot open the file: %s" % path)
|
||||
|
||||
content = fd.read()
|
||||
|
||||
fd.close()
|
||||
return content
|
||||
|
||||
def __buff_to_string(self, buff):
|
||||
|
@ -69,16 +102,26 @@ class dot2k(Dot2c):
|
|||
# cut off the last \n
|
||||
return string[:-1]
|
||||
|
||||
def fill_monitor_type(self):
|
||||
return self.monitor_type.upper()
|
||||
|
||||
def fill_tracepoint_handlers_skel(self):
|
||||
buff = []
|
||||
for event in self.events:
|
||||
buff.append("static void handle_%s(void *data, /* XXX: fill header */)" % event)
|
||||
buff.append("{")
|
||||
handle = "handle_event"
|
||||
if self.is_start_event(event):
|
||||
buff.append("\t/* XXX: validate that this event always leads to the initial state */")
|
||||
handle = "handle_start_event"
|
||||
elif self.is_start_run_event(event):
|
||||
buff.append("\t/* XXX: validate that this event is only valid in the initial state */")
|
||||
handle = "handle_start_run_event"
|
||||
if self.monitor_type == "per_task":
|
||||
buff.append("\tstruct task_struct *p = /* XXX: how do I get p? */;");
|
||||
buff.append("\tda_handle_event_%s(p, %s%s);" % (self.name, event, self.enum_suffix));
|
||||
buff.append("\tda_%s_%s(p, %s%s);" % (handle, self.name, event, self.enum_suffix));
|
||||
else:
|
||||
buff.append("\tda_handle_event_%s(%s%s);" % (self.name, event, self.enum_suffix));
|
||||
buff.append("\tda_%s_%s(%s%s);" % (handle, self.name, event, self.enum_suffix));
|
||||
buff.append("}")
|
||||
buff.append("")
|
||||
return self.__buff_to_string(buff)
|
||||
|
@ -97,18 +140,21 @@ class dot2k(Dot2c):
|
|||
|
||||
def fill_main_c(self):
|
||||
main_c = self.main_c
|
||||
monitor_type = self.fill_monitor_type()
|
||||
min_type = self.get_minimun_type()
|
||||
nr_events = self.events.__len__()
|
||||
nr_events = len(self.events)
|
||||
tracepoint_handlers = self.fill_tracepoint_handlers_skel()
|
||||
tracepoint_attach = self.fill_tracepoint_attach_probe()
|
||||
tracepoint_detach = self.fill_tracepoint_detach_helper()
|
||||
|
||||
main_c = main_c.replace("MIN_TYPE", min_type)
|
||||
main_c = main_c.replace("MODEL_NAME", self.name)
|
||||
main_c = main_c.replace("NR_EVENTS", str(nr_events))
|
||||
main_c = main_c.replace("TRACEPOINT_HANDLERS_SKEL", tracepoint_handlers)
|
||||
main_c = main_c.replace("TRACEPOINT_ATTACH", tracepoint_attach)
|
||||
main_c = main_c.replace("TRACEPOINT_DETACH", tracepoint_detach)
|
||||
main_c = main_c.replace("%%MONITOR_TYPE%%", monitor_type)
|
||||
main_c = main_c.replace("%%MIN_TYPE%%", min_type)
|
||||
main_c = main_c.replace("%%MODEL_NAME%%", self.name)
|
||||
main_c = main_c.replace("%%NR_EVENTS%%", str(nr_events))
|
||||
main_c = main_c.replace("%%TRACEPOINT_HANDLERS_SKEL%%", tracepoint_handlers)
|
||||
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)
|
||||
|
||||
return main_c
|
||||
|
||||
|
@ -137,30 +183,141 @@ class dot2k(Dot2c):
|
|||
|
||||
return self.__buff_to_string(buff)
|
||||
|
||||
def fill_monitor_class_type(self):
|
||||
if self.monitor_type == "per_task":
|
||||
return "DA_MON_EVENTS_ID"
|
||||
return "DA_MON_EVENTS_IMPLICIT"
|
||||
|
||||
def fill_monitor_class(self):
|
||||
if self.monitor_type == "per_task":
|
||||
return "da_monitor_id"
|
||||
return "da_monitor"
|
||||
|
||||
def fill_tracepoint_args_skel(self, tp_type):
|
||||
buff = []
|
||||
tp_args_event = [
|
||||
("char *", "state"),
|
||||
("char *", "event"),
|
||||
("char *", "next_state"),
|
||||
("bool ", "final_state"),
|
||||
]
|
||||
tp_args_error = [
|
||||
("char *", "state"),
|
||||
("char *", "event"),
|
||||
]
|
||||
tp_args_id = ("int ", "id")
|
||||
tp_args = tp_args_event if tp_type == "event" else tp_args_error
|
||||
if self.monitor_type == "per_task":
|
||||
tp_args.insert(0, tp_args_id)
|
||||
tp_proto_c = ", ".join([a+b for a,b in tp_args])
|
||||
tp_args_c = ", ".join([b for a,b in tp_args])
|
||||
buff.append(" TP_PROTO(%s)," % tp_proto_c)
|
||||
buff.append(" TP_ARGS(%s)" % tp_args_c)
|
||||
return self.__buff_to_string(buff)
|
||||
|
||||
def fill_trace_h(self):
|
||||
trace_h = self.trace_h
|
||||
monitor_class = self.fill_monitor_class()
|
||||
monitor_class_type = self.fill_monitor_class_type()
|
||||
tracepoint_args_skel_event = self.fill_tracepoint_args_skel("event")
|
||||
tracepoint_args_skel_error = self.fill_tracepoint_args_skel("error")
|
||||
trace_h = trace_h.replace("%%MODEL_NAME%%", self.name)
|
||||
trace_h = trace_h.replace("%%MODEL_NAME_UP%%", self.name.upper())
|
||||
trace_h = trace_h.replace("%%MONITOR_CLASS%%", monitor_class)
|
||||
trace_h = trace_h.replace("%%MONITOR_CLASS_TYPE%%", monitor_class_type)
|
||||
trace_h = trace_h.replace("%%TRACEPOINT_ARGS_SKEL_EVENT%%", tracepoint_args_skel_event)
|
||||
trace_h = trace_h.replace("%%TRACEPOINT_ARGS_SKEL_ERROR%%", tracepoint_args_skel_error)
|
||||
return trace_h
|
||||
|
||||
def fill_kconfig(self):
|
||||
kconfig = self.kconfig
|
||||
monitor_class_type = self.fill_monitor_class_type()
|
||||
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)
|
||||
return kconfig
|
||||
|
||||
def __patch_file(self, file, marker, line):
|
||||
file_to_patch = os.path.join(self.rv_dir, file)
|
||||
content = self.__read_file(file_to_patch)
|
||||
content = content.replace(marker, line + "\n" + marker)
|
||||
self.__write_file(file_to_patch, content)
|
||||
|
||||
def fill_tracepoint_tooltip(self):
|
||||
monitor_class_type = self.fill_monitor_class_type()
|
||||
if self.auto_patch:
|
||||
self.__patch_file("rv_trace.h",
|
||||
"// Add new monitors based on CONFIG_%s here" % monitor_class_type,
|
||||
"#include <monitors/%s/%s_trace.h>" % (self.name, self.name))
|
||||
return " - Patching %s/rv_trace.h, double check the result" % self.rv_dir
|
||||
|
||||
return """ - Edit %s/rv_trace.h:
|
||||
Add this line where other tracepoints are included and %s is defined:
|
||||
#include <monitors/%s/%s_trace.h>
|
||||
""" % (self.rv_dir, monitor_class_type, self.name, self.name)
|
||||
|
||||
def fill_kconfig_tooltip(self):
|
||||
if self.auto_patch:
|
||||
self.__patch_file("Kconfig",
|
||||
"# Add new monitors here",
|
||||
"source \"kernel/trace/rv/monitors/%s/Kconfig\"" % (self.name))
|
||||
return " - Patching %s/Kconfig, double check the result" % self.rv_dir
|
||||
|
||||
return """ - Edit %s/Kconfig:
|
||||
Add this line where other monitors are included:
|
||||
source \"kernel/trace/rv/monitors/%s/Kconfig\"
|
||||
""" % (self.rv_dir, self.name)
|
||||
|
||||
def fill_makefile_tooltip(self):
|
||||
name = self.name
|
||||
name_up = name.upper()
|
||||
if self.auto_patch:
|
||||
self.__patch_file("Makefile",
|
||||
"# Add new monitors here",
|
||||
"obj-$(CONFIG_RV_MON_%s) += monitors/%s/%s.o" % (name_up, name, name))
|
||||
return " - Patching %s/Makefile, double check the result" % self.rv_dir
|
||||
|
||||
return """ - Edit %s/Makefile:
|
||||
Add this line where other monitors are included:
|
||||
obj-$(CONFIG_RV_MON_%s) += monitors/%s/%s.o
|
||||
""" % (self.rv_dir, name_up, name, name)
|
||||
|
||||
def fill_monitor_tooltip(self):
|
||||
if self.auto_patch:
|
||||
return " - Monitor created in %s/monitors/%s" % (self.rv_dir, self. name)
|
||||
return " - Move %s/ to the kernel's monitor directory (%s/monitors)" % (self.name, self.rv_dir)
|
||||
|
||||
def __create_directory(self):
|
||||
path = self.name
|
||||
if self.auto_patch:
|
||||
path = os.path.join(self.rv_dir, "monitors", path)
|
||||
try:
|
||||
os.mkdir(self.name)
|
||||
os.mkdir(path)
|
||||
except FileExistsError:
|
||||
return
|
||||
except:
|
||||
print("Fail creating the output dir: %s" % self.name)
|
||||
|
||||
def __create_file(self, file_name, content):
|
||||
path = "%s/%s" % (self.name, file_name)
|
||||
def __write_file(self, file_name, content):
|
||||
try:
|
||||
file = open(path, 'w')
|
||||
except FileExistsError:
|
||||
return
|
||||
file = open(file_name, 'w')
|
||||
except:
|
||||
print("Fail creating file: %s" % path)
|
||||
print("Fail writing to file: %s" % file_name)
|
||||
|
||||
file.write(content)
|
||||
|
||||
file.close()
|
||||
|
||||
def __create_file(self, file_name, content):
|
||||
path = "%s/%s" % (self.name, file_name)
|
||||
if self.auto_patch:
|
||||
path = os.path.join(self.rv_dir, "monitors", path)
|
||||
self.__write_file(path, content)
|
||||
|
||||
def __get_main_name(self):
|
||||
path = "%s/%s" % (self.name, "main.c")
|
||||
if os.path.exists(path) == False:
|
||||
if not os.path.exists(path):
|
||||
return "main.c"
|
||||
return "__main.c"
|
||||
|
||||
|
@ -175,3 +332,10 @@ class dot2k(Dot2c):
|
|||
|
||||
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)
|
||||
|
|
6
tools/verification/dot2/dot2k_templates/Kconfig
Normal file
6
tools/verification/dot2/dot2k_templates/Kconfig
Normal file
|
@ -0,0 +1,6 @@
|
|||
config RV_MON_%%MODEL_NAME_UP%%
|
||||
depends on RV
|
||||
select %%MONITOR_CLASS_TYPE%%
|
||||
bool "%%MODEL_NAME%% monitor"
|
||||
help
|
||||
%%DESCRIPTION%%
|
91
tools/verification/dot2/dot2k_templates/main.c
Normal file
91
tools/verification/dot2/dot2k_templates/main.c
Normal file
|
@ -0,0 +1,91 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/tracepoint.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/rv.h>
|
||||
#include <rv/instrumentation.h>
|
||||
#include <rv/da_monitor.h>
|
||||
|
||||
#define MODULE_NAME "%%MODEL_NAME%%"
|
||||
|
||||
/*
|
||||
* XXX: include required tracepoint headers, e.g.,
|
||||
* #include <trace/events/sched.h>
|
||||
*/
|
||||
#include <rv_trace.h>
|
||||
|
||||
/*
|
||||
* This is the self-generated part of the monitor. Generally, there is no need
|
||||
* to touch this section.
|
||||
*/
|
||||
#include "%%MODEL_NAME%%.h"
|
||||
|
||||
/*
|
||||
* Declare the deterministic automata monitor.
|
||||
*
|
||||
* The rv monitor reference is needed for the monitor declaration.
|
||||
*/
|
||||
static struct rv_monitor rv_%%MODEL_NAME%%;
|
||||
DECLARE_DA_MON_%%MONITOR_TYPE%%(%%MODEL_NAME%%, %%MIN_TYPE%%);
|
||||
|
||||
/*
|
||||
* This is the instrumentation part of the monitor.
|
||||
*
|
||||
* This is the section where manual work is required. Here the kernel events
|
||||
* are translated into model's event.
|
||||
*
|
||||
*/
|
||||
%%TRACEPOINT_HANDLERS_SKEL%%
|
||||
static int enable_%%MODEL_NAME%%(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = da_monitor_init_%%MODEL_NAME%%();
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
%%TRACEPOINT_ATTACH%%
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void disable_%%MODEL_NAME%%(void)
|
||||
{
|
||||
rv_%%MODEL_NAME%%.enabled = 0;
|
||||
|
||||
%%TRACEPOINT_DETACH%%
|
||||
|
||||
da_monitor_destroy_%%MODEL_NAME%%();
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the monitor register section.
|
||||
*/
|
||||
static struct rv_monitor rv_%%MODEL_NAME%% = {
|
||||
.name = "%%MODEL_NAME%%",
|
||||
.description = "%%DESCRIPTION%%",
|
||||
.enable = enable_%%MODEL_NAME%%,
|
||||
.disable = disable_%%MODEL_NAME%%,
|
||||
.reset = da_monitor_reset_all_%%MODEL_NAME%%,
|
||||
.enabled = 0,
|
||||
};
|
||||
|
||||
static int __init register_%%MODEL_NAME%%(void)
|
||||
{
|
||||
rv_register_monitor(&rv_%%MODEL_NAME%%);
|
||||
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%%");
|
|
@ -1,91 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/tracepoint.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/rv.h>
|
||||
#include <rv/instrumentation.h>
|
||||
#include <rv/da_monitor.h>
|
||||
|
||||
#define MODULE_NAME "MODEL_NAME"
|
||||
|
||||
/*
|
||||
* XXX: include required tracepoint headers, e.g.,
|
||||
* #include <trace/events/sched.h>
|
||||
*/
|
||||
#include <trace/events/rv.h>
|
||||
|
||||
/*
|
||||
* This is the self-generated part of the monitor. Generally, there is no need
|
||||
* to touch this section.
|
||||
*/
|
||||
#include "MODEL_NAME.h"
|
||||
|
||||
/*
|
||||
* Declare the deterministic automata monitor.
|
||||
*
|
||||
* The rv monitor reference is needed for the monitor declaration.
|
||||
*/
|
||||
static struct rv_monitor rv_MODEL_NAME;
|
||||
DECLARE_DA_MON_GLOBAL(MODEL_NAME, MIN_TYPE);
|
||||
|
||||
/*
|
||||
* This is the instrumentation part of the monitor.
|
||||
*
|
||||
* This is the section where manual work is required. Here the kernel events
|
||||
* are translated into model's event.
|
||||
*
|
||||
*/
|
||||
TRACEPOINT_HANDLERS_SKEL
|
||||
static int enable_MODEL_NAME(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = da_monitor_init_MODEL_NAME();
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
TRACEPOINT_ATTACH
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void disable_MODEL_NAME(void)
|
||||
{
|
||||
rv_MODEL_NAME.enabled = 0;
|
||||
|
||||
TRACEPOINT_DETACH
|
||||
|
||||
da_monitor_destroy_MODEL_NAME();
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the monitor register section.
|
||||
*/
|
||||
static struct rv_monitor rv_MODEL_NAME = {
|
||||
.name = "MODEL_NAME",
|
||||
.description = "auto-generated MODEL_NAME",
|
||||
.enable = enable_MODEL_NAME,
|
||||
.disable = disable_MODEL_NAME,
|
||||
.reset = da_monitor_reset_all_MODEL_NAME,
|
||||
.enabled = 0,
|
||||
};
|
||||
|
||||
static int __init register_MODEL_NAME(void)
|
||||
{
|
||||
rv_register_monitor(&rv_MODEL_NAME);
|
||||
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");
|
|
@ -1,91 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/tracepoint.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/rv.h>
|
||||
#include <rv/instrumentation.h>
|
||||
#include <rv/da_monitor.h>
|
||||
|
||||
#define MODULE_NAME "MODEL_NAME"
|
||||
|
||||
/*
|
||||
* XXX: include required tracepoint headers, e.g.,
|
||||
* #include <linux/trace/events/sched.h>
|
||||
*/
|
||||
#include <trace/events/rv.h>
|
||||
|
||||
/*
|
||||
* This is the self-generated part of the monitor. Generally, there is no need
|
||||
* to touch this section.
|
||||
*/
|
||||
#include "MODEL_NAME.h"
|
||||
|
||||
/*
|
||||
* Declare the deterministic automata monitor.
|
||||
*
|
||||
* The rv monitor reference is needed for the monitor declaration.
|
||||
*/
|
||||
static struct rv_monitor rv_MODEL_NAME;
|
||||
DECLARE_DA_MON_PER_CPU(MODEL_NAME, MIN_TYPE);
|
||||
|
||||
/*
|
||||
* This is the instrumentation part of the monitor.
|
||||
*
|
||||
* This is the section where manual work is required. Here the kernel events
|
||||
* are translated into model's event.
|
||||
*
|
||||
*/
|
||||
TRACEPOINT_HANDLERS_SKEL
|
||||
static int enable_MODEL_NAME(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = da_monitor_init_MODEL_NAME();
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
TRACEPOINT_ATTACH
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void disable_MODEL_NAME(void)
|
||||
{
|
||||
rv_MODEL_NAME.enabled = 0;
|
||||
|
||||
TRACEPOINT_DETACH
|
||||
|
||||
da_monitor_destroy_MODEL_NAME();
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the monitor register section.
|
||||
*/
|
||||
static struct rv_monitor rv_MODEL_NAME = {
|
||||
.name = "MODEL_NAME",
|
||||
.description = "auto-generated MODEL_NAME",
|
||||
.enable = enable_MODEL_NAME,
|
||||
.disable = disable_MODEL_NAME,
|
||||
.reset = da_monitor_reset_all_MODEL_NAME,
|
||||
.enabled = 0,
|
||||
};
|
||||
|
||||
static int __init register_MODEL_NAME(void)
|
||||
{
|
||||
rv_register_monitor(&rv_MODEL_NAME);
|
||||
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");
|
|
@ -1,91 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/tracepoint.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/rv.h>
|
||||
#include <rv/instrumentation.h>
|
||||
#include <rv/da_monitor.h>
|
||||
|
||||
#define MODULE_NAME "MODEL_NAME"
|
||||
|
||||
/*
|
||||
* XXX: include required tracepoint headers, e.g.,
|
||||
* #include <linux/trace/events/sched.h>
|
||||
*/
|
||||
#include <trace/events/rv.h>
|
||||
|
||||
/*
|
||||
* This is the self-generated part of the monitor. Generally, there is no need
|
||||
* to touch this section.
|
||||
*/
|
||||
#include "MODEL_NAME.h"
|
||||
|
||||
/*
|
||||
* Declare the deterministic automata monitor.
|
||||
*
|
||||
* The rv monitor reference is needed for the monitor declaration.
|
||||
*/
|
||||
static struct rv_monitor rv_MODEL_NAME;
|
||||
DECLARE_DA_MON_PER_TASK(MODEL_NAME, MIN_TYPE);
|
||||
|
||||
/*
|
||||
* This is the instrumentation part of the monitor.
|
||||
*
|
||||
* This is the section where manual work is required. Here the kernel events
|
||||
* are translated into model's event.
|
||||
*
|
||||
*/
|
||||
TRACEPOINT_HANDLERS_SKEL
|
||||
static int enable_MODEL_NAME(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = da_monitor_init_MODEL_NAME();
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
TRACEPOINT_ATTACH
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void disable_MODEL_NAME(void)
|
||||
{
|
||||
rv_MODEL_NAME.enabled = 0;
|
||||
|
||||
TRACEPOINT_DETACH
|
||||
|
||||
da_monitor_destroy_MODEL_NAME();
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the monitor register section.
|
||||
*/
|
||||
static struct rv_monitor rv_MODEL_NAME = {
|
||||
.name = "MODEL_NAME",
|
||||
.description = "auto-generated MODEL_NAME",
|
||||
.enable = enable_MODEL_NAME,
|
||||
.disable = disable_MODEL_NAME,
|
||||
.reset = da_monitor_reset_all_MODEL_NAME,
|
||||
.enabled = 0,
|
||||
};
|
||||
|
||||
static int __init register_MODEL_NAME(void)
|
||||
{
|
||||
rv_register_monitor(&rv_MODEL_NAME);
|
||||
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");
|
13
tools/verification/dot2/dot2k_templates/trace.h
Normal file
13
tools/verification/dot2/dot2k_templates/trace.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
/*
|
||||
* Snippet to be included in rv_trace.h
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_RV_MON_%%MODEL_NAME_UP%%
|
||||
DEFINE_EVENT(event_%%MONITOR_CLASS%%, event_%%MODEL_NAME%%,
|
||||
%%TRACEPOINT_ARGS_SKEL_EVENT%%);
|
||||
|
||||
DEFINE_EVENT(error_%%MONITOR_CLASS%%, error_%%MODEL_NAME%%,
|
||||
%%TRACEPOINT_ARGS_SKEL_ERROR%%);
|
||||
#endif /* CONFIG_RV_MON_%%MODEL_NAME_UP%% */
|
Loading…
Add table
Reference in a new issue