mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [RFC 0/3] x86_64,tracing: multiplexing function tracer
@ 2011-04-29 14:43 Jiri Olsa
  2011-04-29 14:43 ` [RFC 1/3] tracing: function tracer registration Jiri Olsa
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Jiri Olsa @ 2011-04-29 14:43 UTC (permalink / raw)
  To: rostedt, fweisbec; +Cc: linux-kernel

hi, me again ;)

from last RFC email it turned out it'd be good to have support
for more than 1 currently running function tracers. With
the possibility to specify separate filter for each of them.

I thought about one way how to do that and put it to the
code for considering. It seems to work properly, though
I was fighting with set_ftrace_filter for a while.. and
it is still not ideal ;)


How does it work?

 - when the function tracer is registered it got assigned unique ID
 - 'mcount callback' beside ip and parent_ip provides bitmask
   set with tracers IDs which are interested in the current function
 - 'mcount callback' calls tracers callbacks as set in the bitmask


How did that bitfield get to the 'mcount callback'?

 - several 'mcount callbacks' are statically generated with code
   providing unique bitmask
 - each combination of tracers (IDs) map to a single 'mcount callback'
   providing bitmask of this combination
 - function pointers of these callbacks are stored and used
   to patch the function 'mcount call' instruction

 To have all bitmask possibilities covered it is generated
 2^(allowed tracers) number of 'mcount callbacks'. As this
 statical part is relativelly small it's probably ok.

 I guess it's possible to use dynamic approach and allocate
 only as many 'mcount callbacks' as needed (similar as
 for optimized kprobes).


How does filtering work (interface) ?

 - each tracer got unique name
 - added file function_tracers providing list of registered tracers
 - one tracer is allways default, and this one will be changed
   via set_ftrace_filter interface
 - default tracer can be changed by write the name to the function_tracers
   file


How does filtering work (code) ?

 - each 'struct dyn_ftrace' record now holds 2 bitmasks:
   filter and notrace
 - those 2 bitmask are updated by the set_ftrace_filter code
   to carry bitmask of tracers interested in the function
 - this info is processed during the 'mcount callback' assigning


Example session

	# echo function > ./current_tracer 
	# cat function_tracers 
	*trace
	# echo 1 > ./function_profile_enabled 
	# cat function_tracers 
	 trace
	*trace_profile
	# cat set_ftrace_filter 
	[               trace] #### all functions enabled ####
	[       trace_profile] #### all functions enabled ####
	# echo sys_read > ./set_ftrace_filter 
	# cat set_ftrace_filter 
	[               trace] #### all functions enabled ####
	[       trace_profile] sys_read
	# echo trace > ./function_tracers 
	# cat function_tracers 
	*trace
	 trace_profile
	# echo sys_write > ./set_ftrace_filter 
	# cat set_ftrace_filter 
	[               trace] sys_write
	[       trace_profile] sys_read


attached patches:
- 1/3 tracing: function tracer registration
- 2/3 tracing: adding statical callers
- 3/3 tracing: set_ftrace_filter support


This is by no means complete solution, and there are
many leftovers.. just wanted to try this way ;)

plz let me know what you think

wbr,
jirka
---
 arch/x86/include/asm/ftrace.h     |    4 +
 arch/x86/kernel/entry_64.S        |   22 ++-
 arch/x86/kernel/ftrace.c          |   50 ++--
 include/linux/ftrace.h            |   16 +-
 kernel/trace/ftrace.c             |  555 +++++++++++++++++++++----------------
 kernel/trace/trace_events.c       |    1 +
 kernel/trace/trace_functions.c    |    2 +
 kernel/trace/trace_irqsoff.c      |    1 +
 kernel/trace/trace_sched_wakeup.c |    1 +
 kernel/trace/trace_stack.c        |    1 +
 10 files changed, 383 insertions(+), 270 deletions(-)

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [RFC 1/3] tracing: function tracer registration
  2011-04-29 14:43 [RFC 0/3] x86_64,tracing: multiplexing function tracer Jiri Olsa
@ 2011-04-29 14:43 ` Jiri Olsa
  2011-04-29 14:43 ` [RFC 2/3] tracing: adding statical callers Jiri Olsa
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Jiri Olsa @ 2011-04-29 14:43 UTC (permalink / raw)
  To: rostedt, fweisbec; +Cc: linux-kernel

adding ID and default tracer support for function
tracer registration

---
 arch/x86/include/asm/ftrace.h     |    2 +
 arch/x86/kernel/entry_64.S        |    6 +-
 arch/x86/kernel/ftrace.c          |   13 --
 include/linux/ftrace.h            |    9 +-
 kernel/trace/ftrace.c             |  290 +++++++++++++++----------------------
 kernel/trace/trace_events.c       |    1 +
 kernel/trace/trace_functions.c    |    2 +
 kernel/trace/trace_irqsoff.c      |    1 +
 kernel/trace/trace_sched_wakeup.c |    1 +
 kernel/trace/trace_stack.c        |    1 +
 10 files changed, 136 insertions(+), 190 deletions(-)

diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
index db24c22..45ae1fa 100644
--- a/arch/x86/include/asm/ftrace.h
+++ b/arch/x86/include/asm/ftrace.h
@@ -1,6 +1,8 @@
 #ifndef _ASM_X86_FTRACE_H
 #define _ASM_X86_FTRACE_H
 
+#define FTRACE_TRACERS_MAX 4
+
 #ifdef __ASSEMBLY__
 
 	.macro MCOUNT_SAVE_FRAME
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 8a445a0..e0ba7d9 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -79,8 +79,10 @@ ENTRY(ftrace_caller)
 	movq 8(%rbp), %rsi
 	subq $MCOUNT_INSN_SIZE, %rdi
 
-GLOBAL(ftrace_call)
-	call ftrace_stub
+	/* by default call all registered handlers */
+	movq $-1, %rdx
+
+	call ftrace_call
 
 	MCOUNT_RESTORE_FRAME
 
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 0ba15a6..dc92378 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -321,19 +321,6 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 	return ftrace_modify_code(rec->ip, old, new);
 }
 
-int ftrace_update_ftrace_func(ftrace_func_t func)
-{
-	unsigned long ip = (unsigned long)(&ftrace_call);
-	unsigned char old[MCOUNT_INSN_SIZE], *new;
-	int ret;
-
-	memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE);
-	new = ftrace_call_replace(ip, (unsigned long)func);
-	ret = ftrace_modify_code(ip, old, new);
-
-	return ret;
-}
-
 int __init ftrace_dyn_arch_init(void *data)
 {
 	/* The return code is retured via data */
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index ca29e03..b7ab09d 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -30,8 +30,9 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
 typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip);
 
 struct ftrace_ops {
-	ftrace_func_t	  func;
-	struct ftrace_ops *next;
+	char *name;
+	int   id;
+	ftrace_func_t func;
 };
 
 extern int function_trace_stop;
@@ -175,9 +176,9 @@ int unregister_ftrace_command(struct ftrace_func_command *cmd);
 /* defined in arch */
 extern int ftrace_ip_converted(unsigned long ip);
 extern int ftrace_dyn_arch_init(void *data);
-extern int ftrace_update_ftrace_func(ftrace_func_t func);
 extern void ftrace_caller(void);
-extern void ftrace_call(void);
+extern void ftrace_call(unsigned long ip, unsigned long parent_ip,
+			unsigned long flags);
 extern void mcount_call(void);
 
 #ifndef FTRACE_ADDR
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index ee24fa1..f1eedda 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -76,62 +76,12 @@ static int ftrace_disabled __read_mostly;
 
 static DEFINE_MUTEX(ftrace_lock);
 
-static struct ftrace_ops ftrace_list_end __read_mostly =
-{
-	.func		= ftrace_stub,
-};
-
-static struct ftrace_ops *ftrace_list __read_mostly = &ftrace_list_end;
-ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub;
-ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub;
-ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub;
-
-/*
- * Traverse the ftrace_list, invoking all entries.  The reason that we
- * can use rcu_dereference_raw() is that elements removed from this list
- * are simply leaked, so there is no need to interact with a grace-period
- * mechanism.  The rcu_dereference_raw() calls are needed to handle
- * concurrent insertions into the ftrace_list.
- *
- * Silly Alpha and silly pointer-speculation compiler optimizations!
- */
-static void ftrace_list_func(unsigned long ip, unsigned long parent_ip)
-{
-	struct ftrace_ops *op = rcu_dereference_raw(ftrace_list); /*see above*/
-
-	while (op != &ftrace_list_end) {
-		op->func(ip, parent_ip);
-		op = rcu_dereference_raw(op->next); /*see above*/
-	};
-}
-
-static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip)
-{
-	if (!test_tsk_trace_trace(current))
-		return;
-
-	ftrace_pid_function(ip, parent_ip);
-}
+static struct ftrace_ops *ftrace_tracers[FTRACE_TRACERS_MAX];
+static DECLARE_BITMAP(ftrace_tracers_bm, FTRACE_TRACERS_MAX);
+static int ftrace_tracers_cur = -1;
 
-static void set_ftrace_pid_function(ftrace_func_t func)
-{
-	/* do not set ftrace_pid_function to itself! */
-	if (func != ftrace_pid_func)
-		ftrace_pid_function = func;
-}
-
-/**
- * clear_ftrace_function - reset the ftrace function
- *
- * This NULLs the ftrace function and in essence stops
- * tracing.  There may be lag
- */
-void clear_ftrace_function(void)
-{
-	ftrace_trace_function = ftrace_stub;
-	__ftrace_trace_function = ftrace_stub;
-	ftrace_pid_function = ftrace_stub;
-}
+#define for_each_tracer(id, bm) \
+	for_each_set_bit(id, bm, FTRACE_TRACERS_MAX)
 
 #ifndef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
 /*
@@ -147,114 +97,82 @@ static void ftrace_test_stop_func(unsigned long ip, unsigned long parent_ip)
 }
 #endif
 
-static int __register_ftrace_function(struct ftrace_ops *ops)
-{
-	ops->next = ftrace_list;
-	/*
-	 * We are entering ops into the ftrace_list but another
-	 * CPU might be walking that list. We need to make sure
-	 * the ops->next pointer is valid before another CPU sees
-	 * the ops pointer included into the ftrace_list.
-	 */
-	rcu_assign_pointer(ftrace_list, ops);
 
-	if (ftrace_enabled) {
-		ftrace_func_t func;
+void ftrace_call(unsigned long ip, unsigned long parent_ip,
+		 unsigned long flags)
+{
+	int id;
 
-		if (ops->next == &ftrace_list_end)
-			func = ops->func;
-		else
-			func = ftrace_list_func;
+	if (!list_empty(&ftrace_pids) &&
+	    !test_tsk_trace_trace(current))
+		return;
 
-		if (!list_empty(&ftrace_pids)) {
-			set_ftrace_pid_function(func);
-			func = ftrace_pid_func;
-		}
+	rcu_read_lock();
+	for_each_tracer(id, &flags) {
+		struct ftrace_ops *ops = rcu_dereference(ftrace_tracers[id]);
+		if (!ops)
+			continue;
 
-		/*
-		 * For one func, simply call it directly.
-		 * For more than one func, call the chain.
-		 */
-#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
-		ftrace_trace_function = func;
-#else
-		__ftrace_trace_function = func;
-		ftrace_trace_function = ftrace_test_stop_func;
-#endif
+		ops->func(ip, parent_ip);
 	}
-
-	return 0;
+	rcu_read_unlock();
 }
 
-static int __unregister_ftrace_function(struct ftrace_ops *ops)
+static int __register_ftrace_function(struct ftrace_ops *ops)
 {
-	struct ftrace_ops **p;
+	int id;
 
-	/*
-	 * If we are removing the last function, then simply point
-	 * to the ftrace_stub.
-	 */
-	if (ftrace_list == ops && ops->next == &ftrace_list_end) {
-		ftrace_trace_function = ftrace_stub;
-		ftrace_list = &ftrace_list_end;
-		return 0;
-	}
+	id = find_first_zero_bit(ftrace_tracers_bm, FTRACE_TRACERS_MAX);
+	if (id >= FTRACE_TRACERS_MAX)
+		return -ENOSPC;
 
-	for (p = &ftrace_list; *p != &ftrace_list_end; p = &(*p)->next)
-		if (*p == ops)
-			break;
+	ops->id = id;
+	set_bit(id, ftrace_tracers_bm);
+	ftrace_tracers_cur = id;
+	rcu_assign_pointer(ftrace_tracers[id], ops);
+	return 0;
+}
 
-	if (*p != ops)
-		return -1;
+static int __unregister_ftrace_function(struct ftrace_ops *ops)
+{
+	int id = ops->id;
 
-	*p = (*p)->next;
+	clear_bit(id, ftrace_tracers_bm);
+	BUG_ON(ops != ftrace_tracers[id]);
+	rcu_assign_pointer(ftrace_tracers[id], NULL);
 
-	if (ftrace_enabled) {
-		/* If we only have one func left, then call that directly */
-		if (ftrace_list->next == &ftrace_list_end) {
-			ftrace_func_t func = ftrace_list->func;
+	if (ftrace_tracers_cur != id)
+		return 0;
 
-			if (!list_empty(&ftrace_pids)) {
-				set_ftrace_pid_function(func);
-				func = ftrace_pid_func;
-			}
-#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
-			ftrace_trace_function = func;
-#else
-			__ftrace_trace_function = func;
-#endif
-		}
-	}
+	/* find another default tracer */
+	ftrace_tracers_cur = find_first_bit(ftrace_tracers_bm,
+					    FTRACE_TRACERS_MAX);
+	if (ftrace_tracers_cur >= FTRACE_TRACERS_MAX)
+		ftrace_tracers_cur = -1;
 
 	return 0;
 }
 
-static void ftrace_update_pid_func(void)
+static int ftrace_tracer_default(char *name)
 {
-	ftrace_func_t func;
+	int id, ret = -EINVAL;
 
-	if (ftrace_trace_function == ftrace_stub)
-		return;
+	mutex_lock(&ftrace_lock);
+	for_each_tracer(id, ftrace_tracers_bm) {
+		struct ftrace_ops *ops = ftrace_tracers[id];
+		BUG_ON(!ops);
 
-#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
-	func = ftrace_trace_function;
-#else
-	func = __ftrace_trace_function;
-#endif
+		if (!strcmp(name, ops->name))
+			break;
+	}
 
-	if (!list_empty(&ftrace_pids)) {
-		set_ftrace_pid_function(func);
-		func = ftrace_pid_func;
-	} else {
-		if (func == ftrace_pid_func)
-			func = ftrace_pid_function;
+	if (id < FTRACE_TRACERS_MAX) {
+		ftrace_tracers_cur = id;
+		ret = 0;
 	}
 
-#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
-	ftrace_trace_function = func;
-#else
-	__ftrace_trace_function = func;
-#endif
+	mutex_unlock(&ftrace_lock);
+	return ret;
 }
 
 #ifdef CONFIG_FUNCTION_PROFILER
@@ -717,6 +635,7 @@ static void unregister_ftrace_profiler(void)
 #else
 static struct ftrace_ops ftrace_profile_ops __read_mostly =
 {
+	.name		= "trace_profile",
 	.func		= function_profile_call,
 };
 
@@ -1143,9 +1062,6 @@ static int __ftrace_modify_code(void *data)
 	else if (*command & FTRACE_DISABLE_CALLS)
 		ftrace_replace_code(0);
 
-	if (*command & FTRACE_UPDATE_TRACE_FUNC)
-		ftrace_update_ftrace_func(ftrace_trace_function);
-
 	if (*command & FTRACE_START_FUNC_RET)
 		ftrace_enable_ftrace_graph_caller();
 	else if (*command & FTRACE_STOP_FUNC_RET)
@@ -1174,11 +1090,6 @@ static int ftrace_start_up;
 
 static void ftrace_startup_enable(int command)
 {
-	if (saved_ftrace_func != ftrace_trace_function) {
-		saved_ftrace_func = ftrace_trace_function;
-		command |= FTRACE_UPDATE_TRACE_FUNC;
-	}
-
 	if (!command || !ftrace_enabled)
 		return;
 
@@ -1212,11 +1123,6 @@ static void ftrace_shutdown(int command)
 	if (!ftrace_start_up)
 		command |= FTRACE_DISABLE_CALLS;
 
-	if (saved_ftrace_func != ftrace_trace_function) {
-		saved_ftrace_func = ftrace_trace_function;
-		command |= FTRACE_UPDATE_TRACE_FUNC;
-	}
-
 	if (!command || !ftrace_enabled)
 		return;
 
@@ -1732,6 +1638,53 @@ ftrace_regex_lseek(struct file *file, loff_t offset, int origin)
 	return ret;
 }
 
+static int ftrace_tracers_show(struct seq_file *seq, void *v)
+{
+	int id;
+
+	mutex_lock(&ftrace_lock);
+	for_each_tracer(id, ftrace_tracers_bm) {
+		struct ftrace_ops *ops = ftrace_tracers[id];
+
+		BUG_ON(!ops);
+		seq_printf(seq, "%s%s\n",
+			ftrace_tracers_cur == id ? "*" : " ",
+			ops->name);
+	}
+
+	mutex_unlock(&ftrace_lock);
+	return 0;
+}
+
+static int
+ftrace_tracers_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ftrace_tracers_show, NULL);
+}
+
+static ssize_t
+ftrace_tracers_write(struct file *filp, const char __user *ubuf, size_t cnt,
+		     loff_t *ppos)
+{
+	char buf[64];
+	int i;
+
+	if (cnt >= sizeof(buf))
+		return -EINVAL;
+
+	if (copy_from_user(&buf, ubuf, cnt))
+		return -EFAULT;
+
+	buf[cnt] = 0;
+	for (i = cnt - 1; i > 0 && isspace(buf[i]); i--)
+		buf[i] = 0;
+
+	if (ftrace_tracer_default(buf))
+		return -EINVAL;
+
+	return cnt;
+}
+
 static int ftrace_match(char *str, char *regex, int len, int type)
 {
 	int matched = 0;
@@ -1952,6 +1905,7 @@ function_trace_probe_call(unsigned long ip, unsigned long parent_ip)
 
 static struct ftrace_ops trace_probe_ops __read_mostly =
 {
+	.name		= "trace_probe",
 	.func		= function_trace_probe_call,
 };
 
@@ -2467,6 +2421,14 @@ static const struct file_operations ftrace_notrace_fops = {
 	.release = ftrace_notrace_release,
 };
 
+static const struct file_operations ftrace_tracers_fops = {
+	.open		= ftrace_tracers_open,
+	.read		= seq_read,
+	.release	= single_release,
+	.llseek		= seq_lseek,
+	.write          = ftrace_tracers_write,
+};
+
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 
 static DEFINE_MUTEX(graph_lock);
@@ -2688,6 +2650,9 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer)
 	trace_create_file("set_ftrace_notrace", 0644, d_tracer,
 				    NULL, &ftrace_notrace_fops);
 
+	trace_create_file("function_tracers", 0644, d_tracer,
+				    NULL, &ftrace_tracers_fops);
+
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 	trace_create_file("set_graph_function", 0444, d_tracer,
 				    NULL,
@@ -2950,7 +2915,6 @@ static int ftrace_pid_add(int p)
 
 	set_ftrace_pid_task(pid);
 
-	ftrace_update_pid_func();
 	ftrace_startup_enable(0);
 
 	mutex_unlock(&ftrace_lock);
@@ -2979,7 +2943,6 @@ static void ftrace_pid_reset(void)
 		kfree(fpid);
 	}
 
-	ftrace_update_pid_func();
 	ftrace_startup_enable(0);
 
 	mutex_unlock(&ftrace_lock);
@@ -3127,7 +3090,6 @@ void ftrace_kill(void)
 {
 	ftrace_disabled = 1;
 	ftrace_enabled = 0;
-	clear_ftrace_function();
 }
 
 /**
@@ -3194,24 +3156,10 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
 
 	last_ftrace_enabled = !!ftrace_enabled;
 
-	if (ftrace_enabled) {
-
+	if (ftrace_enabled)
 		ftrace_startup_sysctl();
-
-		/* we are starting ftrace again */
-		if (ftrace_list != &ftrace_list_end) {
-			if (ftrace_list->next == &ftrace_list_end)
-				ftrace_trace_function = ftrace_list->func;
-			else
-				ftrace_trace_function = ftrace_list_func;
-		}
-
-	} else {
-		/* stopping ftrace calls (just send to ftrace_stub) */
-		ftrace_trace_function = ftrace_stub;
-
+	else
 		ftrace_shutdown_sysctl();
-	}
 
  out:
 	mutex_unlock(&ftrace_lock);
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index e88f74f..43600a1 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1651,6 +1651,7 @@ function_test_events_call(unsigned long ip, unsigned long parent_ip)
 
 static struct ftrace_ops trace_ops __initdata  =
 {
+	.name = "trace_event",
 	.func = function_test_events_call,
 };
 
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index 16aee4d..a991743 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -148,11 +148,13 @@ function_stack_trace_call(unsigned long ip, unsigned long parent_ip)
 
 static struct ftrace_ops trace_ops __read_mostly =
 {
+	.name = "trace",
 	.func = function_trace_call,
 };
 
 static struct ftrace_ops trace_stack_ops __read_mostly =
 {
+	.name = "trace_stack",
 	.func = function_stack_trace_call,
 };
 
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c
index a4969b4..6983594 100644
--- a/kernel/trace/trace_irqsoff.c
+++ b/kernel/trace/trace_irqsoff.c
@@ -152,6 +152,7 @@ irqsoff_tracer_call(unsigned long ip, unsigned long parent_ip)
 
 static struct ftrace_ops trace_ops __read_mostly =
 {
+	.name = "trace_irqs",
 	.func = irqsoff_tracer_call,
 };
 #endif /* CONFIG_FUNCTION_TRACER */
diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c
index 7319559..f8b4622 100644
--- a/kernel/trace/trace_sched_wakeup.c
+++ b/kernel/trace/trace_sched_wakeup.c
@@ -128,6 +128,7 @@ wakeup_tracer_call(unsigned long ip, unsigned long parent_ip)
 
 static struct ftrace_ops trace_ops __read_mostly =
 {
+	.name = "trace_wakeup",
 	.func = wakeup_tracer_call,
 };
 #endif /* CONFIG_FUNCTION_TRACER */
diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c
index 4c5dead..31f361e 100644
--- a/kernel/trace/trace_stack.c
+++ b/kernel/trace/trace_stack.c
@@ -132,6 +132,7 @@ stack_trace_call(unsigned long ip, unsigned long parent_ip)
 
 static struct ftrace_ops trace_ops __read_mostly =
 {
+	.name = "trace_stack",
 	.func = stack_trace_call,
 };
 
-- 
1.7.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [RFC 2/3] tracing: adding statical callers
  2011-04-29 14:43 [RFC 0/3] x86_64,tracing: multiplexing function tracer Jiri Olsa
  2011-04-29 14:43 ` [RFC 1/3] tracing: function tracer registration Jiri Olsa
