Skip to content

Commit

Permalink
sh: perf events: Preliminary callchain support.
Browse files Browse the repository at this point in the history
This implements preliminary support for perf callchains (at the moment
only the kernel side is implemented). The actual implementation itself is
just a simple wrapper around the unwinder API, which allows for callchain
generation with or without the dwarf unwinder.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
  • Loading branch information
Paul Mundt committed Nov 5, 2009
1 parent d1b261e commit 830fafe
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 1 deletion.
2 changes: 1 addition & 1 deletion arch/sh/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
obj-$(CONFIG_DUMP_CODE) += disassemble.o
obj-$(CONFIG_HIBERNATION) += swsusp.o
obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o
obj-$(CONFIG_PERF_EVENTS) += perf_event.o
obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_callchain.o

obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o

Expand Down
98 changes: 98 additions & 0 deletions arch/sh/kernel/perf_callchain.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Performance event callchain support - SuperH architecture code
*
* Copyright (C) 2009 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/perf_event.h>
#include <linux/percpu.h>
#include <asm/unwinder.h>
#include <asm/ptrace.h>

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

static void callchain_warning(void *data, char *msg)
{
}

static void
callchain_warning_symbol(void *data, char *msg, unsigned long symbol)
{
}

static int callchain_stack(void *data, char *name)
{
return 0;
}

static void callchain_address(void *data, unsigned long addr, int reliable)
{
struct perf_callchain_entry *entry = data;

if (reliable)
callchain_store(entry, addr);
}

static const struct stacktrace_ops callchain_ops = {
.warning = callchain_warning,
.warning_symbol = callchain_warning_symbol,
.stack = callchain_stack,
.address = callchain_address,
};

static void
perf_callchain_kernel(struct pt_regs *regs, struct perf_callchain_entry *entry)
{
callchain_store(entry, PERF_CONTEXT_KERNEL);
callchain_store(entry, regs->pc);

unwind_stack(NULL, regs, NULL, &callchain_ops, entry);
}

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 == 0)
return;

if (is_user && current->state != TASK_RUNNING)
return;

/*
* Only the kernel side is implemented for now.
*/
if (!is_user)
perf_callchain_kernel(regs, entry);
}

/*
* No need for separate IRQ and NMI entries.
*/
static DEFINE_PER_CPU(struct perf_callchain_entry, callchain);

struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
{
struct perf_callchain_entry *entry = &__get_cpu_var(callchain);

entry->nr = 0;

perf_do_callchain(regs, entry);

return entry;
}

0 comments on commit 830fafe

Please sign in to comment.