tracing: Add set_event_pid to filter on pids for events
Steven Rostedt
maintainercover tracing: Add set_event_pid to filter on pids for events
Currently the only way to filter pids for events is to add it to the filter file in the tracefs directory. Something like:
echo 'common_pid == 2123 || common_pid == 4211' > filter
The problem with this is that there's a very limited size that the filter can accept. Thus, trying to trace all processes of hackbench is not going to cut it.
I've added a new file called set_event_pid which when not empty will filter the events if the event is for one of the listed pids. It adds special hooks for sched_switch and sched_wakeup to handle next_pid and pid fields respectively.
I have code that will extend this to also dynamically add the children on these pids to the filter on fork. But that's still being worked on.
The filtering is done by a flag being set at sched_switch time, by hooking into the sched_switch tracepoint. When a process is scheduled in, it is checked against the list of pids in the set_event_pid file (bsearch) and if the files is not empty and the pid does not exist, a flag is set to ignore tracing the current task. Then all other tracepoints only need to check the flag to see if it should be ignored. This only affects events within a specific tracing instance. perf and other tracing instances will not be affected by another instance filtering.
The first thing that needed to be done was to add a priority to callbacks of tracepoints. The hook added to sched_switch that determines the if the task should be filtered or not must execute before any other callbacks for that tracepoint. Otherwise filtering the sched_switch tracepoint itself would not work.
The list of pids is allocated by pages. When changing (adding, removing or clearing pids) the file special care must be used, as there are no locks held when reading the list at sched switch. Normal RCU handling is used (synchronize_sched) as all callbacks from tracepoints are called with rcu_read_lock_sched() held.
This will allow for much better task filtering in the future.
Enjoy,
-- Steve
This series can be found at:
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
ftrace/event-pid-filter
Head SHA1: d4f2f260e337242f8a5773f48b98463b95def9a9
Steven Rostedt (Red Hat) (4):
tracepoint: Give priority to probes of tracepoints
tracing: Add set_event_pid directory for future use
tracing: Implement event pid filtering
tracing: Check all tasks on each CPU when filtering pids
----
include/linux/trace_events.h | 7 + include/linux/tracepoint.h | 13 ++ kernel/trace/trace.h | 9 + kernel/trace/trace_events.c | 451 +++++++++++++++++++++++++++++++++++++++++++ kernel/tracepoint.c | 61 ++++-- 5 files changed, 530 insertions(+), 11 deletions(-)
Steven Rostedt
maintainerRFC PATCH 1/4 tracepoint: Give priority to probes of tracepoints
From: "Steven Rostedt (Red Hat)" <[email protected]>
In order to guarantee that a probe will be called before other probes that are attached to a tracepoint, there needs to be a mechanism to provide priority of one probe over the others.
Adding a prio field to the struct tracepoint_func, which lets the probes be sorted by the priority set in the structure. If no priority is specified, then a priority of 10 is given (this is a macro, and perhaps may be changed in the future).
Now probes may be added to affect other probes that are attached to a tracepoint with a guaranteed order.
One use case would be to allow tracing of tracepoints be able to filter by pid. A special (higher priority probe) may be added to the sched_switch tracepoint and set the necessary flags of the other tracepoints to notify them if they should be traced or not. In case a tracepoint is enabled at the sched_switch tracepoint too, the order of the two are not random.
--- include/linux/tracepoint.h | 13 ++++++++++ kernel/tracepoint.c | 61 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 63 insertions(+), 11 deletions(-)
include/linux/tracepoint.h +13 -0
@@ -26,6 +26,7 @@ struct notifier_block;struct tracepoint_func {void *func;void *data; +int prio; };struct tracepoint {
@@ -42,9 +43,14 @@ struct trace_enum_map {unsigned long enum_value; }; +#define TRACEPOINT_DEFAULT_PRIO 10 +extern int tracepoint_probe_register (struct tracepoint *tp,void *probe,void *data);extern int +tracepoint_probe_register_prio (struct tracepoint *tp,void *probe,void *data, +int prio); +extern int tracepoint_probe_unregister (struct tracepoint *tp,void *probe,void *data); extern void for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv),
@@ -207,6 +213,13 @@ extern void syscall_unregfunc(void); (void *)probe, data); \ } \ static inline int \ + register_trace_prio_##name(void (*probe)(data_proto), void *data,\ + int prio) \ + { \ + return tracepoint_probe_register_prio(&__tracepoint_##name, \ + (void *)probe, data, prio); \ + } \ + static inline int \ unregister_trace_##name(void (*probe)(data_proto), void *data) \ { \ return tracepoint_probe_unregister(&__tracepoint_##name,\
kernel/tracepoint.c +50 -11
116 lines not on this page · raw message
Signature · 1 line
2.6.1
Steven Rostedt
maintainerRFC PATCH 2/4 tracing: Add set_event_pid directory for future use
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
Create a tracing directory called set_event_pid, which currently has no function, but will be used to filter all events for the tracing instance or the pids that are added to the file.
The reason no functionality is added with this commit is that this commit focuses on the creation and removal of the pids in a safe manner. And tests can be made against this change to make sure things are correct before hooking features to the list of pids.
--- kernel/trace/trace.h | 7 ++ kernel/trace/trace_events.c | 287 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 294 insertions(+)
kernel/trace/trace.h +7 -0
@@ -176,6 +176,12 @@ struct trace_options {struct trace_option_dentry *topts; }; +struct trace_pid_list { +unsigned int nr_pids; +int order; +pid_t *pids; +}; +/* * The trace array - an array of per-CPU trace arrays. This is the * highest level data structure that individual tracers deal with.
@@ -201,6 +207,7 @@ struct trace_array {bool allocated_snapshot;unsigned long max_latency;#endif +struct trace_pid_list __rcu *filtered_pids;/* * max_lock is used to protect the swapping of buffers * when taking a max snapshot. The buffers themselves are
kernel/trace/trace_events.c +287 -0
345 lines not on this page · raw message
Signature · 1 line
2.6.1
Steven Rostedt
maintainerRFC PATCH 3/4 tracing: Implement event pid filtering
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
Add the necessary hooks to use the pids loaded in set_event_pid to filter all the events enabled in the tracing instance that match the pids listed.
Two probes are added to both sched_switch and sched_wakeup tracepoints to be called before other probes are called and after the other probes are called. The first is used to set the necessary flags to let the probes know to test if they should be traced or not.
The sched_switch pre probe will set the "ignore_pid" flag if neither the previous or next task has a matching pid.
The sched_switch probe will set the "ignore_pid" flag if the next task does not match the matching pid.
The pre probe allows for probes tracing sched_switch to be traced if necessary.
The sched_wakeup pre probe will set the "ignore_pid" flag if neither the current task nor the wakee task has a matching pid.
The sched_wakeup post probe will set the "ignore_pid" flag if the current task does not have a matching pid.
--- include/linux/trace_events.h | 7 ++ kernel/trace/trace.h | 2 + kernel/trace/trace_events.c | 148 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 154 insertions(+), 3 deletions(-)
include/linux/trace_events.h +7 -0
@@ -328,6 +328,7 @@ enum {EVENT_FILE_FL_SOFT_DISABLED_BIT ,EVENT_FILE_FL_TRIGGER_MODE_BIT ,EVENT_FILE_FL_TRIGGER_COND_BIT , + EVENT_FILE_FL_PID_FILTER_BIT, };/*
@@ -341,6 +342,7 @@ enum {* tracepoint may be enabled) * TRIGGER_MODE - When set, invoke the triggers associated with the event * TRIGGER_COND - When set, one or more triggers has an associated filter +* PID_FILTER - When set, the event is filtered based on pid */ enum {EVENT_FILE_FL_ENABLED = (1 <<EVENT_FILE_FL_ENABLED_BIT ),
@@ -351,6 +353,7 @@ enum {EVENT_FILE_FL_SOFT_DISABLED = (1 <<EVENT_FILE_FL_SOFT_DISABLED_BIT ),EVENT_FILE_FL_TRIGGER_MODE = (1 <<EVENT_FILE_FL_TRIGGER_MODE_BIT ),EVENT_FILE_FL_TRIGGER_COND = (1 <<EVENT_FILE_FL_TRIGGER_COND_BIT ), + EVENT_FILE_FL_PID_FILTER = (1 << EVENT_FILE_FL_PID_FILTER_BIT), }; struct trace_event_file {
@@ -429,6 +432,8 @@ extern enum event_trigger_type event_triggers_call(struct trace_event_file *fileextern void event_triggers_post_call (struct trace_event_file *file,enum event_trigger_type tt); +bool trace_event_ignore_this_pid (struct trace_event_file *trace_file); +/** * trace_trigger_soft_disabled - do triggers and test if soft disabled * @file: The file pointer of the event to test
@@ -448,6 +453,8 @@ trace_trigger_soft_disabled(struct trace_event_file *file)event_triggers_call (file,NULL );if (eflags &EVENT_FILE_FL_SOFT_DISABLED )return true; +if (eflags &EVENT_FILE_FL_PID_FILTER ) +return trace_event_ignore_this_pid (file); }return false; }
kernel/trace/trace.h +2 -0
@@ -156,6 +156,8 @@ struct trace_array_cpu {pid_t pid;kuid_t uid;char comm[TASK_COMM_LEN ]; + +bool ignore_pid; };struct tracer ;
kernel/trace/trace_events.c +145 -3
206 lines not on this page · raw message
Signature · 1 line
2.6.1
Steven Rostedt
maintainerRFC PATCH 4/4 tracing: Check all tasks on each CPU when filtering pids
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
My tests found that if a task is running but not filtered when set_event_pid is modified, then it can still be traced.
Call on_each_cpu() to check if the current running task should be filtered and update the per cpu flags of tr->data appropriately.
--- kernel/trace/trace_events.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
kernel/trace/trace_events.c +22 -0
@@ -1549,6 +1549,22 @@ static int max_pids(struct trace_pid_list *pid_list)return (PAGE_SIZE << pid_list->order) /sizeof (pid_t); } +static void ignore_task_cpu (void *data) +{ +struct trace_array *tr = data; +struct trace_pid_list *pid_list; + +/* +* This function is called by on_each_cpu() while the +* event_mutex is held. +*/ + pid_list =rcu_dereference_protected (tr->filtered_pids, +mutex_is_locked (&event_mutex)); + +this_cpu_write (tr->trace_buffer.data->ignore_pid, +check_ignore_pid (pid_list, current)); +} +static ssize_t ftrace_event_pid_write (struct file *filp,const char __user *ubuf,size_t cnt,loff_t *ppos)
@@ -1711,6 +1727,12 @@ ftrace_event_pid_write(struct file *filp, const char __user *ubuf, tr, INT_MAX);register_trace_prio_sched_wakeup (event_filter_pid_sched_wakeup_probe_post, tr,0 ); + +/* +* Ignoring of pids is done at task switch. But we have to +* check for those tasks that are currently running. +*/ +on_each_cpu (ignore_task_cpu, tr,1 ); }mutex_unlock (&event_mutex);
Signature · 1 line
2.6.1