aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-06-15 03:57:59 -0400
committerIngo Molnar <mingo@elte.hu>2009-06-15 03:08:08 -0400
commit038e836e97e70c4ad2b5058b07fc7207f50b59dd (patch)
tree37a9d0a2d95f768593a6594134af98160890ae60
parent5a6cec3abbdb74244caab68db100825a8c4ac02d (diff)
perf_counter, x86: Fix kernel-space call-chains
Kernel-space call-chains were trimmed at the first entry because we never processed anything beyond the first stack context. Allow the backtrace to jump from NMI to IRQ stack then to task stack and finally user-space stack. Also calculate the stack and bp variables correctly so that the stack walker does not exit early. We can get deep traces as a result, visible in perf report -D output: 0x32af0 [0xe0]: PERF_EVENT (IP, 5): 15134: 0xffffffff815225fd period: 1 ... chain: u:2, k:22, nr:24 ..... 0: 0xffffffff815225fd ..... 1: 0xffffffff810ac51c ..... 2: 0xffffffff81018e29 ..... 3: 0xffffffff81523939 ..... 4: 0xffffffff81524b8f ..... 5: 0xffffffff81524bd9 ..... 6: 0xffffffff8105e498 ..... 7: 0xffffffff8152315a ..... 8: 0xffffffff81522c3a ..... 9: 0xffffffff810d9b74 ..... 10: 0xffffffff810dbeec ..... 11: 0xffffffff810dc3fb This is a 22-entries kernel-space chain. (We still only record reliable stack entries.) Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/kernel/cpu/perf_counter.c22
1 files changed, 9 insertions, 13 deletions
diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c
index 09d8cb69c3f3..6d5e7cfd97e7 100644
--- a/arch/x86/kernel/cpu/perf_counter.c
+++ b/arch/x86/kernel/cpu/perf_counter.c
@@ -1575,8 +1575,8 @@ static void backtrace_warning(void *data, char *msg)
1575 1575
1576static int backtrace_stack(void *data, char *name) 1576static int backtrace_stack(void *data, char *name)
1577{ 1577{
1578 /* Don't bother with IRQ stacks for now */ 1578 /* Process all stacks: */
1579 return -1; 1579 return 0;
1580} 1580}
1581 1581
1582static void backtrace_address(void *data, unsigned long addr, int reliable) 1582static void backtrace_address(void *data, unsigned long addr, int reliable)
@@ -1594,6 +1594,8 @@ static const struct stacktrace_ops backtrace_ops = {
1594 .address = backtrace_address, 1594 .address = backtrace_address,
1595}; 1595};
1596 1596
1597#include "../dumpstack.h"
1598
1597static void 1599static void
1598perf_callchain_kernel(struct pt_regs *regs, struct perf_callchain_entry *entry) 1600perf_callchain_kernel(struct pt_regs *regs, struct perf_callchain_entry *entry)
1599{ 1601{
@@ -1601,26 +1603,20 @@ perf_callchain_kernel(struct pt_regs *regs, struct perf_callchain_entry *entry)
1601 char *stack; 1603 char *stack;
1602 int nr = entry->nr; 1604 int nr = entry->nr;
1603 1605
1604 callchain_store(entry, instruction_pointer(regs)); 1606 callchain_store(entry, regs->ip);
1605 1607
1606 stack = ((char *)regs + sizeof(struct pt_regs)); 1608 stack = ((char *)regs + sizeof(struct pt_regs));
1607#ifdef CONFIG_FRAME_POINTER 1609#ifdef CONFIG_FRAME_POINTER
1608 bp = frame_pointer(regs); 1610 get_bp(bp);
1609#else 1611#else
1610 bp = 0; 1612 bp = 0;
1611#endif 1613#endif
1612 1614
1613 dump_trace(NULL, regs, (void *)stack, bp, &backtrace_ops, entry); 1615 dump_trace(NULL, regs, (void *)&stack, bp, &backtrace_ops, entry);
1614 1616
1615 entry->kernel = entry->nr - nr; 1617 entry->kernel = entry->nr - nr;
1616} 1618}
1617 1619
1618
1619struct stack_frame {
1620 const void __user *next_fp;
1621 unsigned long return_address;
1622};
1623
1624static int copy_stack_frame(const void __user *fp, struct stack_frame *frame) 1620static int copy_stack_frame(const void __user *fp, struct stack_frame *frame)
1625{ 1621{
1626 int ret; 1622 int ret;
@@ -1652,7 +1648,7 @@ perf_callchain_user(struct pt_regs *regs, struct perf_callchain_entry *entry)
1652 callchain_store(entry, regs->ip); 1648 callchain_store(entry, regs->ip);
1653 1649
1654 while (entry->nr < MAX_STACK_DEPTH) { 1650 while (entry->nr < MAX_STACK_DEPTH) {
1655 frame.next_fp = NULL; 1651 frame.next_frame = NULL;
1656 frame.return_address = 0; 1652 frame.return_address = 0;
1657 1653
1658 if (!copy_stack_frame(fp, &frame)) 1654 if (!copy_stack_frame(fp, &frame))
@@ -1662,7 +1658,7 @@ perf_callchain_user(struct pt_regs *regs, struct perf_callchain_entry *entry)
1662 break; 1658 break;
1663 1659
1664 callchain_store(entry, frame.return_address); 1660 callchain_store(entry, frame.return_address);
1665 fp = frame.next_fp; 1661 fp = frame.next_frame;
1666 } 1662 }
1667 1663
1668 entry->user = entry->nr - nr; 1664 entry->user = entry->nr - nr;