MIPS, Perf-events: Work with the new callchain interface [Linux 2.6.38]

This Linux kernel change "MIPS, Perf-events: Work with the new callchain interface" is included in the Linux 2.6.38 release. This change is authored by Deng-Cheng Zhu <dengcheng.zhu [at] gmail.com> on Fri Jan 21 16:19:20 2011 +0800. The commit for this change in Linux stable tree is 98f92f2 (patch).

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>

There are 63 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 arch/mips/kernel/perf_event.c | 63 +++++--------------------------------------
 1 file changed, 6 insertions(+), 57 deletions(-)

diff --git a/arch/mips/kernel/perf_event.c b/arch/mips/kernel/perf_event.c
index 3d557611..8f7d2f8 100644
--- a/arch/mips/kernel/perf_event.c
+++ b/arch/mips/kernel/perf_event.c
@@ -534,21 +534,13 @@ static int validate_group(struct perf_event *event)
 #include "perf_event_mipsxx.c"

 /* Callchain handling code. */
-static inline void
-callchain_store(struct perf_callchain_entry *entry,
-       u64 ip)
-{
-   if (entry->nr < PERF_MAX_STACK_DEPTH)
-       entry->ip[entry->nr++] = ip;
-}

 /*
  * Leave userspace callchain empty for now. When we find a way to trace
  * the user stack callchains, we add here.
  */
-static void
-perf_callchain_user(struct pt_regs *regs,
-           struct perf_callchain_entry *entry)
+void perf_callchain_user(struct perf_callchain_entry *entry,
+           struct pt_regs *regs)
 {
 }

@@ -561,23 +553,21 @@ static void save_raw_perf_callchain(struct perf_callchain_entry *entry,
    while (!kstack_end(sp)) {
        addr = *sp++;
        if (__kernel_text_address(addr)) {
-           callchain_store(entry, addr);
+           perf_callchain_store(entry, addr);
            if (entry->nr >= PERF_MAX_STACK_DEPTH)
                break;
        }
    }
 }

-static void
-perf_callchain_kernel(struct pt_regs *regs,
-             struct perf_callchain_entry *entry)
+void perf_callchain_kernel(struct perf_callchain_entry *entry,
+             struct pt_regs *regs)
 {
    unsigned long sp = regs->regs[29];
 #ifdef CONFIG_KALLSYMS
    unsigned long ra = regs->regs[31];
    unsigned long pc = regs->cp0_epc;

-   callchain_store(entry, PERF_CONTEXT_KERNEL);
    if (raw_show_trace || !__kernel_text_address(pc)) {
        unsigned long stack_page =
            (unsigned long)task_stack_page(current);
@@ -587,53 +577,12 @@ static void save_raw_perf_callchain(struct perf_callchain_entry *entry,
        return;
    }
    do {
-       callchain_store(entry, pc);
+       perf_callchain_store(entry, pc);
        if (entry->nr >= PERF_MAX_STACK_DEPTH)
            break;
        pc = unwind_stack(current, &sp, pc, &ra);
    } while (pc);
 #else
-   callchain_store(entry, PERF_CONTEXT_KERNEL);
    save_raw_perf_callchain(entry, sp);
 #endif
 }
-
-static void
-perf_do_callchain(struct pt_regs *regs,
-         struct perf_callchain_entry *entry)
-{
-   int is_user;
-
-   if (!regs)
-       return;
-
-   is_user = user_mode(regs);
-
-   if (!current || !current->pid)
-       return;
-
-   if (is_user && current->state != TASK_RUNNING)
-       return;
-
-   if (!is_user) {
-       perf_callchain_kernel(regs, entry);
-       if (current->mm)
-           regs = task_pt_regs(current);
-       else
-           regs = NULL;
-   }
-   if (regs)
-       perf_callchain_user(regs, entry);
-}
-
-static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry);
-
-struct perf_callchain_entry *
-perf_callchain(struct pt_regs *regs)
-{
-   struct perf_callchain_entry *entry = &__get_cpu_var(pmc_irq_entry);
-
-   entry->nr = 0;
-   perf_do_callchain(regs, entry);
-   return entry;
-}

Leave a Reply

Your email address will not be published. Required fields are marked *