diff options
author | Deng-Cheng Zhu <dengcheng.zhu@gmail.com> | 2011-01-21 03:19:20 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2011-03-14 16:07:27 -0400 |
commit | 98f92f2f9e2fd959157b1d52f7ae160683812740 (patch) | |
tree | 7da1f14de06c1b052cb3c3057fcf5fa6b9078fed | |
parent | c049b6a5f2d8ca16094a4f2a6d8ad39f888a551a (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.c | 63 |
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. */ |
537 | static inline void | ||
538 | callchain_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 | */ |
549 | static void | 542 | void perf_callchain_user(struct perf_callchain_entry *entry, |
550 | perf_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 | ||
571 | static void | 563 | void perf_callchain_kernel(struct perf_callchain_entry *entry, |
572 | perf_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 | |||
601 | static void | ||
602 | perf_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 | |||
629 | static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry); | ||
630 | |||
631 | struct perf_callchain_entry * | ||
632 | perf_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 | } | ||