aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2009-02-10 00:10:27 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-02-22 18:48:53 -0500
commit6794c78243bfda020ab184d6d578944f8e90d26c (patch)
treee697b43e4b757723ed9798c9666b759d9e29ca12
parent17be5b3ddf71d980f67fc826e49b00cd2afd724d (diff)
powerpc64: port of the function graph tracer
This is a port of the function graph tracer that was written by Frederic Weisbecker for the x86. This only works for PPC64 at the moment and only for static tracing. PPC32 and dynamic function graph tracing support will come later. The trace produces a visual calling of functions: # tracer: function_graph # # CPU DURATION FUNCTION CALLS # | | | | | | | 0) 2.224 us | } 0) ! 271.024 us | } 0) ! 320.080 us | } 0) ! 324.656 us | } 0) ! 329.136 us | } 0) | .put_prev_task_fair() { 0) | .update_curr() { 0) 2.240 us | .update_min_vruntime(); 0) 6.512 us | } 0) 2.528 us | .__enqueue_entity(); 0) + 15.536 us | } 0) | .pick_next_task_fair() { 0) 2.032 us | .__pick_next_entity(); 0) 2.064 us | .__clear_buddies(); 0) | .set_next_entity() { 0) 2.672 us | .__dequeue_entity(); 0) 6.864 us | } Geoff Lavand tested on PS3. Tested-by: Geoff Levand <geoffrey.levand@am.sony.com> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--arch/powerpc/Kconfig1
-rw-r--r--arch/powerpc/kernel/Makefile9
-rw-r--r--arch/powerpc/kernel/entry_64.S58
-rw-r--r--arch/powerpc/kernel/ftrace.c79
-rw-r--r--arch/powerpc/kernel/process.c16
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S1
6 files changed, 154 insertions, 10 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index ccdd8de3c558..e122d241f17d 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -111,6 +111,7 @@ config PPC
111 select HAVE_FTRACE_MCOUNT_RECORD 111 select HAVE_FTRACE_MCOUNT_RECORD
112 select HAVE_DYNAMIC_FTRACE 112 select HAVE_DYNAMIC_FTRACE
113 select HAVE_FUNCTION_TRACER 113 select HAVE_FUNCTION_TRACER
114 select HAVE_FUNCTION_GRAPH_TRACER if !DYNAMIC_FTRACE && PPC64
114 select ARCH_WANT_OPTIONAL_GPIOLIB 115 select ARCH_WANT_OPTIONAL_GPIOLIB
115 select HAVE_IDE 116 select HAVE_IDE
116 select HAVE_IOREMAP_PROT 117 select HAVE_IOREMAP_PROT
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index d15992119085..583ba6493a62 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -18,12 +18,10 @@ CFLAGS_REMOVE_cputable.o = -pg -mno-sched-epilog
18CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog 18CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog
19CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog 19CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog
20CFLAGS_REMOVE_prom.o = -pg -mno-sched-epilog 20CFLAGS_REMOVE_prom.o = -pg -mno-sched-epilog
21 21# do not trace tracer code
22ifdef CONFIG_DYNAMIC_FTRACE
23# dynamic ftrace setup.
24CFLAGS_REMOVE_ftrace.o = -pg -mno-sched-epilog 22CFLAGS_REMOVE_ftrace.o = -pg -mno-sched-epilog
25endif 23# timers used by tracing
26 24CFLAGS_REMOVE_time.o = -pg -mno-sched-epilog
27endif 25endif
28 26
29obj-y := cputable.o ptrace.o syscalls.o \ 27obj-y := cputable.o ptrace.o syscalls.o \
@@ -95,6 +93,7 @@ obj-$(CONFIG_AUDIT) += audit.o
95obj64-$(CONFIG_AUDIT) += compat_audit.o 93obj64-$(CONFIG_AUDIT) += compat_audit.o
96 94
97obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o 95obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
96obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
98 97
99obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o 98obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o
100 99
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 383ed6eb0085..a32699e74c3c 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -931,13 +931,65 @@ _GLOBAL(_mcount)
931 ld r5,0(r5) 931 ld r5,0(r5)
932 mtctr r5 932 mtctr r5
933 bctrl 933 bctrl
934
935 nop 934 nop
935
936
937#ifdef CONFIG_FUNCTION_GRAPH_TRACER
938 b ftrace_graph_caller
939#endif
936 ld r0, 128(r1) 940 ld r0, 128(r1)
937 mtlr r0 941 mtlr r0
938 addi r1, r1, 112 942 addi r1, r1, 112
939_GLOBAL(ftrace_stub) 943_GLOBAL(ftrace_stub)
940 blr 944 blr
941 945
942#endif 946#endif /* CONFIG_DYNAMIC_FTRACE */
943#endif 947
948#ifdef CONFIG_FUNCTION_GRAPH_TRACER
949ftrace_graph_caller:
950 /* load r4 with local address */
951 ld r4, 128(r1)
952 subi r4, r4, MCOUNT_INSN_SIZE
953
954 /* get the parent address */
955 ld r11, 112(r1)
956 addi r3, r11, 16
957
958 bl .prepare_ftrace_return
959 nop
960
961 ld r0, 128(r1)
962 mtlr r0
963 addi r1, r1, 112
964 blr
965
966_GLOBAL(return_to_handler)
967 /* need to save return values */
968 std r4, -32(r1)
969 std r3, -24(r1)
970 /* save TOC */
971 std r2, -16(r1)
972 std r31, -8(r1)
973 mr r31, r1
974 stdu r1, -112(r1)
975
976 /* update the TOC */
977 LOAD_REG_IMMEDIATE(r4,ftrace_return_to_handler)
978 ld r2, 8(r4)
979
980 bl .ftrace_return_to_handler
981 nop
982
983 /* return value has real return address */
984 mtlr r3
985
986 ld r1, 0(r1)
987 ld r4, -32(r1)
988 ld r3, -24(r1)
989 ld r2, -16(r1)
990 ld r31, -8(r1)
991
992 /* Jump back to real return address */
993 blr
994#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
995#endif /* CONFIG_FUNCTION_TRACER */
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c
index 4112175183d3..c9b1547f65a5 100644
--- a/arch/powerpc/kernel/ftrace.c
+++ b/arch/powerpc/kernel/ftrace.c
@@ -5,6 +5,9 @@
5 * 5 *
6 * Thanks goes out to P.A. Semi, Inc for supplying me with a PPC64 box. 6 * Thanks goes out to P.A. Semi, Inc for supplying me with a PPC64 box.
7 * 7 *
8 * Added function graph tracer code, taken from x86 that was written
9 * by Frederic Weisbecker, and ported to PPC by Steven Rostedt.
10 *
8 */ 11 */
9 12
10#include <linux/spinlock.h> 13#include <linux/spinlock.h>
@@ -20,8 +23,6 @@
20#include <asm/code-patching.h> 23#include <asm/code-patching.h>
21#include <asm/ftrace.h> 24#include <asm/ftrace.h>
22 25
23static unsigned int ftrace_nop = PPC_NOP_INSTR;
24
25#ifdef CONFIG_PPC32 26#ifdef CONFIG_PPC32
26# define GET_ADDR(addr) addr 27# define GET_ADDR(addr) addr
27#else 28#else
@@ -29,6 +30,8 @@ static unsigned int ftrace_nop = PPC_NOP_INSTR;
29# define GET_ADDR(addr) (*(unsigned long *)addr) 30# define GET_ADDR(addr) (*(unsigned long *)addr)
30#endif 31#endif
31 32
33#ifdef CONFIG_DYNAMIC_FTRACE
34static unsigned int ftrace_nop = PPC_NOP_INSTR;
32 35
33static unsigned int ftrace_calc_offset(long ip, long addr) 36static unsigned int ftrace_calc_offset(long ip, long addr)
34{ 37{
@@ -525,3 +528,75 @@ int __init ftrace_dyn_arch_init(void *data)
525 528
526 return 0; 529 return 0;
527} 530}
531#endif /* CONFIG_DYNAMIC_FTRACE */
532
533#ifdef CONFIG_FUNCTION_GRAPH_TRACER
534
535/*
536 * Hook the return address and push it in the stack of return addrs
537 * in current thread info.
538 */
539void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
540{
541 unsigned long old;
542 unsigned long long calltime;
543 int faulted;
544 struct ftrace_graph_ent trace;
545 unsigned long return_hooker = (unsigned long)
546 &return_to_handler;
547
548 if (unlikely(atomic_read(&current->tracing_graph_pause)))
549 return;
550
551 return_hooker = GET_ADDR(return_hooker);
552
553 /*
554 * Protect against fault, even if it shouldn't
555 * happen. This tool is too much intrusive to
556 * ignore such a protection.
557 */
558 asm volatile(
559 "1: " PPC_LL "%[old], 0(%[parent])\n"
560 "2: " PPC_STL "%[return_hooker], 0(%[parent])\n"
561 " li %[faulted], 0\n"
562 "3:"
563
564 ".section .fixup, \"ax\"\n"
565 "4: li %[faulted], 1\n"
566 " b 3b\n"
567 ".previous\n"
568
569 ".section __ex_table,\"a\"\n"
570 PPC_LONG_ALIGN "\n"
571 PPC_LONG "1b,4b\n"
572 PPC_LONG "2b,4b\n"
573 ".previous"
574
575 : [old] "=r" (old), [faulted] "=r" (faulted)
576 : [parent] "r" (parent), [return_hooker] "r" (return_hooker)
577 : "memory"
578 );
579
580 if (unlikely(faulted)) {
581 ftrace_graph_stop();
582 WARN_ON(1);
583 return;
584 }
585
586 calltime = cpu_clock(raw_smp_processor_id());
587
588 if (ftrace_push_return_trace(old, calltime,
589 self_addr, &trace.depth) == -EBUSY) {
590 *parent = old;
591 return;
592 }
593
594 trace.func = self_addr;
595
596 /* Only trace if the calling function expects to */
597 if (!ftrace_graph_entry(&trace)) {
598 current->curr_ret_stack--;
599 *parent = old;
600 }
601}
602#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index fb7049c054c0..8ede428e76c0 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -33,6 +33,7 @@
33#include <linux/mqueue.h> 33#include <linux/mqueue.h>
34#include <linux/hardirq.h> 34#include <linux/hardirq.h>
35#include <linux/utsname.h> 35#include <linux/utsname.h>
36#include <linux/ftrace.h>
36#include <linux/kernel_stat.h> 37#include <linux/kernel_stat.h>
37 38
38#include <asm/pgtable.h> 39#include <asm/pgtable.h>
@@ -1008,6 +1009,14 @@ void show_stack(struct task_struct *tsk, unsigned long *stack)
1008 unsigned long sp, ip, lr, newsp; 1009 unsigned long sp, ip, lr, newsp;
1009 int count = 0; 1010 int count = 0;
1010 int firstframe = 1; 1011 int firstframe = 1;
1012#ifdef CONFIG_FUNCTION_GRAPH_TRACER
1013 int curr_frame = current->curr_ret_stack;
1014 extern void return_to_handler(void);
1015 unsigned long addr = (unsigned long)return_to_handler;
1016#ifdef CONFIG_PPC64
1017 addr = *(unsigned long*)addr;
1018#endif
1019#endif
1011 1020
1012 sp = (unsigned long) stack; 1021 sp = (unsigned long) stack;
1013 if (tsk == NULL) 1022 if (tsk == NULL)
@@ -1030,6 +1039,13 @@ void show_stack(struct task_struct *tsk, unsigned long *stack)
1030 ip = stack[STACK_FRAME_LR_SAVE]; 1039 ip = stack[STACK_FRAME_LR_SAVE];
1031 if (!firstframe || ip != lr) { 1040 if (!firstframe || ip != lr) {
1032 printk("["REG"] ["REG"] %pS", sp, ip, (void *)ip); 1041 printk("["REG"] ["REG"] %pS", sp, ip, (void *)ip);
1042#ifdef CONFIG_FUNCTION_GRAPH_TRACER
1043 if (ip == addr && curr_frame >= 0) {
1044 printk(" (%pS)",
1045 (void *)current->ret_stack[curr_frame].ret);
1046 curr_frame--;
1047 }
1048#endif
1033 if (firstframe) 1049 if (firstframe)
1034 printk(" (unreliable)"); 1050 printk(" (unreliable)");
1035 printk("\n"); 1051 printk("\n");
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 161b9b9691f0..895af44bf1f4 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -58,6 +58,7 @@ SECTIONS
58 SCHED_TEXT 58 SCHED_TEXT
59 LOCK_TEXT 59 LOCK_TEXT
60 KPROBES_TEXT 60 KPROBES_TEXT
61 IRQENTRY_TEXT
61 62
62#ifdef CONFIG_PPC32 63#ifdef CONFIG_PPC32
63 *(.got1) 64 *(.got1)