@ 2011-04-29 14:43 ` Jiri Olsa
  2011-04-29 14:43 ` [RFC 3/3] tracing: set_ftrace_filter support Jiri Olsa
  2011-04-29 14:57 ` [RFC 0/3] x86_64,tracing: multiplexing function tracer Steven Rostedt
  3 siblings, 0 replies; 7+ messages in thread
From: Jiri Olsa @ 2011-04-29 14:43 UTC (permalink / raw)
  To: rostedt, fweisbec; +Cc: linux-kernel

adding statically generated code for 'mcount callback' providing
unique bitmask

---
 arch/x86/include/asm/ftrace.h |    2 ++
 arch/x86/kernel/entry_64.S    |   22 +++++++++++++++++-----
 arch/x86/kernel/ftrace.c      |   13 +++++++++++++
 include/linux/ftrace.h        |    4 +---
 kernel/trace/ftrace.c         |    2 +-
 5 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
index 45ae1fa..6ef436b 100644
--- a/arch/x86/include/asm/ftrace.h
+++ b/arch/x86/include/asm/ftrace.h
@@ -2,6 +2,7 @@
 #define _ASM_X86_FTRACE_H
 
 #define FTRACE_TRACERS_MAX 4
+#define FTRACE_CALLERS_MAX ((1 << FTRACE_TRACERS_MAX) - 1)
 
 #ifdef __ASSEMBLY__
 
@@ -36,6 +37,7 @@
 
 #ifndef __ASSEMBLY__
 extern void mcount(void);
+extern unsigned long ftrace_callers[FTRACE_CALLERS_MAX];
 
 static inline unsigned long ftrace_call_adjust(unsigned long addr)
 {
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index e0ba7d9..1ec1668 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -69,19 +69,31 @@ ENTRY(mcount)
 	retq
 END(mcount)
 
-ENTRY(ftrace_caller)
+	.section .rodata,"a"
+ENTRY(ftrace_callers)
+	.section .entry.text
+.macro FTRACE_GEN_CALLERS num
+i=1
+.rept (1 << \num) - 1
+1:
 	cmpl $0, function_trace_stop
 	jne  ftrace_stub
-
 	MCOUNT_SAVE_FRAME
+	movq $i, %rdx
+	jmp ftrace_caller
+	.previous
+	.quad 1b
+	.section .entry.text
+i=i+1
+.endr
+.endm
+	FTRACE_GEN_CALLERS FTRACE_TRACERS_MAX
 
+ENTRY(ftrace_caller)
 	movq 0x38(%rsp), %rdi
 	movq 8(%rbp), %rsi
 	subq $MCOUNT_INSN_SIZE, %rdi
 
-	/* by default call all registered handlers */
-	movq $-1, %rdx
-
 	call ftrace_call
 
 	MCOUNT_RESTORE_FRAME
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index dc92378..5a8e679 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -328,6 +328,19 @@ int __init ftrace_dyn_arch_init(void *data)
 
 	return 0;
 }
+
+unsigned long ftrace_arch_tracer_addr(int mask)
+{
+	if (!mask)
+		return 0L;
+
+	/* tracer 1 is index 0 in ftrace_callers */
+	--mask;
+
+	BUG_ON(mask >= FTRACE_CALLERS_MAX);
+	return ftrace_callers[mask];
+}
+
 #endif
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index b7ab09d..b12f5df 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -180,10 +180,8 @@ extern void ftrace_caller(void);
 extern void ftrace_call(unsigned long ip, unsigned long parent_ip,
 			unsigned long flags);
 extern void mcount_call(void);
+extern unsigned long ftrace_arch_tracer_addr(int mask);
 
-#ifndef FTRACE_ADDR
-#define FTRACE_ADDR ((unsigned long)ftrace_caller)
-#endif
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 extern void ftrace_graph_caller(void);
 extern int ftrace_enable_ftrace_graph_caller(void);
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index f1eedda..b39dd52 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -963,7 +963,7 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
 	unsigned long ftrace_addr;
 	unsigned long flag = 0UL;
 
-	ftrace_addr = (unsigned long)FTRACE_ADDR;
+	ftrace_addr = ftrace_arch_tracer_addr(FTRACE_CALLERS_MAX);
 
 	/*
 	 * If this record is not to be traced or we want to disable it,
-- 
1.7.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [RFC 3/3] tracing: set_ftrace_filter support
  2011-04-29 14:43 [RFC 0/3] x86_64,tracing: multiplexing function tracer Jiri Olsa
  2011-04-29 14:43 ` [RFC 1/3] tracing: function tracer registration Jiri Olsa
  2011-04-29 14:43 ` [RFC 2/3] tracing: adding statical callers Jiri Olsa
@ 2011-04-29 14:43 ` Jiri Olsa
  2011-04-29 15:16   ` Steven Rostedt
  2011-04-29 14:57 ` [RFC 0/3] x86_64,tracing: multiplexing function tracer Steven Rostedt
  3 siblings, 1 reply; 7+ messages in thread
