aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@ghostprotocols.net>2008-05-12 15:20:42 -0400
committerThomas Gleixner <tglx@linutronix.de>2008-05-23 14:31:58 -0400
commit16444a8a40d4c7b4f6de34af0cae1f76a4f6c901 (patch)
tree9c290bcdbdc1ecf8f578c30b3b36914e14fdaacc
parent6e766410c4babd37bc7cd5e25009c179781742c8 (diff)
ftrace: add basic support for gcc profiler instrumentation
If CONFIG_FTRACE is selected and /proc/sys/kernel/ftrace_enabled is set to a non-zero value the ftrace routine will be called everytime we enter a kernel function that is not marked with the "notrace" attribute. The ftrace routine will then call a registered function if a function happens to be registered. [ This code has been highly hacked by Steven Rostedt and Ingo Molnar, so don't blame Arnaldo for all of this ;-) ] Update: It is now possible to register more than one ftrace function. If only one ftrace function is registered, that will be the function that ftrace calls directly. If more than one function is registered, then ftrace will call a function that will loop through the functions to call. Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net> Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--Makefile4
-rw-r--r--arch/x86/Kconfig1
-rw-r--r--arch/x86/kernel/entry_32.S27
-rw-r--r--arch/x86/kernel/entry_64.S37
-rw-r--r--include/linux/ftrace.h38
-rw-r--r--kernel/Makefile1
-rw-r--r--kernel/trace/Kconfig5
-rw-r--r--kernel/trace/Makefile3
-rw-r--r--kernel/trace/ftrace.c138
-rw-r--r--lib/Kconfig.debug2
10 files changed, 256 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 20b32351906b..b4a273f19b52 100644
--- a/Makefile
+++ b/Makefile
@@ -528,6 +528,10 @@ KBUILD_CFLAGS += -g
528KBUILD_AFLAGS += -gdwarf-2 528KBUILD_AFLAGS += -gdwarf-2
529endif 529endif
530 530
531ifdef CONFIG_FTRACE
532KBUILD_CFLAGS += -pg
533endif
534
531# We trigger additional mismatches with less inlining 535# We trigger additional mismatches with less inlining
532ifdef CONFIG_DEBUG_SECTION_MISMATCH 536ifdef CONFIG_DEBUG_SECTION_MISMATCH
533KBUILD_CFLAGS += $(call cc-option, -fno-inline-functions-called-once) 537KBUILD_CFLAGS += $(call cc-option, -fno-inline-functions-called-once)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index fe361ae7ef2f..c742dfeb0dbe 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -23,6 +23,7 @@ config X86
23 select HAVE_OPROFILE 23 select HAVE_OPROFILE
24 select HAVE_KPROBES 24 select HAVE_KPROBES
25 select HAVE_KRETPROBES 25 select HAVE_KRETPROBES
26 select HAVE_FTRACE
26 select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64) 27 select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64)
27 select HAVE_ARCH_KGDB if !X86_VOYAGER 28 select HAVE_ARCH_KGDB if !X86_VOYAGER
28 29
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 2a609dc3271c..f47b9b5440d2 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -1109,6 +1109,33 @@ ENDPROC(xen_failsafe_callback)
1109 1109
1110#endif /* CONFIG_XEN */ 1110#endif /* CONFIG_XEN */
1111 1111
1112#ifdef CONFIG_FTRACE
1113ENTRY(mcount)
1114 cmpl $ftrace_stub, ftrace_trace_function
1115 jnz trace
1116
1117.globl ftrace_stub
1118ftrace_stub:
1119 ret
1120
1121 /* taken from glibc */
1122trace:
1123 pushl %eax
1124 pushl %ecx
1125 pushl %edx
1126 movl 0xc(%esp), %eax
1127 movl 0x4(%ebp), %edx
1128
1129 call *ftrace_trace_function
1130
1131 popl %edx
1132 popl %ecx
1133 popl %eax
1134
1135 jmp ftrace_stub
1136END(mcount)
1137#endif
1138
1112.section .rodata,"a" 1139.section .rodata,"a"
1113#include "syscall_table_32.S" 1140#include "syscall_table_32.S"
1114 1141
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 556a8df522a7..f046e0c64883 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -54,6 +54,43 @@
54 54
55 .code64 55 .code64
56 56
57#ifdef CONFIG_FTRACE
58ENTRY(mcount)
59 cmpq $ftrace_stub, ftrace_trace_function
60 jnz trace
61.globl ftrace_stub
62ftrace_stub:
63 retq
64
65trace:
66 /* taken from glibc */
67 subq $0x38, %rsp
68 movq %rax, (%rsp)
69 movq %rcx, 8(%rsp)
70 movq %rdx, 16(%rsp)
71 movq %rsi, 24(%rsp)
72 movq %rdi, 32(%rsp)
73 movq %r8, 40(%rsp)
74 movq %r9, 48(%rsp)
75
76 movq 0x38(%rsp), %rdi
77 movq 8(%rbp), %rsi
78
79 call *ftrace_trace_function
80
81 movq 48(%rsp), %r9
82 movq 40(%rsp), %r8
83 movq 32(%rsp), %rdi
84 movq 24(%rsp), %rsi
85 movq 16(%rsp), %rdx
86 movq 8(%rsp), %rcx
87 movq (%rsp), %rax
88 addq $0x38, %rsp
89
90 jmp ftrace_stub
91END(mcount)
92#endif
93
57#ifndef CONFIG_PREEMPT 94#ifndef CONFIG_PREEMPT
58#define retint_kernel retint_restore_args 95#define retint_kernel retint_restore_args
59#endif 96#endif
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
new file mode 100644
index 000000000000..b96ef14c249a
--- /dev/null
+++ b/include/linux/ftrace.h
@@ -0,0 +1,38 @@
1#ifndef _LINUX_FTRACE_H
2#define _LINUX_FTRACE_H
3
4#ifdef CONFIG_FTRACE
5
6#include <linux/linkage.h>
7
8#define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0))
9#define CALLER_ADDR1 ((unsigned long)__builtin_return_address(1))
10#define CALLER_ADDR2 ((unsigned long)__builtin_return_address(2))
11
12typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip);
13
14struct ftrace_ops {
15 ftrace_func_t func;
16 struct ftrace_ops *next;
17};
18
19/*
20 * The ftrace_ops must be a static and should also
21 * be read_mostly. These functions do modify read_mostly variables
22 * so use them sparely. Never free an ftrace_op or modify the
23 * next pointer after it has been registered. Even after unregistering
24 * it, the next pointer may still be used internally.
25 */
26int register_ftrace_function(struct ftrace_ops *ops);
27int unregister_ftrace_function(struct ftrace_ops *ops);
28void clear_ftrace_function(void);
29
30extern void ftrace_stub(unsigned long a0, unsigned long a1);
31extern void mcount(void);
32
33#else /* !CONFIG_FTRACE */
34# define register_ftrace_function(ops) do { } while (0)
35# define unregister_ftrace_function(ops) do { } while (0)
36# define clear_ftrace_function(ops) do { } while (0)
37#endif /* CONFIG_FTRACE */
38#endif /* _LINUX_FTRACE_H */
diff --git a/kernel/Makefile b/kernel/Makefile
index 1c9938addb9d..fa05f6d8bdbf 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
69obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o 69obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
70obj-$(CONFIG_MARKERS) += marker.o 70obj-$(CONFIG_MARKERS) += marker.o
71obj-$(CONFIG_LATENCYTOP) += latencytop.o 71obj-$(CONFIG_LATENCYTOP) += latencytop.o
72obj-$(CONFIG_FTRACE) += trace/
72 73
73ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y) 74ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
74# According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is 75# According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
new file mode 100644
index 000000000000..8185c91417bc
--- /dev/null
+++ b/kernel/trace/Kconfig
@@ -0,0 +1,5 @@
1#
2# Architectures that offer an FTRACE implementation should select HAVE_FTRACE:
3#
4config HAVE_FTRACE
5 bool
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
new file mode 100644
index 000000000000..bf4fd215a6a9
--- /dev/null
+++ b/kernel/trace/Makefile
@@ -0,0 +1,3 @@
1obj-$(CONFIG_FTRACE) += libftrace.o
2
3libftrace-y := ftrace.o
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
new file mode 100644
index 000000000000..b6a80b98a3fb
--- /dev/null
+++ b/kernel/trace/ftrace.c
@@ -0,0 +1,138 @@
1/*
2 * Infrastructure for profiling code inserted by 'gcc -pg'.
3 *
4 * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
5 * Copyright (C) 2004-2008 Ingo Molnar <mingo@redhat.com>
6 *
7 * Originally ported from the -rt patch by:
8 * Copyright (C) 2007 Arnaldo Carvalho de Melo <acme@redhat.com>
9 *
10 * Based on code in the latency_tracer, that is:
11 *
12 * Copyright (C) 2004-2006 Ingo Molnar
13 * Copyright (C) 2004 William Lee Irwin III
14 */
15
16#include <linux/module.h>
17#include <linux/ftrace.h>
18
19static DEFINE_SPINLOCK(ftrace_func_lock);
20static struct ftrace_ops ftrace_list_end __read_mostly =
21{
22 .func = ftrace_stub,
23};
24
25static struct ftrace_ops *ftrace_list __read_mostly = &ftrace_list_end;
26ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub;
27
28/* mcount is defined per arch in assembly */
29EXPORT_SYMBOL(mcount);
30
31notrace void ftrace_list_func(unsigned long ip, unsigned long parent_ip)
32{
33 struct ftrace_ops *op = ftrace_list;
34
35 /* in case someone actually ports this to alpha! */
36 read_barrier_depends();
37
38 while (op != &ftrace_list_end) {
39 /* silly alpha */
40 read_barrier_depends();
41 op->func(ip, parent_ip);
42 op = op->next;
43 };
44}
45
46/**
47 * register_ftrace_function - register a function for profiling
48 * @ops - ops structure that holds the function for profiling.
49 *
50 * Register a function to be called by all functions in the
51 * kernel.
52 *
53 * Note: @ops->func and all the functions it calls must be labeled
54 * with "notrace", otherwise it will go into a
55 * recursive loop.
56 */
57int register_ftrace_function(struct ftrace_ops *ops)
58{
59 unsigned long flags;
60
61 spin_lock_irqsave(&ftrace_func_lock, flags);
62 ops->next = ftrace_list;
63 /*
64 * We are entering ops into the ftrace_list but another
65 * CPU might be walking that list. We need to make sure
66 * the ops->next pointer is valid before another CPU sees
67 * the ops pointer included into the ftrace_list.
68 */
69 smp_wmb();
70 ftrace_list = ops;
71 /*
72 * For one func, simply call it directly.
73 * For more than one func, call the chain.
74 */
75 if (ops->next == &ftrace_list_end)
76 ftrace_trace_function = ops->func;
77 else
78 ftrace_trace_function = ftrace_list_func;
79 spin_unlock_irqrestore(&ftrace_func_lock, flags);
80
81 return 0;
82}
83
84/**
85 * unregister_ftrace_function - unresgister a function for profiling.
86 * @ops - ops structure that holds the function to unregister
87 *
88 * Unregister a function that was added to be called by ftrace profiling.
89 */
90int unregister_ftrace_function(struct ftrace_ops *ops)
91{
92 unsigned long flags;
93 struct ftrace_ops **p;
94 int ret = 0;
95
96 spin_lock_irqsave(&ftrace_func_lock, flags);
97
98 /*
99 * If we are the only function, then the ftrace pointer is
100 * pointing directly to that function.
101 */
102 if (ftrace_list == ops && ops->next == &ftrace_list_end) {
103 ftrace_trace_function = ftrace_stub;
104 ftrace_list = &ftrace_list_end;
105 goto out;
106 }
107
108 for (p = &ftrace_list; *p != &ftrace_list_end; p = &(*p)->next)
109 if (*p == ops)
110 break;
111
112 if (*p != ops) {
113 ret = -1;
114 goto out;
115 }
116
117 *p = (*p)->next;
118
119 /* If we only have one func left, then call that directly */
120 if (ftrace_list->next == &ftrace_list_end)
121 ftrace_trace_function = ftrace_list->func;
122
123 out:
124 spin_unlock_irqrestore(&ftrace_func_lock, flags);
125
126 return 0;
127}
128
129/**
130 * clear_ftrace_function - reset the ftrace function
131 *
132 * This NULLs the ftrace function and in essence stops
133 * tracing. There may be lag
134 */
135void clear_ftrace_function(void)
136{
137 ftrace_trace_function = ftrace_stub;
138}
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index d2099f41aa1e..d8b6279a9b42 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -634,6 +634,8 @@ config LATENCYTOP
634 Enable this option if you want to use the LatencyTOP tool 634 Enable this option if you want to use the LatencyTOP tool
635 to find out which userspace is blocking on what kernel operations. 635 to find out which userspace is blocking on what kernel operations.
636 636
637source kernel/trace/Kconfig
638
637config PROVIDE_OHCI1394_DMA_INIT 639config PROVIDE_OHCI1394_DMA_INIT
638 bool "Remote debugging over FireWire early on boot" 640 bool "Remote debugging over FireWire early on boot"
639 depends on PCI && X86 641 depends on PCI && X86