Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1382570 > unrolled thread
| Started by | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| First post | 2016-04-19 16:40 +0200 |
| Last post | 2016-04-19 22:40 +0200 |
| Articles | 4 — 2 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
[RFC][PATCH 3/4] tracing: Add infrastructure to allow set_event_pid to follow children Steven Rostedt <rostedt@goodmis.org> - 2016-04-19 16:40 +0200
Re: [RFC][PATCH 3/4] tracing: Add infrastructure to allow set_event_pid to follow children Mathieu Desnoyers <mathieu.desnoyers@efficios.com> - 2016-04-19 19:00 +0200
Re: [RFC][PATCH 3/4] tracing: Add infrastructure to allow set_event_pid to follow children Steven Rostedt <rostedt@goodmis.org> - 2016-04-19 19:20 +0200
Re: [RFC][PATCH 3/4] tracing: Add infrastructure to allow set_event_pid to follow children Mathieu Desnoyers <mathieu.desnoyers@efficios.com> - 2016-04-19 22:40 +0200
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2016-04-19 16:40 +0200 |
| Subject | [RFC][PATCH 3/4] tracing: Add infrastructure to allow set_event_pid to follow children |
| Message-ID | <rpEYO-8k2-17@gated-at.bofh.it> |
From: Steven Rostedt <rostedt@goodmis.org>
Add the infrastructure needed to have the PIDs in set_event_pid to
automatically add PIDs of the children of the tasks that have their PIDs in
set_event_pid. This will also remove PIDs from set_event_pid when a task
exits
This is implemented by adding hooks into the fork and exit tracepoints. On
fork, the PIDs are added to the list, and on exit, they are removed.
Add a new option called event_fork that when set, PIDs in set_event_pid will
automatically get their children PIDs added when they fork, as well as any
task that exits will have its PID removed from set_event_pid.
This works for instances as well.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
kernel/trace/trace.c | 3 ++
kernel/trace/trace.h | 2 ++
kernel/trace/trace_events.c | 84 +++++++++++++++++++++++++++++++++++++++------
3 files changed, 79 insertions(+), 10 deletions(-)
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index a2f0b9f33e9b..0d12dbde8399 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -3571,6 +3571,9 @@ int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled)
if (mask == TRACE_ITER_RECORD_CMD)
trace_event_enable_cmd_record(enabled);
+ if (mask == TRACE_ITER_EVENT_FORK)
+ trace_event_follow_fork(tr, enabled);
+
if (mask == TRACE_ITER_OVERWRITE) {
ring_buffer_change_overwrite(tr->trace_buffer.buffer, enabled);
#ifdef CONFIG_TRACER_MAX_TRACE
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 68cbb8e10aea..2525042760e6 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -655,6 +655,7 @@ static inline void __trace_stack(struct trace_array *tr, unsigned long flags,
extern cycle_t ftrace_now(int cpu);
extern void trace_find_cmdline(int pid, char comm[]);
+extern void trace_event_follow_fork(struct trace_array *tr, bool enable);
#ifdef CONFIG_DYNAMIC_FTRACE
extern unsigned long ftrace_update_tot_cnt;
@@ -966,6 +967,7 @@ extern int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
C(STOP_ON_FREE, "disable_on_free"), \
C(IRQ_INFO, "irq-info"), \
C(MARKERS, "markers"), \
+ C(EVENT_FORK, "event-fork"), \
FUNCTION_FLAGS \
FGRAPH_FLAGS \
STACK_FLAGS \
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 45f7cc72bf25..add81dff7520 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -474,11 +474,23 @@ static void ftrace_clear_events(struct trace_array *tr)
/* Shouldn't this be in a header? */
extern int pid_max;
+/* Returns true if found in filter */
static bool
-ignore_this_task(struct trace_pid_list *filtered_pids, struct task_struct *task)
+find_filtered_pid(struct trace_pid_list *filtered_pids, pid_t search_pid)
{
- pid_t pid;
+ /*
+ * If pid_max changed after filtered_pids was created, we
+ * by default ignore all pids greater than the previous pid_max.
+ */
+ if (search_pid >= filtered_pids->pid_max)
+ return false;
+
+ return test_bit(search_pid, filtered_pids->pids);
+}
+static bool
+ignore_this_task(struct trace_pid_list *filtered_pids, struct task_struct *task)
+{
/*
* Return false, because if filtered_pids does not exist,
* all pids are good to trace.
@@ -486,16 +498,68 @@ ignore_this_task(struct trace_pid_list *filtered_pids, struct task_struct *task)
if (!filtered_pids)
return false;
- pid = task->pid;
+ return !find_filtered_pid(filtered_pids, task->pid);
+}
- /*
- * If pid_max changed after filtered_pids was created, we
- * by default ignore all pids greater than the previous pid_max.
- */
- if (task->pid >= filtered_pids->pid_max)
- return true;
+static void filter_add_remove_task(struct trace_pid_list *pid_list,
+ struct task_struct *self,
+ struct task_struct *task)
+{
+ if (!pid_list)
+ return;
+
+ /* For forks, we only add if the forking task is listed */
+ if (self) {
+ if (!find_filtered_pid(pid_list, self->pid))
+ return;
+ }
+
+ /* Sorry, but we don't support pid_max changing after setting */
+ if (task->pid >= pid_list->pid_max)
+ return;
+
+ /* "self" is set for forks, and NULL for exits */
+ if (self)
+ set_bit(task->pid, pid_list->pids);
+ else
+ clear_bit(task->pid, pid_list->pids);
+}
+
+static void
+event_filter_pid_sched_process_exit(void *data, struct task_struct *task)
+{
+ struct trace_pid_list *pid_list;
+ struct trace_array *tr = data;
+
+ pid_list = rcu_dereference_sched(tr->filtered_pids);
+ filter_add_remove_task(pid_list, NULL, task);
+}
- return !test_bit(task->pid, filtered_pids->pids);
+static void
+event_filter_pid_sched_process_fork(void *data,
+ struct task_struct *self,
+ struct task_struct *task)
+{
+ struct trace_pid_list *pid_list;
+ struct trace_array *tr = data;
+
+ pid_list = rcu_dereference_sched(tr->filtered_pids);
+ filter_add_remove_task(pid_list, self, task);
+}
+
+void trace_event_follow_fork(struct trace_array *tr, bool enable)
+{
+ if (enable) {
+ register_trace_prio_sched_process_fork(event_filter_pid_sched_process_fork,
+ tr, INT_MIN);
+ register_trace_prio_sched_process_exit(event_filter_pid_sched_process_exit,
+ tr, INT_MAX);
+ } else {
+ unregister_trace_sched_process_fork(event_filter_pid_sched_process_fork,
+ tr);
+ unregister_trace_sched_process_exit(event_filter_pid_sched_process_exit,
+ tr);
+ }
}
static void
--
2.8.0.rc3
[toc] | [next] | [standalone]
| From | Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
|---|---|
| Date | 2016-04-19 19:00 +0200 |
| Subject | Re: [RFC][PATCH 3/4] tracing: Add infrastructure to allow set_event_pid to follow children |
| Message-ID | <rpHaj-1sn-41@gated-at.bofh.it> |
| In reply to | #1382570 |
----- On Apr 19, 2016, at 10:34 AM, rostedt rostedt@goodmis.org wrote:
> From: Steven Rostedt <rostedt@goodmis.org>
>
> Add the infrastructure needed to have the PIDs in set_event_pid to
> automatically add PIDs of the children of the tasks that have their PIDs in
> set_event_pid. This will also remove PIDs from set_event_pid when a task
> exits
>
> This is implemented by adding hooks into the fork and exit tracepoints. On
> fork, the PIDs are added to the list, and on exit, they are removed.
>
> Add a new option called event_fork that when set, PIDs in set_event_pid will
> automatically get their children PIDs added when they fork, as well as any
> task that exits will have its PID removed from set_event_pid.
Just out of curiosity: how does it deal with multi-process and multi-thread ?
What events are expected in each case ?
Thanks,
Mathieu
>
> This works for instances as well.
>
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> ---
> kernel/trace/trace.c | 3 ++
> kernel/trace/trace.h | 2 ++
> kernel/trace/trace_events.c | 84 +++++++++++++++++++++++++++++++++++++++------
> 3 files changed, 79 insertions(+), 10 deletions(-)
>
> diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
> index a2f0b9f33e9b..0d12dbde8399 100644
> --- a/kernel/trace/trace.c
> +++ b/kernel/trace/trace.c
> @@ -3571,6 +3571,9 @@ int set_tracer_flag(struct trace_array *tr, unsigned int
> mask, int enabled)
> if (mask == TRACE_ITER_RECORD_CMD)
> trace_event_enable_cmd_record(enabled);
>
> + if (mask == TRACE_ITER_EVENT_FORK)
> + trace_event_follow_fork(tr, enabled);
> +
> if (mask == TRACE_ITER_OVERWRITE) {
> ring_buffer_change_overwrite(tr->trace_buffer.buffer, enabled);
> #ifdef CONFIG_TRACER_MAX_TRACE
> diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
> index 68cbb8e10aea..2525042760e6 100644
> --- a/kernel/trace/trace.h
> +++ b/kernel/trace/trace.h
> @@ -655,6 +655,7 @@ static inline void __trace_stack(struct trace_array *tr,
> unsigned long flags,
> extern cycle_t ftrace_now(int cpu);
>
> extern void trace_find_cmdline(int pid, char comm[]);
> +extern void trace_event_follow_fork(struct trace_array *tr, bool enable);
>
> #ifdef CONFIG_DYNAMIC_FTRACE
> extern unsigned long ftrace_update_tot_cnt;
> @@ -966,6 +967,7 @@ extern int trace_get_user(struct trace_parser *parser, const
> char __user *ubuf,
> C(STOP_ON_FREE, "disable_on_free"), \
> C(IRQ_INFO, "irq-info"), \
> C(MARKERS, "markers"), \
> + C(EVENT_FORK, "event-fork"), \
> FUNCTION_FLAGS \
> FGRAPH_FLAGS \
> STACK_FLAGS \
> diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
> index 45f7cc72bf25..add81dff7520 100644
> --- a/kernel/trace/trace_events.c
> +++ b/kernel/trace/trace_events.c
> @@ -474,11 +474,23 @@ static void ftrace_clear_events(struct trace_array *tr)
> /* Shouldn't this be in a header? */
> extern int pid_max;
>
> +/* Returns true if found in filter */
> static bool
> -ignore_this_task(struct trace_pid_list *filtered_pids, struct task_struct
> *task)
> +find_filtered_pid(struct trace_pid_list *filtered_pids, pid_t search_pid)
> {
> - pid_t pid;
> + /*
> + * If pid_max changed after filtered_pids was created, we
> + * by default ignore all pids greater than the previous pid_max.
> + */
> + if (search_pid >= filtered_pids->pid_max)
> + return false;
> +
> + return test_bit(search_pid, filtered_pids->pids);
> +}
>
> +static bool
> +ignore_this_task(struct trace_pid_list *filtered_pids, struct task_struct
> *task)
> +{
> /*
> * Return false, because if filtered_pids does not exist,
> * all pids are good to trace.
> @@ -486,16 +498,68 @@ ignore_this_task(struct trace_pid_list *filtered_pids,
> struct task_struct *task)
> if (!filtered_pids)
> return false;
>
> - pid = task->pid;
> + return !find_filtered_pid(filtered_pids, task->pid);
> +}
>
> - /*
> - * If pid_max changed after filtered_pids was created, we
> - * by default ignore all pids greater than the previous pid_max.
> - */
> - if (task->pid >= filtered_pids->pid_max)
> - return true;
> +static void filter_add_remove_task(struct trace_pid_list *pid_list,
> + struct task_struct *self,
> + struct task_struct *task)
> +{
> + if (!pid_list)
> + return;
> +
> + /* For forks, we only add if the forking task is listed */
> + if (self) {
> + if (!find_filtered_pid(pid_list, self->pid))
> + return;
> + }
> +
> + /* Sorry, but we don't support pid_max changing after setting */
> + if (task->pid >= pid_list->pid_max)
> + return;
> +
> + /* "self" is set for forks, and NULL for exits */
> + if (self)
> + set_bit(task->pid, pid_list->pids);
> + else
> + clear_bit(task->pid, pid_list->pids);
> +}
> +
> +static void
> +event_filter_pid_sched_process_exit(void *data, struct task_struct *task)
> +{
> + struct trace_pid_list *pid_list;
> + struct trace_array *tr = data;
> +
> + pid_list = rcu_dereference_sched(tr->filtered_pids);
> + filter_add_remove_task(pid_list, NULL, task);
> +}
>
> - return !test_bit(task->pid, filtered_pids->pids);
> +static void
> +event_filter_pid_sched_process_fork(void *data,
> + struct task_struct *self,
> + struct task_struct *task)
> +{
> + struct trace_pid_list *pid_list;
> + struct trace_array *tr = data;
> +
> + pid_list = rcu_dereference_sched(tr->filtered_pids);
> + filter_add_remove_task(pid_list, self, task);
> +}
> +
> +void trace_event_follow_fork(struct trace_array *tr, bool enable)
> +{
> + if (enable) {
> + register_trace_prio_sched_process_fork(event_filter_pid_sched_process_fork,
> + tr, INT_MIN);
> + register_trace_prio_sched_process_exit(event_filter_pid_sched_process_exit,
> + tr, INT_MAX);
> + } else {
> + unregister_trace_sched_process_fork(event_filter_pid_sched_process_fork,
> + tr);
> + unregister_trace_sched_process_exit(event_filter_pid_sched_process_exit,
> + tr);
> + }
> }
>
> static void
> --
> 2.8.0.rc3
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-trace-users" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com
[toc] | [prev] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2016-04-19 19:20 +0200 |
| Subject | Re: [RFC][PATCH 3/4] tracing: Add infrastructure to allow set_event_pid to follow children |
| Message-ID | <rpHtF-1RO-31@gated-at.bofh.it> |
| In reply to | #1382714 |
On Tue, 19 Apr 2016 16:55:11 +0000 (UTC) Mathieu Desnoyers <mathieu.desnoyers@efficios.com> wrote: > ----- On Apr 19, 2016, at 10:34 AM, rostedt rostedt@goodmis.org wrote: > > > From: Steven Rostedt <rostedt@goodmis.org> > > > > Add the infrastructure needed to have the PIDs in set_event_pid to > > automatically add PIDs of the children of the tasks that have their PIDs in > > set_event_pid. This will also remove PIDs from set_event_pid when a task > > exits > > > > This is implemented by adding hooks into the fork and exit tracepoints. On > > fork, the PIDs are added to the list, and on exit, they are removed. > > > > Add a new option called event_fork that when set, PIDs in set_event_pid will > > automatically get their children PIDs added when they fork, as well as any > > task that exits will have its PID removed from set_event_pid. > > Just out of curiosity: how does it deal with multi-process and multi-thread ? > What events are expected in each case ? > Not sure what you mean by that. This is in-kernel, and it's simply tasks. That is, any task (process or thread) that creates another task has its kernel pid checked. That would be the thread ID as well. So it works the same with processes as with threads because within the kernel they are just all just "tasks". -- Steve
[toc] | [prev] | [next] | [standalone]
| From | Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
|---|---|
| Date | 2016-04-19 22:40 +0200 |
| Subject | Re: [RFC][PATCH 3/4] tracing: Add infrastructure to allow set_event_pid to follow children |
| Message-ID | <rpKBb-4bP-3@gated-at.bofh.it> |
| In reply to | #1382735 |
----- On Apr 19, 2016, at 1:13 PM, rostedt rostedt@goodmis.org wrote: > On Tue, 19 Apr 2016 16:55:11 +0000 (UTC) > Mathieu Desnoyers <mathieu.desnoyers@efficios.com> wrote: > >> ----- On Apr 19, 2016, at 10:34 AM, rostedt rostedt@goodmis.org wrote: >> >> > From: Steven Rostedt <rostedt@goodmis.org> >> > >> > Add the infrastructure needed to have the PIDs in set_event_pid to >> > automatically add PIDs of the children of the tasks that have their PIDs in >> > set_event_pid. This will also remove PIDs from set_event_pid when a task >> > exits >> > >> > This is implemented by adding hooks into the fork and exit tracepoints. On >> > fork, the PIDs are added to the list, and on exit, they are removed. >> > >> > Add a new option called event_fork that when set, PIDs in set_event_pid will >> > automatically get their children PIDs added when they fork, as well as any >> > task that exits will have its PID removed from set_event_pid. >> >> Just out of curiosity: how does it deal with multi-process and multi-thread ? >> What events are expected in each case ? >> > > Not sure what you mean by that. This is in-kernel, and it's simply > tasks. That is, any task (process or thread) that creates another task > has its kernel pid checked. That would be the thread ID as well. So it > works the same with processes as with threads because within the kernel > they are just all just "tasks". You register on sched_process_fork and sched_process_exit tracepoints for adding/removing PIDs to/from your "PID tracker". sched_process_fork() is called both when a process and when a thread is created. sched_process_exit() is called from do_exit(). Ah! and it seems do_exit is called whenever a user-space thread exits. The process exiting system call is rather exit_group(2). I was concerned that you might miss the thread exiting system calls, but it seems OK after digging back into that part of the kernel source code. It's been a while since last time I had to do modeling of the kernel state based on events by myself, sorry about the confusion. :-) Thanks, Mathieu > > -- Steve -- Mathieu Desnoyers EfficiOS Inc. http://www.efficios.com
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web