From: Jiri Olsa @ 2011-04-29 14:43 UTC (permalink / raw)
  To: rostedt, fweisbec; +Cc: linux-kernel

adding support to use set_ftrace_filter for multiple tracers

---
 arch/x86/kernel/ftrace.c |   24 +++--
 include/linux/ftrace.h   |    3 +
 kernel/trace/ftrace.c    |  269 ++++++++++++++++++++++++++++++++++------------
 3 files changed, 219 insertions(+), 77 deletions(-)

diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 5a8e679..5fdb40e 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -76,18 +76,20 @@ static int ftrace_calc_offset(long ip, long addr)
 	return (int)(addr - ip);
 }
 
-static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
+static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr, int old)
 {
-	static union ftrace_code_union calc;
+	static union ftrace_code_union calc_new;
+	static union ftrace_code_union calc_old;
+	union ftrace_code_union *calc = old ? &calc_old : &calc_new;
 
-	calc.e8		= 0xe8;
-	calc.offset	= ftrace_calc_offset(ip + MCOUNT_INSN_SIZE, addr);
+	calc->e8	= 0xe8;
+	calc->offset	= ftrace_calc_offset(ip + MCOUNT_INSN_SIZE, addr);
 
 	/*
 	 * No locking needed, this must be called via kstop_machine
 	 * which in essence is like running on a uniprocessor machine.
 	 */
-	return calc.code;
+	return calc->code;
 }
 
 /*
@@ -304,9 +306,10 @@ int ftrace_make_nop(struct module *mod,
 	unsigned char *new, *old;
 	unsigned long ip = rec->ip;
 
-	old = ftrace_call_replace(ip, addr);
+	old = ftrace_call_replace(ip, addr, 1);
 	new = ftrace_nop_replace();
 
+	rec->addr = 0L;
 	return ftrace_modify_code(rec->ip, old, new);
 }
 
@@ -315,9 +318,14 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 	unsigned char *new, *old;
 	unsigned long ip = rec->ip;
 
-	old = ftrace_nop_replace();
-	new = ftrace_call_replace(ip, addr);
+	if (rec->addr)
+		old = ftrace_call_replace(ip, rec->addr, 1);
+	else
+		old = ftrace_nop_replace();
 
+	new = ftrace_call_replace(ip, addr, 0);
+
+	rec->addr = addr;
 	return ftrace_modify_code(rec->ip, old, new);
 }
 
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index b12f5df..9ce3484 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -164,6 +164,9 @@ struct dyn_ftrace {
 		unsigned long		flags;
 		struct dyn_ftrace	*newlist;
 	};
+	unsigned long			filter;
+	unsigned long			no_trace;
+	unsigned long			addr;
 	struct dyn_arch_ftrace		arch;
 };
 
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index b39dd52..bbffb05 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -80,6 +80,8 @@ static struct ftrace_ops *ftrace_tracers[FTRACE_TRACERS_MAX];
 static DECLARE_BITMAP(ftrace_tracers_bm, FTRACE_TRACERS_MAX);
 static int ftrace_tracers_cur = -1;
 
+static void __ftrace_tracer_clear(int id, int type);
+
 #define for_each_tracer(id, bm) \
 	for_each_set_bit(id, bm, FTRACE_TRACERS_MAX)
 
@@ -141,6 +143,8 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops)
 	BUG_ON(ops != ftrace_tracers[id]);
 	rcu_assign_pointer(ftrace_tracers[id], NULL);
 
+	__ftrace_tracer_clear(id, FTRACE_FL_FILTER|FTRACE_FL_NOTRACE);
+
 	if (ftrace_tracers_cur != id)
 		return 0;
 
@@ -175,6 +179,11 @@ static int ftrace_tracer_default(char *name)
 	return ret;
 }
 
+static int __ftrace_get_next_tracer(int idx)
+{
+	return find_next_bit(ftrace_tracers_bm, FTRACE_TRACERS_MAX, idx);
+}
+
 #ifdef CONFIG_FUNCTION_PROFILER
 struct ftrace_profile {
 	struct hlist_node		node;
@@ -808,7 +817,7 @@ enum {
 	FTRACE_STOP_FUNC_RET		= (1 << 4),
 };
 
-static int ftrace_filtered;
+static unsigned long ftrace_tracer_filtered;
 
 static struct dyn_ftrace *ftrace_new_addrs;
 
@@ -845,6 +854,20 @@ static struct dyn_ftrace *ftrace_free_records;
 		}				\
 	}
 
+static void __ftrace_tracer_clear(int id, int type)
+{
+	struct ftrace_page *pg;
+	struct dyn_ftrace *rec;
+	unsigned long mask = ~(1 << id);
+
+	do_for_each_ftrace_rec(pg, rec) {
+		if (type & FTRACE_FL_FILTER)
+			rec->filter  &= mask;
+		if (type & FTRACE_FL_NOTRACE)
+			rec->no_trace &= mask;
+	} while_for_each_ftrace_rec();
+}
+
 static void ftrace_free_rec(struct dyn_ftrace *rec)
 {
 	rec->freelist = ftrace_free_records;
@@ -956,31 +979,52 @@ int ftrace_text_reserved(void *start, void *end)
 	return 0;
 }
 
+unsigned long ftrace_tracer_flag_addr(struct dyn_ftrace *rec,
+				      unsigned long *ftrace_addr, int enable)
+{
+	unsigned long flag = 0L;
+	int id, mask = 0;
+
+	for_each_tracer(id, ftrace_tracers_bm) {
+#define SET(var) (var & (1 << id))
+		int ftrace_filtered = SET(ftrace_tracer_filtered);
+
+		/*
+		 * If this record is not to be traced or we want to disable it,
+		 * then disable it.
+		 *
+		 * If we want to enable it and filtering is off, then enable
+		 * it.
+		 *
+		 * If we want to enable it and filtering is on, enable it
+		 * only if it's filtered
+		 */
+		if (enable && !(SET(rec->no_trace)))
+			if (!ftrace_filtered || (SET(rec->filter)))
+				mask |= (1 << id);
+#undef SET
+	}
+
+	if (mask)
+		flag = FTRACE_FL_ENABLED;
+
+	*ftrace_addr = ftrace_arch_tracer_addr(mask);
+	return flag;
+}
 
 static int
 __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
 {
+	unsigned long flag;
 	unsigned long ftrace_addr;
-	unsigned long flag = 0UL;
 
-	ftrace_addr = ftrace_arch_tracer_addr(FTRACE_CALLERS_MAX);
+	flag = ftrace_tracer_flag_addr(rec, &ftrace_addr, enable);
 
-	/*
-	 * If this record is not to be traced or we want to disable it,
-	 * then disable it.
-	 *
-	 * If we want to enable it and filtering is off, then enable it.
-	 *
-	 * If we want to enable it and filtering is on, enable it only if
-	 * it's filtered
-	 */
-	if (enable && !(rec->flags & FTRACE_FL_NOTRACE)) {
-		if (!ftrace_filtered || (rec->flags & FTRACE_FL_FILTER))
-			flag = FTRACE_FL_ENABLED;
-	}
+	BUG_ON(flag && !ftrace_addr);
 
 	/* If the state of this record hasn't changed, then do nothing */
-	if ((rec->flags & FTRACE_FL_ENABLED) == flag)
+	if (((rec->flags & FTRACE_FL_ENABLED) == flag) &&
+	    (rec->addr == ftrace_addr))
 		return 0;
 
 	if (flag) {
@@ -989,7 +1033,7 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
 	}
 
 	rec->flags &= ~FTRACE_FL_ENABLED;
-	return ftrace_make_nop(NULL, rec, ftrace_addr);
+	return ftrace_make_nop(NULL, rec, rec->addr);
 }
 
 static void ftrace_replace_code(int enable)
