Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sh: perf events: Preliminary callchain support.

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>

+99 -1
+1 -1
arch/sh/kernel/Makefile
··· 39 39 obj-$(CONFIG_DUMP_CODE) += disassemble.o 40 40 obj-$(CONFIG_HIBERNATION) += swsusp.o 41 41 obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o 42 - obj-$(CONFIG_PERF_EVENTS) += perf_event.o 42 + obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_callchain.o 43 43 44 44 obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o 45 45
+98
arch/sh/kernel/perf_callchain.c
··· 1 + /* 2 + * Performance event callchain support - SuperH architecture code 3 + * 4 + * Copyright (C) 2009 Paul Mundt 5 + * 6 + * This file is subject to the terms and conditions of the GNU General Public 7 + * License. See the file "COPYING" in the main directory of this archive 8 + * for more details. 9 + */ 10 + #include <linux/kernel.h> 11 + #include <linux/sched.h> 12 + #include <linux/perf_event.h> 13 + #include <linux/percpu.h> 14 + #include <asm/unwinder.h> 15 + #include <asm/ptrace.h> 16 + 17 + static inline void callchain_store(struct perf_callchain_entry *entry, u64 ip) 18 + { 19 + if (entry->nr < PERF_MAX_STACK_DEPTH) 20 + entry->ip[entry->nr++] = ip; 21 + } 22 + 23 + static void callchain_warning(void *data, char *msg) 24 + { 25 + } 26 + 27 + static void 28 + callchain_warning_symbol(void *data, char *msg, unsigned long symbol) 29 + { 30 + } 31 + 32 + static int callchain_stack(void *data, char *name) 33 + { 34 + return 0; 35 + } 36 + 37 + static void callchain_address(void *data, unsigned long addr, int reliable) 38 + { 39 + struct perf_callchain_entry *entry = data; 40 + 41 + if (reliable) 42 + callchain_store(entry, addr); 43 + } 44 + 45 + static const struct stacktrace_ops callchain_ops = { 46 + .warning = callchain_warning, 47 + .warning_symbol = callchain_warning_symbol, 48 + .stack = callchain_stack, 49 + .address = callchain_address, 50 + }; 51 + 52 + static void 53 + perf_callchain_kernel(struct pt_regs *regs, struct perf_callchain_entry *entry) 54 + { 55 + callchain_store(entry, PERF_CONTEXT_KERNEL); 56 + callchain_store(entry, regs->pc); 57 + 58 + unwind_stack(NULL, regs, NULL, &callchain_ops, entry); 59 + } 60 + 61 + static void 62 + perf_do_callchain(struct pt_regs *regs, struct perf_callchain_entry *entry) 63 + { 64 + int is_user; 65 + 66 + if (!regs) 67 + return; 68 + 69 + is_user = user_mode(regs); 70 + 71 + if (!current || current->pid == 0) 72 + return; 73 + 74 + if (is_user && current->state != TASK_RUNNING) 75 + return; 76 + 77 + /* 78 + * Only the kernel side is implemented for now. 79 + */ 80 + if (!is_user) 81 + perf_callchain_kernel(regs, entry); 82 + } 83 + 84 + /* 85 + * No need for separate IRQ and NMI entries. 86 + */ 87 + static DEFINE_PER_CPU(struct perf_callchain_entry, callchain); 88 + 89 + struct perf_callchain_entry *perf_callchain(struct pt_regs *regs) 90 + { 91 + struct perf_callchain_entry *entry = &__get_cpu_var(callchain); 92 + 93 + entry->nr = 0; 94 + 95 + perf_do_callchain(regs, entry); 96 + 97 + return entry; 98 + }