aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDeng-Cheng Zhu <dengcheng.zhu@gmail.com>2011-01-21 03:19:20 -0500
committerRalf Baechle <ralf@linux-mips.org>2011-03-14 16:07:27 -0400
commit98f92f2f9e2fd959157b1d52f7ae160683812740 (patch)
tree7da1f14de06c1b052cb3c3057fcf5fa6b9078fed
parentc049b6a5f2d8ca16094a4f2a6d8ad39f888a551a (diff)
MIPS, Perf-events: Work with the new callchain interface
This is the MIPS part of the following commits by Frederic Weisbecker: - f72c1a931e311bb7780fee19e41a89ac42cab50e perf: Factorize callchain context handling Store the kernel and user contexts from the generic layer instead of archs, this gathers some repetitive code. - 56962b4449af34070bb1994621ef4f0265eed4d8 perf: Generalize some arch callchain code - Most archs use one callchain buffer per cpu, except x86 that needs to deal with NMIs. Provide a default perf_callchain_buffer() implementation that x86 overrides. - Centralize all the kernel/user regs handling and invoke new arch handlers from there: perf_callchain_user() / perf_callchain_kernel() That avoid all the user_mode(), current->mm checks and so... - Invert some parameters in perf_callchain_*() helpers: entry to the left, regs to the right, following the traditional (dst, src). - 70791ce9ba68a5921c9905ef05d23f62a90bc10c perf: Generalize callchain_store() callchain_store() is the same on every archs, inline it in perf_event.h and rename it to perf_callchain_store() to avoid any collision. This removes repetitive code. - c1a65932fd7216fdc9a0db8bbffe1d47842f862c perf: Drop unappropriate tests on arch callchains Drop the TASK_RUNNING test on user tasks for callchains as this check doesn't seem to make any sense. Also remove the tests for !current that is not supposed to happen and current->pid as this should be handled at the generic level, with exclude_idle attribute. Reported-by: Wu Zhangjin <wuzhangjin@gmail.com> Acked-by: Frederic Weisbecker <fweisbec@gmail.com> Acked-by: David Daney <ddaney@caviumnetworks.com> Signed-off-by: Deng-Cheng Zhu <dengcheng.zhu@gmail.com> To: a.p.zijlstra@chello.nl To: will.deacon@arm.com Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: paulus@samba.org Cc: mingo@elte.hu Cc: acme@redhat.com Cc: dengcheng.zhu@gmail.com Cc: matt@console-pimps.org Cc: sshtylyov@mvista.com Patchwork: http://patchwork.linux-mips.org/patch/2014/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/kernel/perf_event.c63
1 files changed, 6 insertions, 57 deletions
diff --git a/arch/mips/kernel/perf_event.c b/arch/mips/kernel/perf_event.c
index 3d55761146e5..8f7d2f84d095 100644
--- a/arch/mips/kernel/perf_event.c
+++ b/arch/mips/kernel/perf_event.c
@@ -534,21 +534,13 @@ handle_associated_event(struct cpu_hw_events *cpuc,
534#include "perf_event_mipsxx.c" 534#include "perf_event_mipsxx.c"
535 535
536/* Callchain handling code. */ 536/* Callchain handling code. */
537static inline void
538callchain_store(struct perf_callchain_entry *entry,
539 u64 ip)
540{
541 if (entry->nr < PERF_MAX_STACK_DEPTH)
542 entry->ip[entry->nr++] = ip;
543}
544 537
545/* 538/*
546 * Leave userspace callchain empty for now. When we find a way to trace 539 * Leave userspace callchain empty for now. When we find a way to trace
547 * the user stack callchains, we add here. 540 * the user stack callchains, we add here.
548 */ 541 */
549static void 542void perf_callchain_user(struct perf_callchain_entry *entry,
550perf_callchain_user(struct pt_regs *regs, 543 struct pt_regs *regs)
551 struct perf_callchain_entry *entry)
552{ 544{
553} 545}
554 546
@@ -561,23 +553,21 @@ static void save_raw_perf_callchain(struct perf_callchain_entry *entry,
561 while (!kstack_end(sp)) { 553 while (!kstack_end(sp)) {
562 addr = *sp++; 554 addr = *sp++;
563 if (__kernel_text_address(addr)) { 555 if (__kernel_text_address(addr)) {
564 callchain_store(entry, addr); 556 perf_callchain_store(entry, addr);
565 if (entry->nr >= PERF_MAX_STACK_DEPTH) 557 if (entry->nr >= PERF_MAX_STACK_DEPTH)
566 break; 558 break;
567 } 559 }
568 } 560 }
569} 561}
570 562
571static void 563void perf_callchain_kernel(struct perf_callchain_entry *entry,
572perf_callchain_kernel(struct pt_regs *regs, 564 struct pt_regs *regs)
573 struct perf_callchain_entry *entry)
574{ 565{
575 unsigned long sp = regs->regs[29]; 566 unsigned long sp = regs->regs[29];
576#ifdef CONFIG_KALLSYMS 567#ifdef CONFIG_KALLSYMS
577 unsigned long ra = regs->regs[31]; 568 unsigned long ra = regs->regs[31];
578 unsigned long pc = regs->cp0_epc; 569 unsigned long pc = regs->cp0_epc;
579 570
580 callchain_store(entry, PERF_CONTEXT_KERNEL);
581 if (raw_show_trace || !__kernel_text_address(pc)) { 571 if (raw_show_trace || !__kernel_text_address(pc)) {
582 unsigned long stack_page = 572 unsigned long stack_page =
583 (unsigned long)task_stack_page(current); 573 (unsigned long)task_stack_page(current);
@@ -587,53 +577,12 @@ perf_callchain_kernel(struct pt_regs *regs,
587 return; 577 return;
588 } 578 }
589 do { 579 do {
590 callchain_store(entry, pc); 580 perf_callchain_store(entry, pc);
591 if (entry->nr >= PERF_MAX_STACK_DEPTH) 581 if (entry->nr >= PERF_MAX_STACK_DEPTH)
592 break; 582 break;
593 pc = unwind_stack(current, &sp, pc, &ra); 583 pc = unwind_stack(current, &sp, pc, &ra);
594 } while (pc); 584 } while (pc);
595#else 585#else
596 callchain_store(entry, PERF_CONTEXT_KERNEL);
597 save_raw_perf_callchain(entry, sp); 586 save_raw_perf_callchain(entry, sp);
598#endif 587#endif
599} 588}
600
601static void
602perf_do_callchain(struct pt_regs *regs,
603 struct perf_callchain_entry *entry)
604{
605 int is_user;
606
607 if (!regs)
608 return;
609
610 is_user = user_mode(regs);
611
612 if (!current || !current->pid)
613 return;
614
615 if (is_user && current->state != TASK_RUNNING)
616 return;
617
618 if (!is_user) {
619 perf_callchain_kernel(regs, entry);
620 if (current->mm)
621 regs = task_pt_regs(current);
622 else
623 regs = NULL;
624 }
625 if (regs)
626 perf_callchain_user(regs, entry);
627}
628
629static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry);
630
631struct perf_callchain_entry *
632perf_callchain(struct pt_regs *regs)
633{
634 struct perf_callchain_entry *entry = &__get_cpu_var(pmc_irq_entry);
635
636 entry->nr = 0;
637 perf_do_callchain(regs, entry);
638 return entry;
639}