aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2010-05-20 01:47:21 -0400
committerFrederic Weisbecker <fweisbec@gmail.com>2010-06-08 17:31:27 -0400
commitb0f82b81fe6bbcf78d478071f33e44554726bc81 (patch)
tree6305c095b927f956a791b9dce687cb94a21718e6
parentc9cf4dbb4d9ca715d8fedf13301a53296429abc6 (diff)
perf: Drop the skip argument from perf_arch_fetch_regs_caller
Drop this argument now that we always want to rewind only to the state of the first caller. It means frame pointers are not necessary anymore to reliably get the source of an event. But this also means we need this helper to be a macro now, as an inline function is not an option since we need to know when to provide a default implentation. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Signed-off-by: Paul Mackerras <paulus@samba.org> Cc: David Miller <davem@davemloft.net> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--arch/powerpc/include/asm/perf_event.h12
-rw-r--r--arch/powerpc/kernel/misc.S26
-rw-r--r--arch/sparc/include/asm/perf_event.h8
-rw-r--r--arch/sparc/kernel/helpers.S6
-rw-r--r--arch/x86/include/asm/perf_event.h13
-rw-r--r--arch/x86/include/asm/stacktrace.h7
-rw-r--r--arch/x86/kernel/cpu/perf_event.c16
-rw-r--r--include/linux/perf_event.h32
-rw-r--r--include/trace/ftrace.h2
-rw-r--r--kernel/perf_event.c5
-rw-r--r--kernel/trace/trace_event_perf.c2
11 files changed, 46 insertions, 83 deletions
diff --git a/arch/powerpc/include/asm/perf_event.h b/arch/powerpc/include/asm/perf_event.h
index e6d4ce69b126..5c16b891d501 100644
--- a/arch/powerpc/include/asm/perf_event.h
+++ b/arch/powerpc/include/asm/perf_event.h
@@ -21,3 +21,15 @@
21#ifdef CONFIG_FSL_EMB_PERF_EVENT 21#ifdef CONFIG_FSL_EMB_PERF_EVENT
22#include <asm/perf_event_fsl_emb.h> 22#include <asm/perf_event_fsl_emb.h>
23#endif 23#endif
24
25#ifdef CONFIG_PERF_EVENTS
26#include <asm/ptrace.h>
27#include <asm/reg.h>
28
29#define perf_arch_fetch_caller_regs(regs, __ip) \
30 do { \
31 (regs)->nip = __ip; \
32 (regs)->gpr[1] = *(unsigned long *)__get_SP(); \
33 asm volatile("mfmsr %0" : "=r" ((regs)->msr)); \
34 } while (0)
35#endif
diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S
index 22e507c8a556..2d29752cbe16 100644
--- a/arch/powerpc/kernel/misc.S
+++ b/arch/powerpc/kernel/misc.S
@@ -127,29 +127,3 @@ _GLOBAL(__setup_cpu_power7)
127_GLOBAL(__restore_cpu_power7) 127_GLOBAL(__restore_cpu_power7)
128 /* place holder */ 128 /* place holder */
129 blr 129 blr
130
131/*
132 * Get a minimal set of registers for our caller's nth caller.
133 * r3 = regs pointer, r5 = n.
134 *
135 * We only get R1 (stack pointer), NIP (next instruction pointer)
136 * and LR (link register). These are all we can get in the
137 * general case without doing complicated stack unwinding, but
138 * fortunately they are enough to do a stack backtrace, which
139 * is all we need them for.
140 */
141_GLOBAL(perf_arch_fetch_caller_regs)
142 mr r6,r1
143 cmpwi r5,0
144 mflr r4
145 ble 2f
146 mtctr r5
1471: PPC_LL r6,0(r6)
148 bdnz 1b
149 PPC_LL r4,PPC_LR_STKOFF(r6)
1502: PPC_LL r7,0(r6)
151 PPC_LL r7,PPC_LR_STKOFF(r7)
152 PPC_STL r6,GPR1-STACK_FRAME_OVERHEAD(r3)
153 PPC_STL r4,_NIP-STACK_FRAME_OVERHEAD(r3)
154 PPC_STL r7,_LINK-STACK_FRAME_OVERHEAD(r3)
155 blr
diff --git a/arch/sparc/include/asm/perf_event.h b/arch/sparc/include/asm/perf_event.h
index 7e2669894ce8..74c4e0cd889c 100644
--- a/arch/sparc/include/asm/perf_event.h
+++ b/arch/sparc/include/asm/perf_event.h
@@ -6,7 +6,15 @@ extern void set_perf_event_pending(void);
6#define PERF_EVENT_INDEX_OFFSET 0 6#define PERF_EVENT_INDEX_OFFSET 0
7 7
8#ifdef CONFIG_PERF_EVENTS 8#ifdef CONFIG_PERF_EVENTS
9#include <asm/ptrace.h>
10
9extern void init_hw_perf_events(void); 11extern void init_hw_perf_events(void);
12
13extern void
14__perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip);
15
16#define perf_arch_fetch_caller_regs(pt_regs, ip) \
17 __perf_arch_fetch_caller_regs(pt_regs, ip, 1);
10#else 18#else
11static inline void init_hw_perf_events(void) { } 19static inline void init_hw_perf_events(void) { }
12#endif 20#endif
diff --git a/arch/sparc/kernel/helpers.S b/arch/sparc/kernel/helpers.S
index 92090cc9e829..682fee06a16b 100644
--- a/arch/sparc/kernel/helpers.S
+++ b/arch/sparc/kernel/helpers.S
@@ -47,9 +47,9 @@ stack_trace_flush:
47 .size stack_trace_flush,.-stack_trace_flush 47 .size stack_trace_flush,.-stack_trace_flush
48 48
49#ifdef CONFIG_PERF_EVENTS 49#ifdef CONFIG_PERF_EVENTS
50 .globl perf_arch_fetch_caller_regs 50 .globl __perf_arch_fetch_caller_regs
51 .type perf_arch_fetch_caller_regs,#function 51 .type __perf_arch_fetch_caller_regs,#function
52perf_arch_fetch_caller_regs: 52__perf_arch_fetch_caller_regs:
53 /* We always read the %pstate into %o5 since we will use 53 /* We always read the %pstate into %o5 since we will use
54 * that to construct a fake %tstate to store into the regs. 54 * that to construct a fake %tstate to store into the regs.
55 */ 55 */
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index 254883d0c7e0..02de29830ffe 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -140,6 +140,19 @@ extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
140extern unsigned long perf_misc_flags(struct pt_regs *regs); 140extern unsigned long perf_misc_flags(struct pt_regs *regs);
141#define perf_misc_flags(regs) perf_misc_flags(regs) 141#define perf_misc_flags(regs) perf_misc_flags(regs)
142 142
143#include <asm/stacktrace.h>
144
145/*
146 * We abuse bit 3 from flags to pass exact information, see perf_misc_flags
147 * and the comment with PERF_EFLAGS_EXACT.
148 */
149#define perf_arch_fetch_caller_regs(regs, __ip) { \
150 (regs)->ip = (__ip); \
151 (regs)->bp = caller_frame_pointer(); \
152 (regs)->cs = __KERNEL_CS; \
153 regs->flags = 0; \
154}
155
143#else 156#else
144static inline void init_hw_perf_events(void) { } 157static inline void init_hw_perf_events(void) { }
145static inline void perf_events_lapic_init(void) { } 158static inline void perf_events_lapic_init(void) { }
diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h
index a957463d3c7a..2b16a2ad23dc 100644
--- a/arch/x86/include/asm/stacktrace.h
+++ b/arch/x86/include/asm/stacktrace.h
@@ -78,17 +78,14 @@ struct stack_frame_ia32 {
78 u32 return_address; 78 u32 return_address;
79}; 79};
80 80
81static inline unsigned long rewind_frame_pointer(int n) 81static inline unsigned long caller_frame_pointer(void)
82{ 82{
83 struct stack_frame *frame; 83 struct stack_frame *frame;
84 84
85 get_bp(frame); 85 get_bp(frame);
86 86
87#ifdef CONFIG_FRAME_POINTER 87#ifdef CONFIG_FRAME_POINTER
88 while (n--) { 88 frame = frame->next_frame;
89 if (probe_kernel_address(&frame->next_frame, frame))
90 break;
91 }
92#endif 89#endif
93 90
94 return (unsigned long)frame; 91 return (unsigned long)frame;
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 9632fb61e8f9..2c075fe573d0 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -1706,22 +1706,6 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
1706 return entry; 1706 return entry;
1707} 1707}
1708 1708
1709void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip)
1710{
1711 regs->ip = ip;
1712 /*
1713 * perf_arch_fetch_caller_regs adds another call, we need to increment
1714 * the skip level
1715 */
1716 regs->bp = rewind_frame_pointer(skip + 1);
1717 regs->cs = __KERNEL_CS;
1718 /*
1719 * We abuse bit 3 to pass exact information, see perf_misc_flags
1720 * and the comment with PERF_EFLAGS_EXACT.
1721 */
1722 regs->flags = 0;
1723}
1724
1725unsigned long perf_instruction_pointer(struct pt_regs *regs) 1709unsigned long perf_instruction_pointer(struct pt_regs *regs)
1726{ 1710{
1727 unsigned long ip; 1711 unsigned long ip;
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index fb6c91eac7e3..bea785cef493 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -905,8 +905,10 @@ extern atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
905 905
906extern void __perf_sw_event(u32, u64, int, struct pt_regs *, u64); 906extern void __perf_sw_event(u32, u64, int, struct pt_regs *, u64);
907 907
908extern void 908#ifndef perf_arch_fetch_caller_regs
909perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip); 909static inline void
910perf_arch_fetch_caller_regs(struct regs *regs, unsigned long ip) { }
911#endif
910 912
911/* 913/*
912 * Take a snapshot of the regs. Skip ip and frame pointer to 914 * Take a snapshot of the regs. Skip ip and frame pointer to
@@ -916,31 +918,11 @@ perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip);
916 * - bp for callchains 918 * - bp for callchains
917 * - eflags, for future purposes, just in case 919 * - eflags, for future purposes, just in case
918 */ 920 */
919static inline void perf_fetch_caller_regs(struct pt_regs *regs, int skip) 921static inline void perf_fetch_caller_regs(struct pt_regs *regs)
920{ 922{
921 unsigned long ip;
922
923 memset(regs, 0, sizeof(*regs)); 923 memset(regs, 0, sizeof(*regs));
924 924
925 switch (skip) { 925 perf_arch_fetch_caller_regs(regs, CALLER_ADDR0);
926 case 1 :
927 ip = CALLER_ADDR0;
928 break;
929 case 2 :
930 ip = CALLER_ADDR1;
931 break;
932 case 3 :
933 ip = CALLER_ADDR2;
934 break;
935 case 4:
936 ip = CALLER_ADDR3;
937 break;
938 /* No need to support further for now */
939 default:
940 ip = 0;
941 }
942
943 return perf_arch_fetch_caller_regs(regs, ip, skip);
944} 926}
945 927
946static inline void 928static inline void
@@ -950,7 +932,7 @@ perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr)
950 struct pt_regs hot_regs; 932 struct pt_regs hot_regs;
951 933
952 if (!regs) { 934 if (!regs) {
953 perf_fetch_caller_regs(&hot_regs, 1); 935 perf_fetch_caller_regs(&hot_regs);
954 regs = &hot_regs; 936 regs = &hot_regs;
955 } 937 }
956 __perf_sw_event(event_id, nr, nmi, regs, addr); 938 __perf_sw_event(event_id, nr, nmi, regs, addr);
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 3d685d1f2a03..8ee8b6e6b25e 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -705,7 +705,7 @@ perf_trace_##call(void *__data, proto) \
705 int __data_size; \ 705 int __data_size; \
706 int rctx; \ 706 int rctx; \
707 \ 707 \
708 perf_fetch_caller_regs(&__regs, 1); \ 708 perf_fetch_caller_regs(&__regs); \
709 \ 709 \
710 __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \ 710 __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \
711 __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),\ 711 __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),\
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index e099650cd249..9ae4dbcdf469 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -2851,11 +2851,6 @@ __weak struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
2851 return NULL; 2851 return NULL;
2852} 2852}
2853 2853
2854__weak
2855void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip)
2856{
2857}
2858
2859 2854
2860/* 2855/*
2861 * We assume there is only KVM supporting the callbacks. 2856 * We assume there is only KVM supporting the callbacks.
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
index cb6f365016e4..21db1d3a48d0 100644
--- a/kernel/trace/trace_event_perf.c
+++ b/kernel/trace/trace_event_perf.c
@@ -9,8 +9,6 @@
9#include <linux/kprobes.h> 9#include <linux/kprobes.h>
10#include "trace.h" 10#include "trace.h"
11 11
12EXPORT_SYMBOL_GPL(perf_arch_fetch_caller_regs);
13
14static char *perf_trace_buf[4]; 12static char *perf_trace_buf[4];
15 13
16/* 14/*