@@ -1273,6 +1317,7 @@ struct ftrace_iterator {
 	struct trace_parser		parser;
 	int				hidx;
 	int				idx;
+	int				tracer;
 	unsigned			flags;
 };
 
@@ -1363,6 +1408,76 @@ t_hash_show(struct seq_file *m, struct ftrace_iterator *iter)
 	return 0;
 }
 
+static void reset_iter_read(struct ftrace_iterator *iter)
+{
+	iter->pos = 0;
+	iter->func_pos = 0;
+	iter->flags &= ~(FTRACE_ITER_PRINTALL & FTRACE_ITER_HASH);
+}
+
+static void *t_start(struct seq_file *m, loff_t *pos);
+
+#define TRACER_ISSET(var) (var & (1 << iter->tracer))
+
+static struct dyn_ftrace*
+t_next_entry(struct ftrace_iterator *iter)
+{
+	struct dyn_ftrace *rec = NULL;
+
+	while(!rec) {
+		if (iter->idx >= iter->pg->index) {
+			if (!iter->pg->next)
+				break;
+
+			iter->pg = iter->pg->next;
+			iter->idx = 0;
+
+		} else {
+			rec = &iter->pg->records[iter->idx++];
+
+			if ((rec->flags & FTRACE_FL_FREE) ||
+
+			    (!(iter->flags & FTRACE_ITER_FAILURES) &&
+			     (rec->flags & FTRACE_FL_FAILED)) ||
+
+			    ((iter->flags & FTRACE_ITER_FAILURES) &&
+			     !(rec->flags & FTRACE_FL_FAILED)) ||
+
+			    ((iter->flags & FTRACE_ITER_FILTER) &&
+			     !(TRACER_ISSET(rec->filter))) ||
+
+			    ((iter->flags & FTRACE_ITER_NOTRACE) &&
+			     !(TRACER_ISSET(rec->no_trace)))) {
+				rec = NULL;
+			}
+		}
+	}
+
+	return rec;
+}
+
+static int t_next_new_tracer(struct ftrace_iterator *iter)
+{
+	int id = __ftrace_get_next_tracer(++iter->tracer);
+	if (id >= FTRACE_TRACERS_MAX)
+		return -1;
+
+	iter->tracer = id;
+	iter->pg = ftrace_pages_start;
+	iter->idx = 0;
+
+	if (iter->flags & FTRACE_ITER_FILTER) {
+		if (!TRACER_ISSET(ftrace_tracer_filtered))
+			iter->flags |= FTRACE_ITER_PRINTALL;
+		else
+			iter->flags &= ~FTRACE_ITER_PRINTALL;
+		/* reset in case of seek/pread */
+		iter->flags &= ~FTRACE_ITER_HASH;
+	}
+
+	return id;
+}
+
 static void *
 t_next(struct seq_file *m, void *v, loff_t *pos)
 {
@@ -1375,32 +1490,21 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
 	(*pos)++;
 	iter->pos = iter->func_pos = *pos;
 
+	if (iter->flags & FTRACE_ITER_PRINTALL) {
+		if (t_next_new_tracer(iter) > 0)
+			if (iter->flags & FTRACE_ITER_PRINTALL)
+				return iter;
+	}
+
 	if (iter->flags & FTRACE_ITER_PRINTALL)
 		return t_hash_start(m, pos);
 
- retry:
-	if (iter->idx >= iter->pg->index) {
-		if (iter->pg->next) {
-			iter->pg = iter->pg->next;
-			iter->idx = 0;
-			goto retry;
-		}
-	} else {
-		rec = &iter->pg->records[iter->idx++];
-		if ((rec->flags & FTRACE_FL_FREE) ||
-
-		    (!(iter->flags & FTRACE_ITER_FAILURES) &&
-		     (rec->flags & FTRACE_FL_FAILED)) ||
-
-		    ((iter->flags & FTRACE_ITER_FAILURES) &&
-		     !(rec->flags & FTRACE_FL_FAILED)) ||
-
-		    ((iter->flags & FTRACE_ITER_FILTER) &&
-		     !(rec->flags & FTRACE_FL_FILTER)) ||
-
-		    ((iter->flags & FTRACE_ITER_NOTRACE) &&
-		     !(rec->flags & FTRACE_FL_NOTRACE))) {
-			rec = NULL;
+retry:
+	rec = t_next_entry(iter);
+	if (!rec) {
+		if (t_next_new_tracer(iter) > 0) {
+			if (iter->flags & FTRACE_ITER_PRINTALL)
+				return iter;
 			goto retry;
 		}
 	}
@@ -1409,17 +1513,9 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
 		return t_hash_start(m, pos);
 
 	iter->func = rec;
-
 	return iter;
 }
 
-static void reset_iter_read(struct ftrace_iterator *iter)
-{
-	iter->pos = 0;
-	iter->func_pos = 0;
-	iter->flags &= ~(FTRACE_ITER_PRINTALL & FTRACE_ITER_HASH);
-}
-
 static void *t_start(struct seq_file *m, loff_t *pos)
 {
 	struct ftrace_iterator *iter = m->private;
@@ -1430,15 +1526,17 @@ static void *t_start(struct seq_file *m, loff_t *pos)
 	/*
 	 * If an lseek was done, then reset and start from beginning.
 	 */
-	if (*pos < iter->pos)
+	if (*pos < iter->pos) {
 		reset_iter_read(iter);
+		iter->tracer = 0;
+	}
 
 	/*
 	 * For set_ftrace_filter reading, if we have the filter
 	 * off, we can short cut and just print out that all
 	 * functions are enabled.
 	 */
-	if (iter->flags & FTRACE_ITER_FILTER && !ftrace_filtered) {
+	if (iter->flags & FTRACE_ITER_FILTER && !TRACER_ISSET(ftrace_tracer_filtered)) {
 		if (*pos > 0)
 			return t_hash_start(m, pos);
 		iter->flags |= FTRACE_ITER_PRINTALL;
@@ -1472,6 +1570,7 @@ static void *t_start(struct seq_file *m, loff_t *pos)
 
 	return iter;
 }
+#undef TRACER_ISSET
 
 static void t_stop(struct seq_file *m, void *p)
 {
@@ -1482,12 +1581,14 @@ static int t_show(struct seq_file *m, void *v)
 {
 	struct ftrace_iterator *iter = m->private;
 	struct dyn_ftrace *rec;
+	char *tracer = iter->tracer < FTRACE_TRACERS_MAX ?
+		       ftrace_tracers[iter->tracer]->name : NULL;
 
 	if (iter->flags & FTRACE_ITER_HASH)
 		return t_hash_show(m, iter);
 
 	if (iter->flags & FTRACE_ITER_PRINTALL) {
-		seq_printf(m, "#### all functions enabled ####\n");
+		seq_printf(m, "[%20s] #### all functions enabled ####\n", tracer);
 		return 0;
 	}
 
@@ -1496,7 +1597,7 @@ static int t_show(struct seq_file *m, void *v)
 	if (!rec)
 		return 0;
 
-	seq_printf(m, "%ps\n", (void *)rec->ip);
+	seq_printf(m, "[%20s] %ps\n", tracer, (void *)rec->ip);
 
 	return 0;
 }
@@ -1552,21 +1653,15 @@ ftrace_failures_open(struct inode *inode, struct file *file)
 	return ret;
 }
 
-
 static void ftrace_filter_reset(int enable)
 {
-	struct ftrace_page *pg;
-	struct dyn_ftrace *rec;
 	unsigned long type = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
 
 	mutex_lock(&ftrace_lock);
 	if (enable)
-		ftrace_filtered = 0;
-	do_for_each_ftrace_rec(pg, rec) {
-		if (rec->flags & FTRACE_FL_FAILED)
-			continue;
-		rec->flags &= ~type;
-	} while_for_each_ftrace_rec();
+		ftrace_tracer_filtered &= ~(1 << ftrace_tracers_cur);
+
+	__ftrace_tracer_clear(ftrace_tracers_cur, type);
 	mutex_unlock(&ftrace_lock);
 }
 
@@ -1722,6 +1817,22 @@ ftrace_match_record(struct dyn_ftrace *rec, char *regex, int len, int type)
 	return ftrace_match(str, regex, len, type);
 }
 
+#define TRACER_SET(enable) \
+do { \
+	if (enable) \
+		rec->filter   |= (1 << ftrace_tracers_cur); \
+	else \
+		rec->no_trace |= (1 << ftrace_tracers_cur); \
+} while (0)
+
+#define TRACER_UNSET(enable) \
+do { \
+	if (enable) \
+		rec->filter   &= ~(1 << ftrace_tracers_cur); \
+	else \
+		rec->no_trace &= ~(1 << ftrace_tracers_cur); \
+} while (0)
+
 static int ftrace_match_records(char *buff, int len, int enable)
 {
 	unsigned int search_len;
@@ -1739,16 +1850,23 @@ static int ftrace_match_records(char *buff, int len, int enable)
 	search_len = strlen(search);
 
 	mutex_lock(&ftrace_lock);
+
+	if (ftrace_tracers_cur < 0)
+		goto out_unlock;
+
 	do_for_each_ftrace_rec(pg, rec) {
 
 		if (rec->flags & FTRACE_FL_FAILED)
 			continue;
 
 		if (ftrace_match_record(rec, search, search_len, type)) {
-			if (not)
+			if (not) {
 				rec->flags &= ~flag;
-			else
+				TRACER_UNSET(enable);
+			} else {
 				rec->flags |= flag;
+				TRACER_SET(enable);
+			}
 			found = 1;
 		}
 		/*
@@ -1756,10 +1874,12 @@ static int ftrace_match_records(char *buff, int len, int enable)
 		 * is filtered on.
 		 */
 		if (enable && (rec->flags & FTRACE_FL_FILTER))
-			ftrace_filtered = 1;
+			ftrace_tracer_filtered |= (1 << ftrace_tracers_cur);
+
 	} while_for_each_ftrace_rec();
-	mutex_unlock(&ftrace_lock);
 
+ out_unlock:
+	mutex_unlock(&ftrace_lock);
 	return found;
 }
 
@@ -1811,6 +1931,10 @@ static int ftrace_match_module_records(char *buff, char *mod, int enable)
 	}
 
 	mutex_lock(&ftrace_lock);
+
+	if (ftrace_tracers_cur < 0)
+		goto out_unlock;
+
 	do_for_each_ftrace_rec(pg, rec) {
 
 		if (rec->flags & FTRACE_FL_FAILED)
@@ -1818,20 +1942,27 @@ static int ftrace_match_module_records(char *buff, char *mod, int enable)
 
 		if (ftrace_match_module_record(rec, mod,
 					       search, search_len, type)) {
-			if (not)
+			if (not) {
 				rec->flags &= ~flag;
-			else
+				TRACER_UNSET(enable);
+			} else {
 				rec->flags |= flag;
+				TRACER_SET(enable);
+			}
 			found = 1;
 		}
 		if (enable && (rec->flags & FTRACE_FL_FILTER))
-			ftrace_filtered = 1;
+			ftrace_tracer_filtered |= (1 << ftrace_tracers_cur);
 
 	} while_for_each_ftrace_rec();
+
+ out_unlock:
 	mutex_unlock(&ftrace_lock);
 
 	return found;
 }
+#undef TRACER_SET
+#undef TRACER_UNSET
 
 /*
  * We register the module command as a template to show others how
-- 
1.7.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC 0/3] x86_64,tracing: multiplexing function tracer
  2011-04-29 14:43 [RFC 0/3] x86_64,tracing: multiplexing function tracer Jiri Olsa
                   ` (2 preceding siblings ...)
  2011-04-29 14:43 ` [RFC 3/3] tracing: set_ftrace_filter support Jiri Olsa
@ 2011-04-29 14:57 ` Steven Rostedt
  2011-04-29 15:06   ` Jiri Olsa
  3 siblings, 1 reply; 7+ messages in thread
From: Steven Rostedt @ 2011-04-29 14:57 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: fweisbec, linux-kernel

On Fri, 2011-04-29 at 16:43 +0200, Jiri Olsa wrote:
> hi, me again ;)
> 
> from last RFC email it turned out it'd be good to have support
> for more than 1 currently running function tracers. With
> the possibility to specify separate filter for each of them.

Jiri, I thought I told you to wait, as I'm basically doing the same
thing. Except that I'm gutting the heck out of ftrace.c.

I've been working the last several days rewriting this code.

> 
> I thought about one way how to do that and put it to the
> code for considering. It seems to work properly, though
> I was fighting with set_ftrace_filter for a while.. and
> it is still not ideal ;)

Soon, set_ftrace_filter will only affect the function tracer and not any
other user of function tracing.

I'm almost done. I was hoping to release something today, but it will
probably have to wait till next week.

-- Steve



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC 0/3] x86_64,tracing: multiplexing function tracer
  2011-04-29 14:57 ` [RFC 0/3] x86_64,tracing: multiplexing function tracer Steven Rostedt
@ 2011-04-29 15:06   ` Jiri Olsa
  0 siblings, 0 replies; 7+ messages in thread
From: Jiri Olsa @ 2011-04-29 15:06 UTC (permalink / raw)
  To: Steven Rostedt; +Cc: fweisbec, linux-kernel

On Fri, Apr 29, 2011 at 10:57:10AM -0400, Steven Rostedt wrote:
> On Fri, 2011-04-29 at 16:43 +0200, Jiri Olsa wrote:
> > hi, me again ;)
> > 
> > from last RFC email it turned out it'd be good to have support
> > for more than 1 currently running function tracers. With
> > the possibility to specify separate filter for each of them.
> 
> Jiri, I thought I told you to wait, as I'm basically doing the same
> thing. Except that I'm gutting the heck out of ftrace.c.

yep, I was just keeping busy.. ;)
looking forward to see your change

jirka

> 
> I've been working the last several days rewriting this code.
> 
> > 
> > I thought about one way how to do that and put it to the
> > code for considering. It seems to work properly, though
> > I was fighting with set_ftrace_filter for a while.. and
> > it is still not ideal ;)
> 
> Soon, set_ftrace_filter will only affect the function tracer and not any
> other user of function tracing.
> 
> I'm almost done. I was hoping to release something today, but it will
> probably have to wait till next week.
> 
> -- Steve
> 
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC 3/3] tracing: set_ftrace_filter support
  2011-04-29 14:43 ` [RFC 3/3] tracing: set_ftrace_filter support Jiri Olsa
@ 2011-04-29 15:16   ` Steven Rostedt
  0 siblings, 0 replies; 7+ messages in thread
From: Steven Rostedt @ 2011-04-29 15:16 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: fweisbec, linux-kernel

On Fri, 2011-04-29 at 16:43 +0200, Jiri Olsa wrote:
> diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
> index b12f5df..9ce3484 100644
> --- a/include/linux/ftrace.h
> +++ b/include/linux/ftrace.h
> @@ -164,6 +164,9 @@ struct dyn_ftrace {
>                 unsigned long           flags;
>                 struct dyn_ftrace       *newlist;
>         };
> +       unsigned long                   filter;
> +       unsigned long                   no_trace;
> +       unsigned long                   addr;
>         struct dyn_arch_ftrace          arch;
>  };
>   

Big Fricken NACK!

Absolutely not! The dyn_ftrace structure is allocated for almost every
single function in the kernel. Any function that can be traced has this
structure allocated.

On my box I have:

# cat /debug/tracing/dyn_ftrace_total_info 
32605 0 0

That's 32,605 functions that can be traced, which turns to be 32,605
dyn_ftrace structs allocated. Now this number is after all modules have
been loaded. You added 3 longs, on 64 bit boxes that's 24 bytes, you
just increased the function tracer footprint by 782,520 bytes!

I'm working around not touching that structure, and I will continue to
NAK any changes that increases its size. Actually, I did touch that
structure, but I did not increase the size of it.

-- Steve




^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2011-04-29 15:16 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-04-29 14:43 [RFC 0/3] x86_64,tracing: multiplexing function tracer Jiri Olsa
2011-04-29 14:43 ` [RFC 1/3] tracing: function tracer registration Jiri Olsa
2011-04-29 14:43 ` [RFC 2/3] tracing: adding statical callers Jiri Olsa
2011-04-29 14:43 ` [RFC 3/3] tracing: set_ftrace_filter support Jiri Olsa
2011-04-29 15:16   ` Steven Rostedt
2011-04-29 14:57 ` [RFC 0/3] x86_64,tracing: multiplexing function tracer Steven Rostedt
2011-04-29 15:06   ` Jiri Olsa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®