aboutsummaryrefslogtreecommitdiffstats
path: root/tools/tracing
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2022-08-02 10:06:12 -0700
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2022-08-02 10:06:12 -0700
commit8bb5e7f4dcd9b9ef22a3ea25c9066a8a968f12dd (patch)
tree0f1383880607a227142f9388a066959926233ff1 /tools/tracing
parentInput: document the units for resolution of size axes (diff)
parentInput: adc-joystick - fix ordering in adc_joystick_probe() (diff)
Merge branch 'next' into for-linus
Prepare input updates for 5.20 (or 6.0) merge window.
Diffstat (limited to 'tools/tracing')
-rw-r--r--tools/tracing/rtla/Makefile42
-rw-r--r--tools/tracing/rtla/README.txt13
-rw-r--r--tools/tracing/rtla/src/osnoise.c83
-rw-r--r--tools/tracing/rtla/src/osnoise.h8
-rw-r--r--tools/tracing/rtla/src/osnoise_hist.c100
-rw-r--r--tools/tracing/rtla/src/osnoise_top.c100
-rw-r--r--tools/tracing/rtla/src/timerlat_hist.c117
-rw-r--r--tools/tracing/rtla/src/timerlat_top.c112
-rw-r--r--tools/tracing/rtla/src/trace.c345
-rw-r--r--tools/tracing/rtla/src/trace.h23
-rw-r--r--tools/tracing/rtla/src/utils.c141
-rw-r--r--tools/tracing/rtla/src/utils.h4
12 files changed, 1012 insertions, 76 deletions
diff --git a/tools/tracing/rtla/Makefile b/tools/tracing/rtla/Makefile
index 5a1eda617992..3822f4ea5f49 100644
--- a/tools/tracing/rtla/Makefile
+++ b/tools/tracing/rtla/Makefile
@@ -23,6 +23,7 @@ $(call allow-override,LD_SO_CONF_PATH,/etc/ld.so.conf.d/)
$(call allow-override,LDCONFIG,ldconfig)
INSTALL = install
+MKDIR = mkdir
FOPTS := -flto=auto -ffat-lto-objects -fexceptions -fstack-protector-strong \
-fasynchronous-unwind-tables -fstack-clash-protection
WOPTS := -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -Wno-maybe-uninitialized
@@ -31,7 +32,7 @@ TRACEFS_HEADERS := $$($(PKG_CONFIG) --cflags libtracefs)
CFLAGS := -O -g -DVERSION=\"$(VERSION)\" $(FOPTS) $(MOPTS) $(WOPTS) $(TRACEFS_HEADERS)
LDFLAGS := -ggdb
-LIBS := $$($(PKG_CONFIG) --libs libtracefs) -lprocps
+LIBS := $$($(PKG_CONFIG) --libs libtracefs)
SRC := $(wildcard src/*.c)
HDR := $(wildcard src/*.h)
@@ -46,7 +47,7 @@ DATADIR := /usr/share
DOCDIR := $(DATADIR)/doc
MANDIR := $(DATADIR)/man
LICDIR := $(DATADIR)/licenses
-SRCTREE := $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR))
+SRCTREE := $(or $(BUILD_SRC),$(CURDIR))
# If running from the tarball, man pages are stored in the Documentation
# dir. If running from the kernel source, man pages are stored in
@@ -57,6 +58,41 @@ else
DOCSRC = $(SRCTREE)/../../../Documentation/tools/rtla/
endif
+LIBTRACEEVENT_MIN_VERSION = 1.5
+LIBTRACEFS_MIN_VERSION = 1.3
+
+TEST_LIBTRACEEVENT = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEEVENT_MIN_VERSION) libtraceevent > /dev/null 2>&1 || echo n")
+ifeq ("$(TEST_LIBTRACEEVENT)", "n")
+.PHONY: warning_traceevent
+warning_traceevent:
+ @echo "********************************************"
+ @echo "** NOTICE: libtraceevent version $(LIBTRACEEVENT_MIN_VERSION) or higher not found"
+ @echo "**"
+ @echo "** Consider installing the latest libtraceevent from your"
+ @echo "** distribution, e.g., 'dnf install libtraceevent' on Fedora,"
+ @echo "** or from source:"
+ @echo "**"
+ @echo "** https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/ "
+ @echo "**"
+ @echo "********************************************"
+endif
+
+TEST_LIBTRACEFS = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEFS_MIN_VERSION) libtracefs > /dev/null 2>&1 || echo n")
+ifeq ("$(TEST_LIBTRACEFS)", "n")
+.PHONY: warning_tracefs
+warning_tracefs:
+ @echo "********************************************"
+ @echo "** NOTICE: libtracefs version $(LIBTRACEFS_MIN_VERSION) or higher not found"
+ @echo "**"
+ @echo "** Consider installing the latest libtracefs from your"
+ @echo "** distribution, e.g., 'dnf install libtracefs' on Fedora,"
+ @echo "** or from source:"
+ @echo "**"
+ @echo "** https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ "
+ @echo "**"
+ @echo "********************************************"
+endif
+
.PHONY: all
all: rtla
@@ -68,7 +104,7 @@ static: $(OBJ)
.PHONY: install
install: doc_install
- $(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR)
+ $(MKDIR) -p $(DESTDIR)$(BINDIR)
$(INSTALL) rtla -m 755 $(DESTDIR)$(BINDIR)
$(STRIP) $(DESTDIR)$(BINDIR)/rtla
@test ! -f $(DESTDIR)$(BINDIR)/osnoise || rm $(DESTDIR)$(BINDIR)/osnoise
diff --git a/tools/tracing/rtla/README.txt b/tools/tracing/rtla/README.txt
index 6c88446f7e74..4af3fd40f171 100644
--- a/tools/tracing/rtla/README.txt
+++ b/tools/tracing/rtla/README.txt
@@ -1,19 +1,16 @@
RTLA: Real-Time Linux Analysis tools
-The rtla is a meta-tool that includes a set of commands that
-aims to analyze the real-time properties of Linux. But, instead of
-testing Linux as a black box, rtla leverages kernel tracing
-capabilities to provide precise information about the properties
-and root causes of unexpected results.
+The rtla meta-tool includes a set of commands that aims to analyze
+the real-time properties of Linux. Instead of testing Linux as a black box,
+rtla leverages kernel tracing capabilities to provide precise information
+about the properties and root causes of unexpected results.
Installing RTLA
-RTLA depends on some libraries and tools. More precisely, it depends on the
-following libraries:
+RTLA depends on the following libraries and tools:
- libtracefs
- libtraceevent
- - procps
It also depends on python3-docutils to compile man pages.
diff --git a/tools/tracing/rtla/src/osnoise.c b/tools/tracing/rtla/src/osnoise.c
index e60f1862bad0..b8ec6c15bccb 100644
--- a/tools/tracing/rtla/src/osnoise.c
+++ b/tools/tracing/rtla/src/osnoise.c
@@ -656,6 +656,85 @@ void osnoise_put_print_stack(struct osnoise_context *context)
}
/*
+ * osnoise_get_tracing_thresh - read and save the original "tracing_thresh"
+ */
+static long long
+osnoise_get_tracing_thresh(struct osnoise_context *context)
+{
+ long long tracing_thresh;
+
+ if (context->tracing_thresh != OSNOISE_OPTION_INIT_VAL)
+ return context->tracing_thresh;
+
+ if (context->orig_tracing_thresh != OSNOISE_OPTION_INIT_VAL)
+ return context->orig_tracing_thresh;
+
+ tracing_thresh = osnoise_read_ll_config("tracing_thresh");
+ if (tracing_thresh < 0)
+ goto out_err;
+
+ context->orig_tracing_thresh = tracing_thresh;
+ return tracing_thresh;
+
+out_err:
+ return OSNOISE_OPTION_INIT_VAL;
+}
+
+/*
+ * osnoise_set_tracing_thresh - set "tracing_thresh"
+ */
+int osnoise_set_tracing_thresh(struct osnoise_context *context, long long tracing_thresh)
+{
+ long long curr_tracing_thresh = osnoise_get_tracing_thresh(context);
+ int retval;
+
+ if (curr_tracing_thresh == OSNOISE_OPTION_INIT_VAL)
+ return -1;
+
+ retval = osnoise_write_ll_config("tracing_thresh", tracing_thresh);
+ if (retval < 0)
+ return -1;
+
+ context->tracing_thresh = tracing_thresh;
+
+ return 0;
+}
+
+/*
+ * osnoise_restore_tracing_thresh - restore the original "tracing_thresh"
+ */
+void osnoise_restore_tracing_thresh(struct osnoise_context *context)
+{
+ int retval;
+
+ if (context->orig_tracing_thresh == OSNOISE_OPTION_INIT_VAL)
+ return;
+
+ if (context->orig_tracing_thresh == context->tracing_thresh)
+ goto out_done;
+
+ retval = osnoise_write_ll_config("tracing_thresh", context->orig_tracing_thresh);
+ if (retval < 0)
+ err_msg("Could not restore original tracing_thresh\n");
+
+out_done:
+ context->tracing_thresh = OSNOISE_OPTION_INIT_VAL;
+}
+
+/*
+ * osnoise_put_tracing_thresh - restore original values and cleanup data
+ */
+void osnoise_put_tracing_thresh(struct osnoise_context *context)
+{
+ osnoise_restore_tracing_thresh(context);
+
+ if (context->orig_tracing_thresh == OSNOISE_OPTION_INIT_VAL)
+ return;
+
+ context->orig_tracing_thresh = OSNOISE_OPTION_INIT_VAL;
+}
+
+/*
* enable_osnoise - enable osnoise tracer in the trace_instance
*/
int enable_osnoise(struct trace_instance *trace)
@@ -716,6 +795,9 @@ struct osnoise_context *osnoise_context_alloc(void)
context->orig_print_stack = OSNOISE_OPTION_INIT_VAL;
context->print_stack = OSNOISE_OPTION_INIT_VAL;
+ context->orig_tracing_thresh = OSNOISE_OPTION_INIT_VAL;
+ context->tracing_thresh = OSNOISE_OPTION_INIT_VAL;
+
osnoise_get_context(context);
return context;
@@ -741,6 +823,7 @@ void osnoise_put_context(struct osnoise_context *context)
osnoise_put_stop_total_us(context);
osnoise_put_timerlat_period_us(context);
osnoise_put_print_stack(context);
+ osnoise_put_tracing_thresh(context);
free(context);
}
diff --git a/tools/tracing/rtla/src/osnoise.h b/tools/tracing/rtla/src/osnoise.h
index 9e4b2e2a4559..04a4384cc544 100644
--- a/tools/tracing/rtla/src/osnoise.h
+++ b/tools/tracing/rtla/src/osnoise.h
@@ -23,6 +23,10 @@ struct osnoise_context {
long long orig_timerlat_period_us;
long long timerlat_period_us;
+ /* 0 as init value */
+ long long orig_tracing_thresh;
+ long long tracing_thresh;
+
/* -1 as init value because 0 is disabled */
long long orig_stop_us;
long long stop_us;
@@ -67,6 +71,10 @@ int osnoise_set_timerlat_period_us(struct osnoise_context *context,
long long timerlat_period_us);
void osnoise_restore_timerlat_period_us(struct osnoise_context *context);
+int osnoise_set_tracing_thresh(struct osnoise_context *context,
+ long long tracing_thresh);
+void osnoise_restore_tracing_thresh(struct osnoise_context *context);
+
void osnoise_restore_print_stack(struct osnoise_context *context);
int osnoise_set_print_stack(struct osnoise_context *context,
long long print_stack);
diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c
index 52c053cc1789..5d7ea479ac89 100644
--- a/tools/tracing/rtla/src/osnoise_hist.c
+++ b/tools/tracing/rtla/src/osnoise_hist.c
@@ -21,6 +21,7 @@ struct osnoise_hist_params {
char *trace_output;
unsigned long long runtime;
unsigned long long period;
+ long long threshold;
long long stop_us;
long long stop_total_us;
int sleep_time;
@@ -28,6 +29,7 @@ struct osnoise_hist_params {
int set_sched;
int output_divisor;
struct sched_attr sched_param;
+ struct trace_events *events;
char no_header;
char no_summary;
@@ -425,19 +427,25 @@ static void osnoise_hist_usage(char *usage)
static const char * const msg[] = {
"",
- " usage: rtla osnoise hist [-h] [-D] [-d s] [-p us] [-r us] [-s us] [-S us] [-t[=file]] \\",
- " [-c cpu-list] [-P priority] [-b N] [-E N] [--no-header] [--no-summary] \\",
- " [--no-index] [--with-zeros]",
+ " usage: rtla osnoise hist [-h] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\",
+ " [-T us] [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\",
+ " [-c cpu-list] [-P priority] [-b N] [-E N] [--no-header] [--no-summary] [--no-index] \\",
+ " [--with-zeros]",
"",
" -h/--help: print this menu",
+ " -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit",
" -p/--period us: osnoise period in us",
" -r/--runtime us: osnoise runtime in us",
" -s/--stop us: stop trace if a single sample is higher than the argument in us",
" -S/--stop-total us: stop trace if the total sample is higher than the argument in us",
+ " -T/--threshold us: the minimum delta to be considered a noise",
" -c/--cpus cpu-list: list of cpus to run osnoise threads",
" -d/--duration time[s|m|h|d]: duration of the session",
" -D/--debug: print debug info",
" -t/--trace[=file]: save the stopped trace to [file|osnoise_trace.txt]",
+ " -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed",
+ " --filter <filter>: enable a trace event filter to the previous -e event",
+ " --trigger <trigger>: enable a trace event trigger to the previous -e event",
" -b/--bucket-size N: set the histogram bucket size (default 1)",
" -E/--entries N: set the number of entries of the histogram (default 256)",
" --no-header: do not print header",
@@ -471,6 +479,7 @@ static struct osnoise_hist_params
*osnoise_hist_parse_args(int argc, char *argv[])
{
struct osnoise_hist_params *params;
+ struct trace_events *tevent;
int retval;
int c;
@@ -485,6 +494,7 @@ static struct osnoise_hist_params
while (1) {
static struct option long_options[] = {
+ {"auto", required_argument, 0, 'a'},
{"bucket-size", required_argument, 0, 'b'},
{"entries", required_argument, 0, 'E'},
{"cpus", required_argument, 0, 'c'},
@@ -497,17 +507,21 @@ static struct osnoise_hist_params
{"stop", required_argument, 0, 's'},
{"stop-total", required_argument, 0, 'S'},
{"trace", optional_argument, 0, 't'},
+ {"event", required_argument, 0, 'e'},
+ {"threshold", required_argument, 0, 'T'},
{"no-header", no_argument, 0, '0'},
{"no-summary", no_argument, 0, '1'},
{"no-index", no_argument, 0, '2'},
{"with-zeros", no_argument, 0, '3'},
+ {"trigger", required_argument, 0, '4'},
+ {"filter", required_argument, 0, '5'},
{0, 0, 0, 0}
};
/* getopt_long stores the option index here. */
int option_index = 0;
- c = getopt_long(argc, argv, "c:b:d:E:Dhp:P:r:s:S:t::0123",
+ c = getopt_long(argc, argv, "a:c:b:d:e:E:Dhp:P:r:s:S:t::T:01234:5:",
long_options, &option_index);
/* detect the end of the options. */
@@ -515,6 +529,17 @@ static struct osnoise_hist_params
break;
switch (c) {
+ case 'a':
+ /* set sample stop to auto_thresh */
+ params->stop_us = get_llong_from_str(optarg);
+
+ /* set sample threshold to 1 */
+ params->threshold = 1;
+
+ /* set trace */
+ params->trace_output = "osnoise_trace.txt";
+
+ break;
case 'b':
params->bucket_size = get_llong_from_str(optarg);
if ((params->bucket_size == 0) || (params->bucket_size >= 1000000))
@@ -534,6 +559,18 @@ static struct osnoise_hist_params
if (!params->duration)
osnoise_hist_usage("Invalid -D duration\n");
break;
+ case 'e':
+ tevent = trace_event_alloc(optarg);
+ if (!tevent) {
+ err_msg("Error alloc trace event");
+ exit(EXIT_FAILURE);
+ }
+
+ if (params->events)
+ tevent->next = params->events;
+
+ params->events = tevent;
+ break;
case 'E':
params->entries = get_llong_from_str(optarg);
if ((params->entries < 10) || (params->entries > 9999999))
@@ -565,6 +602,9 @@ static struct osnoise_hist_params
case 'S':
params->stop_total_us = get_llong_from_str(optarg);
break;
+ case 'T':
+ params->threshold = get_llong_from_str(optarg);
+ break;
case 't':
if (optarg)
/* skip = */
@@ -584,6 +624,28 @@ static struct osnoise_hist_params
case '3': /* with zeros */
params->with_zeros = 1;
break;
+ case '4': /* trigger */
+ if (params->events) {
+ retval = trace_event_add_trigger(params->events, optarg);
+ if (retval) {
+ err_msg("Error adding trigger %s\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ osnoise_hist_usage("--trigger requires a previous -e\n");
+ }
+ break;
+ case '5': /* filter */
+ if (params->events) {
+ retval = trace_event_add_filter(params->events, optarg);
+ if (retval) {
+ err_msg("Error adding filter %s\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ osnoise_hist_usage("--filter requires a previous -e\n");
+ }
+ break;
default:
osnoise_hist_usage("Invalid option");
}
@@ -645,6 +707,14 @@ osnoise_hist_apply_config(struct osnoise_tool *tool, struct osnoise_hist_params
}
}
+ if (params->threshold) {
+ retval = osnoise_set_tracing_thresh(tool->context, params->threshold);
+ if (retval) {
+ err_msg("Failed to set tracing_thresh\n");
+ goto out_err;
+ }
+ }
+
return 0;
out_err:
@@ -739,7 +809,7 @@ int osnoise_hist_main(int argc, char *argv[])
retval = set_comm_sched_attr("osnoise/", &params->sched_param);
if (retval) {
err_msg("Failed to set sched parameters\n");
- goto out_hist;
+ goto out_free;
}
}
@@ -749,8 +819,15 @@ int osnoise_hist_main(int argc, char *argv[])
record = osnoise_init_trace_tool("osnoise");
if (!record) {
err_msg("Failed to enable the trace instance\n");
- goto out_hist;
+ goto out_free;
}
+
+ if (params->events) {
+ retval = trace_events_enable(&record->trace, params->events);
+ if (retval)
+ goto out_hist;
+ }
+
trace_instance_start(&record->trace);
}
@@ -771,9 +848,9 @@ int osnoise_hist_main(int argc, char *argv[])
goto out_hist;
}
- if (!tracefs_trace_is_on(trace->inst))
+ if (trace_is_off(&tool->trace, &record->trace))
break;
- };
+ }
osnoise_read_trace_hist(tool);
@@ -781,8 +858,8 @@ int osnoise_hist_main(int argc, char *argv[])
return_value = 0;
- if (!tracefs_trace_is_on(trace->inst)) {
- printf("rtla timelat hit stop tracing\n");
+ if (trace_is_off(&tool->trace, &record->trace)) {
+ printf("rtla osnoise hit stop tracing\n");
if (params->trace_output) {
printf(" Saving trace to %s\n", params->trace_output);
save_trace_to_file(record->trace.inst, params->trace_output);
@@ -790,6 +867,9 @@ int osnoise_hist_main(int argc, char *argv[])
}
out_hist:
+ trace_events_destroy(&record->trace, params->events);
+ params->events = NULL;
+out_free:
osnoise_free_histogram(tool->data);
out_destroy:
osnoise_destroy_tool(record);
diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c
index 7af769b9c0de..76479bfb2922 100644
--- a/tools/tracing/rtla/src/osnoise_top.c
+++ b/tools/tracing/rtla/src/osnoise_top.c
@@ -23,6 +23,7 @@ struct osnoise_top_params {
char *trace_output;
unsigned long long runtime;
unsigned long long period;
+ long long threshold;
long long stop_us;
long long stop_total_us;
int sleep_time;
@@ -30,6 +31,7 @@ struct osnoise_top_params {
int quiet;
int set_sched;
struct sched_attr sched_param;
+ struct trace_events *events;
};
struct osnoise_top_cpu {
@@ -244,18 +246,24 @@ void osnoise_top_usage(char *usage)
int i;
static const char * const msg[] = {
- " usage: rtla osnoise [top] [-h] [-q] [-D] [-d s] [-p us] [-r us] [-s us] [-S us] [-t[=file]] \\",
+ " usage: rtla osnoise [top] [-h] [-q] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\",
+ " [-T us] [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\",
" [-c cpu-list] [-P priority]",
"",
" -h/--help: print this menu",
+ " -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit",
" -p/--period us: osnoise period in us",
" -r/--runtime us: osnoise runtime in us",
" -s/--stop us: stop trace if a single sample is higher than the argument in us",
" -S/--stop-total us: stop trace if the total sample is higher than the argument in us",
+ " -T/--threshold us: the minimum delta to be considered a noise",
" -c/--cpus cpu-list: list of cpus to run osnoise threads",
" -d/--duration time[s|m|h|d]: duration of the session",
" -D/--debug: print debug info",
" -t/--trace[=file]: save the stopped trace to [file|osnoise_trace.txt]",
+ " -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed",
+ " --filter <filter>: enable a trace event filter to the previous -e event",
+ " --trigger <trigger>: enable a trace event trigger to the previous -e event",
" -q/--quiet print only a summary at the end",
" -P/--priority o:prio|r:prio|f:prio|d:runtime:period : set scheduling parameters",
" o:prio - use SCHED_OTHER with prio",
@@ -283,6 +291,7 @@ void osnoise_top_usage(char *usage)
struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv)
{
struct osnoise_top_params *params;
+ struct trace_events *tevent;
int retval;
int c;
@@ -292,9 +301,11 @@ struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv)
while (1) {
static struct option long_options[] = {
+ {"auto", required_argument, 0, 'a'},
{"cpus", required_argument, 0, 'c'},
{"debug", no_argument, 0, 'D'},
{"duration", required_argument, 0, 'd'},
+ {"event", required_argument, 0, 'e'},
{"help", no_argument, 0, 'h'},
{"period", required_argument, 0, 'p'},
{"priority", required_argument, 0, 'P'},
@@ -302,14 +313,17 @@ struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv)
{"runtime", required_argument, 0, 'r'},
{"stop", required_argument, 0, 's'},
{"stop-total", required_argument, 0, 'S'},
+ {"threshold", required_argument, 0, 'T'},
{"trace", optional_argument, 0, 't'},
+ {"trigger", required_argument, 0, '0'},
+ {"filter", required_argument, 0, '1'},
{0, 0, 0, 0}
};
/* getopt_long stores the option index here. */
int option_index = 0;
- c = getopt_long(argc, argv, "c:d:Dhp:P:qr:s:S:t::",
+ c = getopt_long(argc, argv, "a:c:d:De:hp:P:qr:s:S:t::T:0:1:",
long_options, &option_index);
/* Detect the end of the options. */
@@ -317,6 +331,17 @@ struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv)
break;
switch (c) {
+ case 'a':
+ /* set sample stop to auto_thresh */
+ params->stop_us = get_llong_from_str(optarg);
+
+ /* set sample threshold to 1 */
+ params->threshold = 1;
+
+ /* set trace */
+ params->trace_output = "osnoise_trace.txt";
+
+ break;
case 'c':
retval = parse_cpu_list(optarg, &params->monitored_cpus);
if (retval)
@@ -331,6 +356,18 @@ struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv)
if (!params->duration)
osnoise_top_usage("Invalid -D duration\n");
break;
+ case 'e':
+ tevent = trace_event_alloc(optarg);
+ if (!tevent) {
+ err_msg("Error alloc trace event");
+ exit(EXIT_FAILURE);
+ }
+
+ if (params->events)
+ tevent->next = params->events;
+ params->events = tevent;
+
+ break;
case 'h':
case '?':
osnoise_top_usage(NULL);
@@ -367,6 +404,31 @@ struct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv)
else
params->trace_output = "osnoise_trace.txt";
break;
+ case 'T':
+ params->threshold = get_llong_from_str(optarg);
+ break;
+ case '0': /* trigger */
+ if (params->events) {
+ retval = trace_event_add_trigger(params->events, optarg);
+ if (retval) {
+ err_msg("Error adding trigger %s\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ osnoise_top_usage("--trigger requires a previous -e\n");
+ }
+ break;
+ case '1': /* filter */
+ if (params->events) {
+ retval = trace_event_add_filter(params->events, optarg);
+ if (retval) {
+ err_msg("Error adding filter %s\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ osnoise_top_usage("--filter requires a previous -e\n");
+ }
+ break;
default:
osnoise_top_usage("Invalid option");
}
@@ -425,6 +487,14 @@ osnoise_top_apply_config(struct osnoise_tool *tool, struct osnoise_top_params *p
}
}
+ if (params->threshold) {
+ retval = osnoise_set_tracing_thresh(tool->context, params->threshold);
+ if (retval) {
+ err_msg("Failed to set tracing_thresh\n");
+ goto out_err;
+ }
+ }
+
return 0;
out_err:
@@ -502,7 +572,7 @@ int osnoise_top_main(int argc, char **argv)
retval = osnoise_top_apply_config(tool, params);
if (retval) {
err_msg("Could not apply config\n");
- goto out_top;
+ goto out_free;
}
trace = &tool->trace;
@@ -510,14 +580,14 @@ int osnoise_top_main(int argc, char **argv)
retval = enable_osnoise(trace);
if (retval) {
err_msg("Failed to enable osnoise tracer\n");
- goto out_top;
+ goto out_free;
}
if (params->set_sched) {
retval = set_comm_sched_attr("osnoise/", &params->sched_param);
if (retval) {
err_msg("Failed to set sched parameters\n");
- goto out_top;
+ goto out_free;
}
}
@@ -527,15 +597,22 @@ int osnoise_top_main(int argc, char **argv)
record = osnoise_init_trace_tool("osnoise");
if (!record) {
err_msg("Failed to enable the trace instance\n");
- goto out_top;
+ goto out_free;
}
+
+ if (params->events) {
+ retval = trace_events_enable(&record->trace, params->events);
+ if (retval)
+ goto out_top;
+ }
+
trace_instance_start(&record->trace);
}
tool->start_time = time(NULL);
osnoise_top_set_signals(params);
- do {
+ while (!stop_tracing) {
sleep(params->sleep_time);
retval = tracefs_iterate_raw_events(trace->tep,
@@ -552,16 +629,16 @@ int osnoise_top_main(int argc, char **argv)
if (!params->quiet)
osnoise_print_stats(params, tool);
- if (!tracefs_trace_is_on(trace->inst))
+ if (trace_is_off(&tool->trace, &record->trace))
break;
- } while (!stop_tracing);
+ }
osnoise_print_stats(params, tool);
return_value = 0;
- if (!tracefs_trace_is_on(trace->inst)) {
+ if (trace_is_off(&tool->trace, &record->trace)) {
printf("osnoise hit stop tracing\n");
if (params->trace_output) {
printf(" Saving trace to %s\n", params->trace_output);
@@ -570,6 +647,9 @@ int osnoise_top_main(int argc, char **argv)
}
out_top:
+ trace_events_destroy(&record->trace, params->events);
+ params->events = NULL;
+out_free:
osnoise_free_top(tool->data);
osnoise_destroy_tool(record);
osnoise_destroy_tool(tool);
diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c
index 237e1735afa7..f3ec628f5e51 100644
--- a/tools/tracing/rtla/src/timerlat_hist.c
+++ b/tools/tracing/rtla/src/timerlat_hist.c
@@ -28,7 +28,9 @@ struct timerlat_hist_params {
int output_divisor;
int duration;
int set_sched;
+ int dma_latency;
struct sched_attr sched_param;
+ struct trace_events *events;
char no_irq;
char no_thread;
@@ -428,11 +430,13 @@ static void timerlat_hist_usage(char *usage)
char *msg[] = {
"",
- " usage: [rtla] timerlat hist [-h] [-q] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] [-t[=file]] \\",
- " [-c cpu-list] [-P priority] [-E N] [-b N] [--no-irq] [--no-thread] [--no-header] [--no-summary] \\",
- " [--no-index] [--with-zeros]",
+ " usage: [rtla] timerlat hist [-h] [-q] [-d s] [-D] [-n] [-a us] [-p us] [-i us] [-T us] [-s us] \\",
+ " [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] \\",
+ " [-P priority] [-E N] [-b N] [--no-irq] [--no-thread] [--no-header] [--no-summary] \\",
+ " [--no-index] [--with-zeros] [--dma-latency us]",
"",
" -h/--help: print this menu",
+ " -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit",
" -p/--period us: timerlat period in us",
" -i/--irq us: stop trace if the irq latency is higher than the argument in us",
" -T/--thread us: stop trace if the thread latency is higher than the argument in us",
@@ -440,7 +444,10 @@ static void timerlat_hist_usage(char *usage)
" -c/--cpus cpus: run the tracer only on the given cpus",
" -d/--duration time[m|h|d]: duration of the session in seconds",
" -D/--debug: print debug info",
- " -T/--trace[=file]: save the stopped trace to [file|timerlat_trace.txt]",
+ " -t/--trace[=file]: save the stopped trace to [file|timerlat_trace.txt]",
+ " -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed",
+ " --filter <filter>: enable a trace event filter to the previous -e event",
+ " --trigger <trigger>: enable a trace event trigger to the previous -e event",
" -n/--nano: display data in nanoseconds",
" -b/--bucket-size N: set the histogram bucket size (default 1)",
" -E/--entries N: set the number of entries of the histogram (default 256)",
@@ -450,6 +457,7 @@ static void timerlat_hist_usage(char *usage)
" --no-summary: do not print summary",
" --no-index: do not print index",
" --with-zeros: print zero only entries",
+ " --dma-latency us: set /dev/cpu_dma_latency latency <us> to reduce exit from idle latency",
" -P/--priority o:prio|r:prio|f:prio|d:runtime:period : set scheduling parameters",
" o:prio - use SCHED_OTHER with prio",
" r:prio - use SCHED_RR with prio",
@@ -477,6 +485,8 @@ static struct timerlat_hist_params
*timerlat_hist_parse_args(int argc, char *argv[])
{
struct timerlat_hist_params *params;
+ struct trace_events *tevent;
+ int auto_thresh;
int retval;
int c;
@@ -484,6 +494,9 @@ static struct timerlat_hist_params
if (!params)
exit(1);
+ /* disabled by default */
+ params->dma_latency = -1;
+
/* display data in microseconds */
params->output_divisor = 1000;
params->bucket_size = 1;
@@ -491,6 +504,7 @@ static struct timerlat_hist_params
while (1) {
static struct option long_options[] = {
+ {"auto", required_argument, 0, 'a'},
{"cpus", required_argument, 0, 'c'},
{"bucket-size", required_argument, 0, 'b'},
{"debug", no_argument, 0, 'D'},
@@ -504,19 +518,23 @@ static struct timerlat_hist_params
{"stack", required_argument, 0, 's'},
{"thread", required_argument, 0, 'T'},
{"trace", optional_argument, 0, 't'},
+ {"event", required_argument, 0, 'e'},
{"no-irq", no_argument, 0, '0'},
{"no-thread", no_argument, 0, '1'},
{"no-header", no_argument, 0, '2'},
{"no-summary", no_argument, 0, '3'},
{"no-index", no_argument, 0, '4'},
{"with-zeros", no_argument, 0, '5'},
+ {"trigger", required_argument, 0, '6'},
+ {"filter", required_argument, 0, '7'},
+ {"dma-latency", required_argument, 0, '8'},
{0, 0, 0, 0}
};
/* getopt_long stores the option index here. */
int option_index = 0;
- c = getopt_long(argc, argv, "c:b:d:E:Dhi:np:P:s:t::T:012345",
+ c = getopt_long(argc, argv, "a:c:b:d:e:E:Dhi:np:P:s:t::T:0123456:7:8:",
long_options, &option_index);
/* detect the end of the options. */
@@ -524,6 +542,19 @@ static struct timerlat_hist_params
break;
switch (c) {
+ case 'a':
+ auto_thresh = get_llong_from_str(optarg);
+
+ /* set thread stop to auto_thresh */
+ params->stop_total_us = auto_thresh;
+
+ /* get stack trace */
+ params->print_stack = auto_thresh;
+
+ /* set trace */
+ params->trace_output = "timerlat_trace.txt";
+
+ break;
case 'c':
retval = parse_cpu_list(optarg, &params->monitored_cpus);
if (retval)
@@ -543,6 +574,18 @@ static struct timerlat_hist_params
if (!params->duration)
timerlat_hist_usage("Invalid -D duration\n");
break;
+ case 'e':
+ tevent = trace_event_alloc(optarg);
+ if (!tevent) {
+ err_msg("Error alloc trace event");
+ exit(EXIT_FAILURE);
+ }
+
+ if (params->events)
+ tevent->next = params->events;
+
+ params->events = tevent;
+ break;
case 'E':
params->entries = get_llong_from_str(optarg);
if ((params->entries < 10) || (params->entries > 9999999))
@@ -600,6 +643,35 @@ static struct timerlat_hist_params
case '5': /* with zeros */
params->with_zeros = 1;
break;
+ case '6': /* trigger */
+ if (params->events) {
+ retval = trace_event_add_trigger(params->events, optarg);
+ if (retval) {
+ err_msg("Error adding trigger %s\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ timerlat_hist_usage("--trigger requires a previous -e\n");
+ }
+ break;
+ case '7': /* filter */
+ if (params->events) {
+ retval = trace_event_add_filter(params->events, optarg);
+ if (retval) {
+ err_msg("Error adding filter %s\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ timerlat_hist_usage("--filter requires a previous -e\n");
+ }
+ break;
+ case '8':
+ params->dma_latency = get_llong_from_str(optarg);
+ if (params->dma_latency < 0 || params->dma_latency > 10000) {
+ err_msg("--dma-latency needs to be >= 0 and < 10000");
+ exit(EXIT_FAILURE);
+ }
+ break;
default:
timerlat_hist_usage("Invalid option");
}
@@ -732,6 +804,7 @@ int timerlat_hist_main(int argc, char *argv[])
struct osnoise_tool *record = NULL;
struct osnoise_tool *tool = NULL;
struct trace_instance *trace;
+ int dma_latency_fd = -1;
int return_value = 1;
int retval;
@@ -748,7 +821,7 @@ int timerlat_hist_main(int argc, char *argv[])
retval = timerlat_hist_apply_config(tool, params);
if (retval) {
err_msg("Could not apply config\n");
- goto out_hist;
+ goto out_free;
}
trace = &tool->trace;
@@ -756,14 +829,22 @@ int timerlat_hist_main(int argc, char *argv[])
retval = enable_timerlat(trace);
if (retval) {
err_msg("Failed to enable timerlat tracer\n");
- goto out_hist;
+ goto out_free;
}
if (params->set_sched) {
retval = set_comm_sched_attr("timerlat/", &params->sched_param);
if (retval) {
err_msg("Failed to set sched parameters\n");
- goto out_hist;
+ goto out_free;
+ }
+ }
+
+ if (params->dma_latency >= 0) {
+ dma_latency_fd = set_cpu_dma_latency(params->dma_latency);
+ if (dma_latency_fd < 0) {
+ err_msg("Could not set /dev/cpu_dma_latency.\n");
+ goto out_free;
}
}
@@ -773,8 +854,15 @@ int timerlat_hist_main(int argc, char *argv[])
record = osnoise_init_trace_tool("timerlat");
if (!record) {
err_msg("Failed to enable the trace instance\n");
- goto out_hist;
+ goto out_free;
}
+
+ if (params->events) {
+ retval = trace_events_enable(&record->trace, params->events);
+ if (retval)
+ goto out_hist;
+ }
+
trace_instance_start(&record->trace);
}
@@ -795,15 +883,15 @@ int timerlat_hist_main(int argc, char *argv[])
goto out_hist;
}
- if (!tracefs_trace_is_on(trace->inst))
+ if (trace_is_off(&tool->trace, &record->trace))
break;
- };
+ }
timerlat_print_stats(params, tool);
return_value = 0;
- if (!tracefs_trace_is_on(trace->inst)) {
+ if (trace_is_off(&tool->trace, &record->trace)) {
printf("rtla timelat hit stop tracing\n");
if (params->trace_output) {
printf(" Saving trace to %s\n", params->trace_output);
@@ -812,6 +900,11 @@ int timerlat_hist_main(int argc, char *argv[])
}
out_hist:
+ if (dma_latency_fd >= 0)
+ close(dma_latency_fd);
+ trace_events_destroy(&record->trace, params->events);
+ params->events = NULL;
+out_free:
timerlat_free_histogram(tool->data);
osnoise_destroy_tool(record);
osnoise_destroy_tool(tool);
diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c
index d4187f6534ed..35452a1d45e9 100644
--- a/tools/tracing/rtla/src/timerlat_top.c
+++ b/tools/tracing/rtla/src/timerlat_top.c
@@ -29,7 +29,9 @@ struct timerlat_top_params {
int duration;
int quiet;
int set_sched;
+ int dma_latency;
struct sched_attr sched_param;
+ struct trace_events *events;
};
struct timerlat_top_cpu {
@@ -266,10 +268,12 @@ static void timerlat_top_usage(char *usage)
static const char *const msg[] = {
"",
- " usage: rtla timerlat [top] [-h] [-q] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] [-t[=file]] \\",
- " [-c cpu-list] [-P priority]",
+ " usage: rtla timerlat [top] [-h] [-q] [-a us] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] \\",
+ " [[-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] \\",
+ " [-P priority] [--dma-latency us]",
"",
" -h/--help: print this menu",
+ " -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit",
" -p/--period us: timerlat period in us",
" -i/--irq us: stop trace if the irq latency is higher than the argument in us",
" -T/--thread us: stop trace if the thread latency is higher than the argument in us",
@@ -278,8 +282,12 @@ static void timerlat_top_usage(char *usage)
" -d/--duration time[m|h|d]: duration of the session in seconds",
" -D/--debug: print debug info",
" -t/--trace[=file]: save the stopped trace to [file|timerlat_trace.txt]",
+ " -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed",
+ " --filter <command>: enable a trace event filter to the previous -e event",
+ " --trigger <command>: enable a trace event trigger to the previous -e event",
" -n/--nano: display data in nanoseconds",
" -q/--quiet print only a summary at the end",
+ " --dma-latency us: set /dev/cpu_dma_latency latency <us> to reduce exit from idle latency",
" -P/--priority o:prio|r:prio|f:prio|d:runtime:period : set scheduling parameters",
" o:prio - use SCHED_OTHER with prio",
" r:prio - use SCHED_RR with prio",
@@ -307,6 +315,8 @@ static struct timerlat_top_params
*timerlat_top_parse_args(int argc, char **argv)
{
struct timerlat_top_params *params;
+ struct trace_events *tevent;
+ long long auto_thresh;
int retval;
int c;
@@ -314,14 +324,19 @@ static struct timerlat_top_params
if (!params)
exit(1);
+ /* disabled by default */
+ params->dma_latency = -1;
+
/* display data in microseconds */
params->output_divisor = 1000;
while (1) {
static struct option long_options[] = {
+ {"auto", required_argument, 0, 'a'},
{"cpus", required_argument, 0, 'c'},
{"debug", no_argument, 0, 'D'},
{"duration", required_argument, 0, 'd'},
+ {"event", required_argument, 0, 'e'},
{"help", no_argument, 0, 'h'},
{"irq", required_argument, 0, 'i'},
{"nano", no_argument, 0, 'n'},
@@ -331,13 +346,16 @@ static struct timerlat_top_params
{"stack", required_argument, 0, 's'},
{"thread", required_argument, 0, 'T'},
{"trace", optional_argument, 0, 't'},
+ {"trigger", required_argument, 0, '0'},
+ {"filter", required_argument, 0, '1'},
+ {"dma-latency", required_argument, 0, '2'},
{0, 0, 0, 0}
};
/* getopt_long stores the option index here. */
int option_index = 0;
- c = getopt_long(argc, argv, "c:d:Dhi:np:P:qs:t::T:",
+ c = getopt_long(argc, argv, "a:c:d:De:hi:np:P:qs:t::T:0:1:2:",
long_options, &option_index);
/* detect the end of the options. */
@@ -345,6 +363,19 @@ static struct timerlat_top_params
break;
switch (c) {
+ case 'a':
+ auto_thresh = get_llong_from_str(optarg);
+
+ /* set thread stop to auto_thresh */
+ params->stop_total_us = auto_thresh;
+
+ /* get stack trace */
+ params->print_stack = auto_thresh;
+
+ /* set trace */
+ params->trace_output = "timerlat_trace.txt";
+
+ break;
case 'c':
retval = parse_cpu_list(optarg, &params->monitored_cpus);
if (retval)
@@ -359,6 +390,17 @@ static struct timerlat_top_params
if (!params->duration)
timerlat_top_usage("Invalid -D duration\n");
break;
+ case 'e':
+ tevent = trace_event_alloc(optarg);
+ if (!tevent) {
+ err_msg("Error alloc trace event");
+ exit(EXIT_FAILURE);
+ }
+
+ if (params->events)
+ tevent->next = params->events;
+ params->events = tevent;
+ break;
case 'h':
case '?':
timerlat_top_usage(NULL);
@@ -396,6 +438,35 @@ static struct timerlat_top_params
else
params->trace_output = "timerlat_trace.txt";
break;
+ case '0': /* trigger */
+ if (params->events) {
+ retval = trace_event_add_trigger(params->events, optarg);
+ if (retval) {
+ err_msg("Error adding trigger %s\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ timerlat_top_usage("--trigger requires a previous -e\n");
+ }
+ break;
+ case '1': /* filter */
+ if (params->events) {
+ retval = trace_event_add_filter(params->events, optarg);
+ if (retval) {
+ err_msg("Error adding filter %s\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ timerlat_top_usage("--filter requires a previous -e\n");
+ }
+ break;
+ case '2': /* dma-latency */
+ params->dma_latency = get_llong_from_str(optarg);
+ if (params->dma_latency < 0 || params->dma_latency > 10000) {
+ err_msg("--dma-latency needs to be >= 0 and < 10000");
+ exit(EXIT_FAILURE);
+ }
+ break;
default:
timerlat_top_usage("Invalid option");
}
@@ -524,6 +595,7 @@ int timerlat_top_main(int argc, char *argv[])
struct osnoise_tool *record = NULL;
struct osnoise_tool *top = NULL;
struct trace_instance *trace;
+ int dma_latency_fd = -1;
int return_value = 1;
int retval;
@@ -540,7 +612,7 @@ int timerlat_top_main(int argc, char *argv[])
retval = timerlat_top_apply_config(top, params);
if (retval) {
err_msg("Could not apply config\n");
- goto out_top;
+ goto out_free;
}
trace = &top->trace;
@@ -548,14 +620,22 @@ int timerlat_top_main(int argc, char *argv[])
retval = enable_timerlat(trace);
if (retval) {
err_msg("Failed to enable timerlat tracer\n");
- goto out_top;
+ goto out_free;
}
if (params->set_sched) {
retval = set_comm_sched_attr("timerlat/", &params->sched_param);
if (retval) {
err_msg("Failed to set sched parameters\n");
- goto out_top;
+ goto out_free;
+ }
+ }
+
+ if (params->dma_latency >= 0) {
+ dma_latency_fd = set_cpu_dma_latency(params->dma_latency);
+ if (dma_latency_fd < 0) {
+ err_msg("Could not set /dev/cpu_dma_latency.\n");
+ goto out_free;
}
}
@@ -565,8 +645,15 @@ int timerlat_top_main(int argc, char *argv[])
record = osnoise_init_trace_tool("timerlat");
if (!record) {
err_msg("Failed to enable the trace instance\n");
- goto out_top;
+ goto out_free;
}
+
+ if (params->events) {
+ retval = trace_events_enable(&record->trace, params->events);
+ if (retval)
+ goto out_top;
+ }
+
trace_instance_start(&record->trace);
}
@@ -590,16 +677,16 @@ int timerlat_top_main(int argc, char *argv[])
if (!params->quiet)
timerlat_print_stats(params, top);
- if (!tracefs_trace_is_on(trace->inst))
+ if (trace_is_off(&top->trace, &record->trace))
break;
- };
+ }
timerlat_print_stats(params, top);
return_value = 0;
- if (!tracefs_trace_is_on(trace->inst)) {
+ if (trace_is_off(&top->trace, &record->trace)) {
printf("rtla timelat hit stop tracing\n");
if (params->trace_output) {
printf(" Saving trace to %s\n", params->trace_output);
@@ -608,6 +695,11 @@ int timerlat_top_main(int argc, char *argv[])
}
out_top:
+ if (dma_latency_fd >= 0)
+ close(dma_latency_fd);
+ trace_events_destroy(&record->trace, params->events);
+ params->events = NULL;
+out_free:
timerlat_free_top(top->data);
osnoise_destroy_tool(record);
osnoise_destroy_tool(top);
diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c
index 83de259abcc1..5784c9f9e570 100644
--- a/tools/tracing/rtla/src/trace.c
+++ b/tools/tracing/rtla/src/trace.c
@@ -190,3 +190,348 @@ int trace_instance_start(struct trace_instance *trace)
{
return tracefs_trace_on(trace->inst);
}
+
+/*
+ * trace_events_free - free a list of trace events
+ */
+static void trace_events_free(struct trace_events *events)
+{
+ struct trace_events *tevent = events;
+ struct trace_events *free_event;
+
+ while (tevent) {
+ free_event = tevent;
+
+ tevent = tevent->next;
+
+ if (free_event->filter)
+ free(free_event->filter);
+ if (free_event->trigger)
+ free(free_event->trigger);
+ free(free_event->system);
+ free(free_event);
+ }
+}
+
+/*
+ * trace_event_alloc - alloc and parse a single trace event
+ */
+struct trace_events *trace_event_alloc(const char *event_string)
+{
+ struct trace_events *tevent;
+
+ tevent = calloc(1, sizeof(*tevent));
+ if (!tevent)
+ return NULL;
+
+ tevent->system = strdup(event_string);
+ if (!tevent->system) {
+ free(tevent);
+ return NULL;
+ }
+
+ tevent->event = strstr(tevent->system, ":");
+ if (tevent->event) {
+ *tevent->event = '\0';
+ tevent->event = &tevent->event[1];
+ }
+
+ return tevent;
+}
+
+/*
+ * trace_event_add_filter - record an event filter
+ */
+int trace_event_add_filter(struct trace_events *event, char *filter)
+{
+ if (event->filter)
+ free(event->filter);
+
+ event->filter = strdup(filter);
+ if (!event->filter)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * trace_event_add_trigger - record an event trigger action
+ */
+int trace_event_add_trigger(struct trace_events *event, char *trigger)
+{
+ if (event->trigger)
+ free(event->trigger);
+
+ event->trigger = strdup(trigger);
+ if (!event->trigger)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * trace_event_disable_filter - disable an event filter
+ */
+static void trace_event_disable_filter(struct trace_instance *instance,
+ struct trace_events *tevent)
+{
+ char filter[1024];
+ int retval;
+
+ if (!tevent->filter)
+ return;
+
+ if (!tevent->filter_enabled)
+ return;
+
+ debug_msg("Disabling %s:%s filter %s\n", tevent->system,
+ tevent->event ? : "*", tevent->filter);
+
+ snprintf(filter, 1024, "!%s\n", tevent->filter);
+
+ retval = tracefs_event_file_write(instance->inst, tevent->system,
+ tevent->event, "filter", filter);
+ if (retval < 0)
+ err_msg("Error disabling %s:%s filter %s\n", tevent->system,
+ tevent->event ? : "*", tevent->filter);
+}
+
+/*
+ * trace_event_save_hist - save the content of an event hist
+ *
+ * If the trigger is a hist: one, save the content of the hist file.
+ */
+static void trace_event_save_hist(struct trace_instance *instance,
+ struct trace_events *tevent)
+{
+ int retval, index, out_fd;
+ mode_t mode = 0644;
+ char path[1024];
+ char *hist;
+
+ if (!tevent)
+ return;
+
+ /* trigger enables hist */
+ if (!tevent->trigger)
+ return;
+
+ /* is this a hist: trigger? */
+ retval = strncmp(tevent->trigger, "hist:", strlen("hist:"));
+ if (retval)
+ return;
+
+ snprintf(path, 1024, "%s_%s_hist.txt", tevent->system, tevent->event);
+
+ printf(" Saving event %s:%s hist to %s\n", tevent->system, tevent->event, path);
+
+ out_fd = creat(path, mode);
+ if (out_fd < 0) {
+ err_msg(" Failed to create %s output file\n", path);
+ return;
+ }
+
+ hist = tracefs_event_file_read(instance->inst, tevent->system, tevent->event, "hist", 0);
+ if (!hist) {
+ err_msg(" Failed to read %s:%s hist file\n", tevent->system, tevent->event);
+ goto out_close;
+ }
+
+ index = 0;
+ do {
+ index += write(out_fd, &hist[index], strlen(hist) - index);
+ } while (index < strlen(hist));
+
+ free(hist);
+out_close:
+ close(out_fd);
+}
+
+/*
+ * trace_event_disable_trigger - disable an event trigger
+ */
+static void trace_event_disable_trigger(struct trace_instance *instance,
+ struct trace_events *tevent)
+{
+ char trigger[1024];
+ int retval;
+
+ if (!tevent->trigger)
+ return;
+
+ if (!tevent->trigger_enabled)
+ return;
+
+ debug_msg("Disabling %s:%s trigger %s\n", tevent->system,
+ tevent->event ? : "*", tevent->trigger);
+
+ trace_event_save_hist(instance, tevent);
+
+ snprintf(trigger, 1024, "!%s\n", tevent->trigger);
+
+ retval = tracefs_event_file_write(instance->inst, tevent->system,
+ tevent->event, "trigger", trigger);
+ if (retval < 0)
+ err_msg("Error disabling %s:%s trigger %s\n", tevent->system,
+ tevent->event ? : "*", tevent->trigger);
+}
+
+/*
+ * trace_events_disable - disable all trace events
+ */
+void trace_events_disable(struct trace_instance *instance,
+ struct trace_events *events)
+{
+ struct trace_events *tevent = events;
+
+ if (!events)
+ return;
+
+ while (tevent) {
+ debug_msg("Disabling event %s:%s\n", tevent->system, tevent->event ? : "*");
+ if (tevent->enabled) {
+ trace_event_disable_filter(instance, tevent);
+ trace_event_disable_trigger(instance, tevent);
+ tracefs_event_disable(instance->inst, tevent->system, tevent->event);
+ }
+
+ tevent->enabled = 0;
+ tevent = tevent->next;
+ }
+}
+
+/*
+ * trace_event_enable_filter - enable an event filter associated with an event
+ */
+static int trace_event_enable_filter(struct trace_instance *instance,
+ struct trace_events *tevent)
+{
+ char filter[1024];
+ int retval;
+
+ if (!tevent->filter)
+ return 0;
+
+ if (!tevent->event) {
+ err_msg("Filter %s applies only for single events, not for all %s:* events\n",
+ tevent->filter, tevent->system);
+ return 1;
+ }
+
+ snprintf(filter, 1024, "%s\n", tevent->filter);
+
+ debug_msg("Enabling %s:%s filter %s\n", tevent->system,
+ tevent->event ? : "*", tevent->filter);
+
+ retval = tracefs_event_file_write(instance->inst, tevent->system,
+ tevent->event, "filter", filter);
+ if (retval < 0) {
+ err_msg("Error enabling %s:%s filter %s\n", tevent->system,
+ tevent->event ? : "*", tevent->filter);
+ return 1;
+ }
+
+ tevent->filter_enabled = 1;
+ return 0;
+}
+
+/*
+ * trace_event_enable_trigger - enable an event trigger associated with an event
+ */
+static int trace_event_enable_trigger(struct trace_instance *instance,
+ struct trace_events *tevent)
+{
+ char trigger[1024];
+ int retval;
+
+ if (!tevent->trigger)
+ return 0;
+
+ if (!tevent->event) {
+ err_msg("Trigger %s applies only for single events, not for all %s:* events\n",
+ tevent->trigger, tevent->system);
+ return 1;
+ }
+
+ snprintf(trigger, 1024, "%s\n", tevent->trigger);
+
+ debug_msg("Enabling %s:%s trigger %s\n", tevent->system,
+ tevent->event ? : "*", tevent->trigger);
+
+ retval = tracefs_event_file_write(instance->inst, tevent->system,
+ tevent->event, "trigger", trigger);
+ if (retval < 0) {
+ err_msg("Error enabling %s:%s trigger %s\n", tevent->system,
+ tevent->event ? : "*", tevent->trigger);
+ return 1;
+ }
+
+ tevent->trigger_enabled = 1;
+
+ return 0;
+}
+
+/*
+ * trace_events_enable - enable all events
+ */
+int trace_events_enable(struct trace_instance *instance,
+ struct trace_events *events)
+{
+ struct trace_events *tevent = events;
+ int retval;
+
+ while (tevent) {
+ debug_msg("Enabling event %s:%s\n", tevent->system, tevent->event ? : "*");
+ retval = tracefs_event_enable(instance->inst, tevent->system, tevent->event);
+ if (retval < 0) {
+ err_msg("Error enabling event %s:%s\n", tevent->system,
+ tevent->event ? : "*");
+ return 1;
+ }
+
+ retval = trace_event_enable_filter(instance, tevent);
+ if (retval)
+ return 1;
+
+ retval = trace_event_enable_trigger(instance, tevent);
+ if (retval)
+ return 1;
+
+ tevent->enabled = 1;
+ tevent = tevent->next;
+ }
+
+ return 0;
+}
+
+/*
+ * trace_events_destroy - disable and free all trace events
+ */
+void trace_events_destroy(struct trace_instance *instance,
+ struct trace_events *events)
+{
+ if (!events)
+ return;
+
+ trace_events_disable(instance, events);
+ 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;
+}
diff --git a/tools/tracing/rtla/src/trace.h b/tools/tracing/rtla/src/trace.h
index 0ea1df0ad9a7..2e9a89a25615 100644
--- a/tools/tracing/rtla/src/trace.h
+++ b/tools/tracing/rtla/src/trace.h
@@ -2,6 +2,17 @@
#include <tracefs.h>
#include <stddef.h>
+struct trace_events {
+ struct trace_events *next;
+ char *system;
+ char *event;
+ char *filter;
+ char *trigger;
+ char enabled;
+ char filter_enabled;
+ char trigger_enabled;
+};
+
struct trace_instance {
struct tracefs_instance *inst;
struct tep_handle *tep;
@@ -25,3 +36,15 @@ void destroy_instance(struct tracefs_instance *inst);
int save_trace_to_file(struct tracefs_instance *inst, const char *filename);
int collect_registered_events(struct tep_event *tep, struct tep_record *record,
int cpu, void *context);
+
+struct trace_events *trace_event_alloc(const char *event_string);
+void trace_events_disable(struct trace_instance *instance,
+ struct trace_events *events);
+void trace_events_destroy(struct trace_instance *instance,
+ struct trace_events *events);
+int trace_events_enable(struct trace_instance *instance,
+ struct trace_events *events);
+
+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);
diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c
index ffaf8ec84001..5352167a1e75 100644
--- a/tools/tracing/rtla/src/utils.c
+++ b/tools/tracing/rtla/src/utils.c
@@ -3,13 +3,14 @@
* Copyright (C) 2021 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
*/
-#include <proc/readproc.h>
+#include <dirent.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
+#include <fcntl.h>
#include <sched.h>
#include <stdio.h>
@@ -254,50 +255,114 @@ int __set_sched_attr(int pid, struct sched_attr *attr)
retval = sched_setattr(pid, attr, flags);
if (retval < 0) {
- err_msg("boost_with_deadline failed to boost pid %d: %s\n",
+ err_msg("Failed to set sched attributes to the pid %d: %s\n",
pid, strerror(errno));
return 1;
}
return 0;
}
+
/*
- * set_comm_sched_attr - set sched params to threads starting with char *comm
+ * procfs_is_workload_pid - check if a procfs entry contains a comm_prefix* comm
+ *
+ * Check if the procfs entry is a directory of a process, and then check if the
+ * process has a comm with the prefix set in char *comm_prefix. As the
+ * current users of this function only check for kernel threads, there is no
+ * need to check for the threads for the process.
*
- * This function uses procps to list the currently running threads and then
- * set the sched_attr *attr to the threads that start with char *comm. It is
+ * Return: True if the proc_entry contains a comm file with comm_prefix*.
+ * Otherwise returns false.
+ */
+static int procfs_is_workload_pid(const char *comm_prefix, struct dirent *proc_entry)
+{
+ char buffer[MAX_PATH];
+ int comm_fd, retval;
+ char *t_name;
+
+ if (proc_entry->d_type != DT_DIR)
+ return 0;
+
+ if (*proc_entry->d_name == '.')
+ return 0;
+
+ /* check if the string is a pid */
+ for (t_name = proc_entry->d_name; t_name; t_name++) {
+ if (!isdigit(*t_name))
+ break;
+ }
+
+ if (*t_name != '\0')
+ return 0;
+
+ snprintf(buffer, MAX_PATH, "/proc/%s/comm", proc_entry->d_name);
+ comm_fd = open(buffer, O_RDONLY);
+ if (comm_fd < 0)
+ return 0;
+
+ memset(buffer, 0, MAX_PATH);
+ retval = read(comm_fd, buffer, MAX_PATH);
+
+ close(comm_fd);
+
+ if (retval <= 0)
+ return 0;
+
+ retval = strncmp(comm_prefix, buffer, strlen(comm_prefix));
+ if (retval)
+ return 0;
+
+ /* comm already have \n */
+ debug_msg("Found workload pid:%s comm:%s", proc_entry->d_name, buffer);
+
+ return 1;
+}
+
+/*
+ * set_comm_sched_attr - set sched params to threads starting with char *comm_prefix
+ *
+ * This function uses procfs to list the currently running threads and then set the
+ * sched_attr *attr to the threads that start with char *comm_prefix. It is
* mainly used to set the priority to the kernel threads created by the
* tracers.
*/
-int set_comm_sched_attr(const char *comm, struct sched_attr *attr)
+int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr)
{
- int flags = PROC_FILLCOM | PROC_FILLSTAT;
- PROCTAB *ptp;
- proc_t task;
+ struct dirent *proc_entry;
+ DIR *procfs;
int retval;
- ptp = openproc(flags);
- if (!ptp) {
- err_msg("error openproc()\n");
- return -ENOENT;
+ if (strlen(comm_prefix) >= MAX_PATH) {
+ err_msg("Command prefix is too long: %d < strlen(%s)\n",
+ MAX_PATH, comm_prefix);
+ return 1;
+ }
+
+ procfs = opendir("/proc");
+ if (!procfs) {
+ err_msg("Could not open procfs\n");
+ return 1;
}
- memset(&task, 0, sizeof(task));
+ while ((proc_entry = readdir(procfs))) {
- while (readproc(ptp, &task)) {
- retval = strncmp(comm, task.cmd, strlen(comm));
- if (retval)
+ retval = procfs_is_workload_pid(comm_prefix, proc_entry);
+ if (!retval)
continue;
- retval = __set_sched_attr(task.tid, attr);
- if (retval)
+
+ /* procfs_is_workload_pid confirmed it is a pid */
+ retval = __set_sched_attr(atoi(proc_entry->d_name), attr);
+ if (retval) {
+ err_msg("Error setting sched attributes for pid:%s\n", proc_entry->d_name);
goto out_err;
- }
+ }
- closeproc(ptp);
+ debug_msg("Set sched attributes for pid:%s\n", proc_entry->d_name);
+ }
return 0;
out_err:
- closeproc(ptp);
+ closedir(procfs);
return 1;
}
@@ -431,3 +496,35 @@ int parse_prio(char *arg, struct sched_attr *sched_param)
}
return 0;
}
+
+/*
+ * set_cpu_dma_latency - set the /dev/cpu_dma_latecy
+ *
+ * This is used to reduce the exit from idle latency. The value
+ * will be reset once the file descriptor of /dev/cpu_dma_latecy
+ * is closed.
+ *
+ * Return: the /dev/cpu_dma_latecy file descriptor
+ */
+int set_cpu_dma_latency(int32_t latency)
+{
+ int retval;
+ int fd;
+
+ fd = open("/dev/cpu_dma_latency", O_RDWR);
+ if (fd < 0) {
+ err_msg("Error opening /dev/cpu_dma_latency\n");
+ return -1;
+ }
+
+ retval = write(fd, &latency, 4);
+ if (retval < 1) {
+ err_msg("Error setting /dev/cpu_dma_latency\n");
+ close(fd);
+ return -1;
+ }
+
+ debug_msg("Set /dev/cpu_dma_latency to %d\n", latency);
+
+ return fd;
+}
diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h
index 9aa962319ca2..5571afd3b549 100644
--- a/tools/tracing/rtla/src/utils.h
+++ b/tools/tracing/rtla/src/utils.h
@@ -6,6 +6,7 @@
* '18446744073709551615\0'
*/
#define BUFF_U64_STR_SIZE 24
+#define MAX_PATH 1024
#define container_of(ptr, type, member)({ \
const typeof(((type *)0)->member) *__mptr = (ptr); \
@@ -53,4 +54,5 @@ struct sched_attr {
};
int parse_prio(char *arg, struct sched_attr *sched_param);
-int set_comm_sched_attr(const char *comm, struct sched_attr *attr);
+int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr);
+int set_cpu_dma_latency(int32_t latency);