Thread (9 messages) flat view 9 messages, 2 authors, 3d ago

Re: [PATCH v4 5/6] rtla: Unconditionally clean any pre-existing filters for user-provided events

From: Valentin Schneider <vschneid@redhat.com>
Date: 2026-08-13 17:59:13
Also in: lkml
Subsystem: real-time linux analysis (rtla) tools, the rest · Maintainers: Steven Rostedt, Tomas Glozar, Linus Torvalds

On 10/08/26 13:24, Tomas Glozar wrote:
út 4. 8. 2026 v 19:43 odesílatel Valentin Schneider
[off-list ref] napsal:
quoted
A later commit will apply a filter to events recorded to the trace
output. To prevent any user confusion, remove pre-existing filters when
enabling an event provided via the '-e' command line argument.

Suggested-by: Tomas Glozar <tglozar@redhat.com>
Signed-off-by: Valentin Schneider <vschneid@redhat.com>
---
I found that I missed one case when suggesting this: the user might
supply an event twice. With this change, it will now clear the filter
the second time the event is applied:

$ rtla timerlat hist --no-aa --on-threshold trace \
    --on-threshold shell,command="grep sched_switch timerlat_trace.txt
| grep -Fv '[000]' | head -n1" \
    -i 1 -e sched:sched_switch -e sched:sched_switch --filter "cpu == 0"

Without this commit:
 Saving trace to timerlat_trace.txt
# RTLA timerlat histogram
...
With this commit:
 Saving trace to timerlat_trace.txt
         <idle>-0       [002] d..2. 423185.347008: sched_switch: ...
# RTLA timerlat histogram
...
(Note that events are processed in opposite order to the command line.)

This is unexpected and might break scripts that for some reason enable
an event twice. So I'm not sure if my suggestion was the best
solution.
Hm, didn't think of that.

I would say having the last defined event+filter override any previous
filter would make the most sense.

trace-cmd does this partially:

bash-5.3# trace-cmd record -e sched_switch -f 'CPU==0' -e sched_switch -- bash -c 'ls &>/dev/null'
CPU0 data recorded at offset=0x180000
    109 bytes in size (8192 uncompressed)
CPU1 data recorded at offset=0x181000
    0 bytes in size (0 uncompressed)
CPU2 data recorded at offset=0x181000
    0 bytes in size (0 uncompressed)
CPU3 data recorded at offset=0x181000
    0 bytes in size (0 uncompressed)

bash-5.3# trace-cmd record -e sched_switch -f 'CPU==0' -e sched_switch -f 'CPU==1' -- bash -c 'ls &>/dev/null'
CPU0 data recorded at offset=0x180000
    0 bytes in size (0 uncompressed)
CPU1 data recorded at offset=0x180000
    1428 bytes in size (237568 uncompressed)
CPU2 data recorded at offset=0x181000
    0 bytes in size (0 uncompressed)
CPU3 data recorded at offset=0x181000
    0 bytes in size (0 uncompressed)

Although I didn't realize that events were handled in reverse cmdline input
order until you pointed it out.

AIUI filers and triggers rely on the LIFO ordering to grab the
last-provided event; making the events list double-linked (but not
circular) would let us process them in FIFO order; something like the
barely tested:

---
diff --git a/tools/tracing/rtla/src/cli_p.h b/tools/tracing/rtla/src/cli_p.h
index 3c939de9abf02..4638cc317ea26 100644
--- a/tools/tracing/rtla/src/cli_p.h
+++ b/tools/tracing/rtla/src/cli_p.h
@@ -221,8 +221,10 @@ static int opt_event_cb(const struct option *opt, const char *arg, int unset)
 	if (!tevent)
 		fatal("Error alloc trace event");
 
-	if (*events)
+	if (*events) {
 		tevent->next = *events;
+		(*events)->prev = tevent;
+	}
 	*events = tevent;
 
 	return 0;
diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c
index e407447773d04..35601a2e8d0c7 100644
--- a/tools/tracing/rtla/src/trace.c
+++ b/tools/tracing/rtla/src/trace.c
@@ -440,6 +440,18 @@ static void trace_event_disable_trigger(struct trace_instance *instance,
 			tevent->event ? : "*", tevent->trigger);
 }
 
+static inline struct trace_events *trace_events_tail(struct trace_events *tevent)
+{
+	while (tevent && tevent->next)
+		tevent = tevent->next;
+
+	return tevent;
+}
+
+/* Events are stashed in LIFO order; flip that to FIFO processing */
+#define for_each_trace_event(tevent) \
+	for (tevent = trace_events_tail(tevent); tevent; tevent = tevent->prev)
+
 /*
  * trace_events_disable - disable all trace events
  */
@@ -451,7 +463,7 @@ void trace_events_disable(struct trace_instance *instance,
 	if (!events)
 		return;
 
-	while (tevent) {
+	for_each_trace_event(tevent) {
 		debug_msg("Disabling event %s:%s\n", tevent->system, tevent->event ? : "*");
 		if (tevent->enabled) {
 			trace_event_disable_filter(instance, tevent);
@@ -460,7 +472,6 @@ void trace_events_disable(struct trace_instance *instance,
 		}
 
 		tevent->enabled = 0;
-		tevent = tevent->next;
 	}
 }
 
@@ -544,7 +555,10 @@ int trace_events_enable(struct trace_instance *instance,
 	struct trace_events *tevent = events;
 	int retval;
 
-	while (tevent) {
+	if (!events)
+		return 0;
+
+	for_each_trace_event(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) {
@@ -562,7 +576,6 @@ int trace_events_enable(struct trace_instance *instance,
 			return 1;
 
 		tevent->enabled = 1;
-		tevent = tevent->next;
 	}
 
 	return 0;
diff --git a/tools/tracing/rtla/src/trace.h b/tools/tracing/rtla/src/trace.h
index 95b911a2228b2..eacafc0c96b31 100644
--- a/tools/tracing/rtla/src/trace.h
+++ b/tools/tracing/rtla/src/trace.h
@@ -4,6 +4,7 @@
 
 struct trace_events {
 	struct trace_events *next;
+	struct trace_events *prev;
 	char *system;
 	char *event;
 	char *filter;
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help