Commit 59278bc8 authored by David S. Miller's avatar David S. Miller

[SPARC64]: Basic oprofile support.

parent 15aeae37
...@@ -1646,6 +1646,7 @@ config SOFT_WATCHDOG ...@@ -1646,6 +1646,7 @@ config SOFT_WATCHDOG
endmenu endmenu
source "arch/sparc64/oprofile/Kconfig"
menu "Kernel hacking" menu "Kernel hacking"
......
...@@ -68,6 +68,9 @@ core-$(CONFIG_SOLARIS_EMUL) += arch/sparc64/solaris/ ...@@ -68,6 +68,9 @@ core-$(CONFIG_SOLARIS_EMUL) += arch/sparc64/solaris/
core-y += arch/sparc64/math-emu/ core-y += arch/sparc64/math-emu/
libs-y += arch/sparc64/prom/ arch/sparc64/lib/ libs-y += arch/sparc64/prom/ arch/sparc64/lib/
# FIXME: is drivers- right?
drivers-$(CONFIG_OPROFILE) += arch/sparc64/oprofile/
makeboot =$(Q)$(MAKE) -f scripts/Makefile.build obj=arch/sparc64/boot $(1) makeboot =$(Q)$(MAKE) -f scripts/Makefile.build obj=arch/sparc64/boot $(1)
tftpboot.img vmlinux.aout: tftpboot.img vmlinux.aout:
......
...@@ -16,6 +16,7 @@ obj-y := process.o setup.o cpu.o idprom.o \ ...@@ -16,6 +16,7 @@ obj-y := process.o setup.o cpu.o idprom.o \
obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \ obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \
pci_psycho.o pci_sabre.o pci_schizo.o pci_psycho.o pci_sabre.o pci_schizo.o
obj-$(CONFIG_SMP) += smp.o trampoline.o obj-$(CONFIG_SMP) += smp.o trampoline.o
obj-$(CONFIG_PROFILING) += profile.o
obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o ioctl32.o obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o ioctl32.o
obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
obj-$(CONFIG_BINFMT_AOUT32) += binfmt_aout32.o obj-$(CONFIG_BINFMT_AOUT32) += binfmt_aout32.o
......
/* arch/sparc64/kernel/profile.c
*
* Almost entirely copied from ppc64 which is:
* (C) 2002 John Levon <levon@movementarian.org>
*/
#include <linux/profile.h>
#include <linux/spinlock.h>
#include <linux/notifier.h>
#include <asm/irq.h>
static struct notifier_block *profile_listeners;
static rwlock_t profile_lock = RW_LOCK_UNLOCKED;
int register_profile_notifier(struct notifier_block *nb)
{
int err;
write_lock_irq(&profile_lock);
err = notifier_chain_register(&profile_listeners, nb);
write_unlock_irq(&profile_lock);
return err;
}
int unregister_profile_notifier(struct notifier_block *nb)
{
int err;
write_lock_irq(&profile_lock);
err = notifier_chain_unregister(&profile_listeners, nb);
write_unlock_irq(&profile_lock);
return err;
}
void sparc64_profile_hook(struct pt_regs *regs)
{
read_lock(&profile_lock);
notifier_call_chain(&profile_listeners, 0, regs);
read_unlock(&profile_lock);
}
...@@ -926,7 +926,7 @@ void smp_promstop_others(void) ...@@ -926,7 +926,7 @@ void smp_promstop_others(void)
smp_cross_call(&xcall_promstop, 0, 0, 0); smp_cross_call(&xcall_promstop, 0, 0, 0);
} }
extern void sparc64_do_profile(unsigned long pc, unsigned long o7); extern void sparc64_do_profile(struct pt_regs *regs);
static unsigned long current_tick_offset; static unsigned long current_tick_offset;
...@@ -960,9 +960,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) ...@@ -960,9 +960,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
} }
do { do {
if (!user) sparc64_do_profile(regs);
sparc64_do_profile(regs->tpc,
regs->u_regs[UREG_RETPC]);
if (!--prof_counter(cpu)) { if (!--prof_counter(cpu)) {
if (cpu == boot_cpu_id) { if (cpu == boot_cpu_id) {
irq_enter(); irq_enter();
......
...@@ -373,3 +373,8 @@ EXPORT_SYMBOL(do_BUG); ...@@ -373,3 +373,8 @@ EXPORT_SYMBOL(do_BUG);
/* for ns8703 */ /* for ns8703 */
EXPORT_SYMBOL(ns87303_lock); EXPORT_SYMBOL(ns87303_lock);
#ifdef CONFIG_PROFILING
EXPORT_SYMBOL_GPL(register_profile_notifier);
EXPORT_SYMBOL_GPL(unregister_profile_notifier);
#endif
...@@ -84,9 +84,23 @@ static __inline__ void timer_check_rtc(void) ...@@ -84,9 +84,23 @@ static __inline__ void timer_check_rtc(void)
} }
} }
void sparc64_do_profile(unsigned long pc, unsigned long o7) void sparc64_do_profile(struct pt_regs *regs)
{ {
if (prof_buffer && current->pid) { unsigned long pc = regs->tpc;
unsigned long o7 = regs->u_regs[UREG_RETPC];
#ifdef CONFIG_PROFILING
extern void sparc64_profile_hook(struct pt_regs *);
sparc64_profile_hook(regs);
#endif
if (user_mode(regs))
return;
if (!prof_buffer)
return;
{
extern int _stext; extern int _stext;
extern int rwlock_impl_begin, rwlock_impl_end; extern int rwlock_impl_begin, rwlock_impl_end;
extern int atomic_impl_begin, atomic_impl_end; extern int atomic_impl_begin, atomic_impl_end;
...@@ -123,8 +137,7 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -123,8 +137,7 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
do { do {
#ifndef CONFIG_SMP #ifndef CONFIG_SMP
if ((regs->tstate & TSTATE_PRIV) != 0) sparc64_do_profile(regs);
sparc64_do_profile(regs->tpc, regs->u_regs[UREG_RETPC]);
#endif #endif
do_timer(regs); do_timer(regs);
......
menu "Profiling support"
depends on EXPERIMENTAL
config PROFILING
bool "Profiling support (EXPERIMENTAL)"
help
Say Y here to enable the extended profiling support mechanisms used
by profilers such as OProfile.
config OPROFILE
tristate "OProfile system profiling (EXPERIMENTAL)"
depends on PROFILING
help
OProfile is a profiling system capable of profiling the
whole system, include the kernel, kernel modules, libraries,
and applications.
If unsure, say N.
endmenu
obj-$(CONFIG_OPROFILE) += oprofile.o
DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
oprof.o cpu_buffer.o buffer_sync.o \
event_buffer.o oprofile_files.o \
oprofilefs.o oprofile_stats.o )
oprofile-y := $(DRIVER_OBJS) init.o timer_int.o
/**
* @file init.c
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author John Levon <levon@movementarian.org>
*/
#include <linux/kernel.h>
#include <linux/oprofile.h>
#include <linux/init.h>
extern void timer_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu);
int __init oprofile_arch_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
{
timer_init(ops, cpu);
return 0;
}
/**
* @file timer_int.c
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author John Levon <levon@movementarian.org>
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/notifier.h>
#include <linux/smp.h>
#include <linux/irq.h>
#include <linux/oprofile.h>
#include <asm/ptrace.h>
static int timer_notify(struct notifier_block * self, unsigned long val, void * data)
{
struct pt_regs * regs = (struct pt_regs *)data;
int cpu = smp_processor_id();
oprofile_add_sample(instruction_pointer(regs), 0, cpu);
return 0;
}
static struct notifier_block timer_notifier = {
.notifier_call = timer_notify,
};
static int timer_start(void)
{
return register_profile_notifier(&timer_notifier);
}
static void timer_stop(void)
{
unregister_profile_notifier(&timer_notifier);
}
static struct oprofile_operations timer_ops = {
.start = timer_start,
.stop = timer_stop
};
void __init timer_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
{
*ops = &timer_ops;
*cpu = OPROFILE_CPU_TIMER;
printk(KERN_INFO "oprofile: using timer interrupt.\n");
}
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/linkage.h> #include <linux/linkage.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/errno.h>
#include <asm/pil.h> #include <asm/pil.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
...@@ -156,4 +157,25 @@ static __inline__ unsigned long get_softint(void) ...@@ -156,4 +157,25 @@ static __inline__ unsigned long get_softint(void)
return retval; return retval;
} }
struct notifier_block;
#ifdef CONFIG_PROFILING
int register_profile_notifier(struct notifier_block *nb);
int unregister_profile_notifier(struct notifier_block *nb);
#else
static inline int register_profile_notifier(struct notifier_block *nb)
{
return -ENOSYS;
}
static inline int unregister_profile_notifier(struct notifier_block *nb)
{
return -ENOSYS;
}
#endif /* CONFIG_PROFILING */
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment