Commit 758d297b authored by Will Cohen's avatar Will Cohen Committed by David Mosberger

[PATCH] ia64: oprofile support

I have revised the oprofile patch for ia64 to provide just the basic
timer interrupt mechanism to avoid interferring with the perfmon 2.0
support. I have verified the oprofile ia64 patch applies cleanly and
build a working kernel with the 2.6.0-test4 kernel and the
linux-2.6.0-test4-ia64-030826.diff.bz2 patch.

More work is required to get oprofile to work with the perfmon 2.0.
However, the patch as it is currently implements should not cause
problems for the perfom 2.0 support.
parent ed8dff30
...@@ -589,6 +589,7 @@ source "lib/Kconfig" ...@@ -589,6 +589,7 @@ source "lib/Kconfig"
source "arch/ia64/hp/sim/Kconfig" source "arch/ia64/hp/sim/Kconfig"
source "arch/ia64/oprofile/Kconfig"
menu "Kernel hacking" menu "Kernel hacking"
......
...@@ -65,6 +65,7 @@ drivers-$(CONFIG_PCI) += arch/ia64/pci/ ...@@ -65,6 +65,7 @@ drivers-$(CONFIG_PCI) += arch/ia64/pci/
drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/ drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/
drivers-$(CONFIG_IA64_HP_ZX1) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ drivers-$(CONFIG_IA64_HP_ZX1) += arch/ia64/hp/common/ arch/ia64/hp/zx1/
drivers-$(CONFIG_IA64_GENERIC) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ arch/ia64/hp/sim/ drivers-$(CONFIG_IA64_GENERIC) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ arch/ia64/hp/sim/
drivers-$(CONFIG_OPROFILE) += arch/ia64/oprofile/
boot := arch/ia64/hp/sim/boot boot := arch/ia64/hp/sim/boot
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/time.h> #include <linux/time.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/efi.h> #include <linux/efi.h>
#include <linux/profile.h>
#include <linux/timex.h> #include <linux/timex.h>
#include <asm/delay.h> #include <asm/delay.h>
...@@ -38,29 +39,6 @@ unsigned long last_cli_ip; ...@@ -38,29 +39,6 @@ unsigned long last_cli_ip;
#endif #endif
static void
do_profile (unsigned long ip)
{
extern cpumask_t prof_cpu_mask;
if (!prof_buffer)
return;
if (!cpu_isset(smp_processor_id(), prof_cpu_mask))
return;
ip -= (unsigned long) _stext;
ip >>= prof_shift;
/*
* Don't ignore out-of-bounds IP values silently, put them into the last
* histogram slot, so if present, they will show up as a sharp peak.
*/
if (ip > prof_len - 1)
ip = prof_len - 1;
atomic_inc((atomic_t *) &prof_buffer[ip]);
}
static void static void
itc_reset (void) itc_reset (void)
{ {
...@@ -199,6 +177,52 @@ do_gettimeofday (struct timeval *tv) ...@@ -199,6 +177,52 @@ do_gettimeofday (struct timeval *tv)
tv->tv_usec = usec; tv->tv_usec = usec;
} }
/*
* The profiling function is SMP safe. (nothing can mess
* around with "current", and the profiling counters are
* updated with atomic operations). This is especially
* useful with a profiling multiplier != 1
*/
static inline void
ia64_do_profile (struct pt_regs * regs)
{
unsigned long ip, slot;
extern unsigned long prof_cpu_mask;
profile_hook(regs);
if (user_mode(regs))
return;
if (!prof_buffer)
return;
ip = instruction_pointer(regs);
/* Conserve space in histogram by encoding slot bits in address
* bits 2 and 3 rather than bits 0 and 1.
*/
slot = ip & 3;
ip = (ip & ~3UL) + 4*slot;
/*
* Only measure the CPUs specified by /proc/irq/prof_cpu_mask.
* (default is all CPUs.)
*/
if (!cpu_isset(smp_processor_id(), prof_cpu_mask))
return;
ip -= (unsigned long) &_stext;
ip >>= prof_shift;
/*
* Don't ignore out-of-bounds IP values silently,
* put them into the last histogram slot, so if
* present, they will show up as a sharp peak.
*/
if (ip > prof_len-1)
ip = prof_len-1;
atomic_inc((atomic_t *)&prof_buffer[ip]);
}
static irqreturn_t static irqreturn_t
timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
{ {
...@@ -210,14 +234,9 @@ timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) ...@@ -210,14 +234,9 @@ timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
printk(KERN_ERR "Oops: timer tick before it's due (itc=%lx,itm=%lx)\n", printk(KERN_ERR "Oops: timer tick before it's due (itc=%lx,itm=%lx)\n",
ia64_get_itc(), new_itm); ia64_get_itc(), new_itm);
ia64_do_profile(regs);
while (1) { while (1) {
/*
* Do kernel PC profiling here. We multiply the instruction number by
* four so that we can use a prof_shift of 2 to get instruction-level
* instead of just bundle-level accuracy.
*/
if (!user_mode(regs))
do_profile(regs->cr_iip + 4*ia64_psr(regs)->ri);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
smp_do_timer(regs); smp_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 \
timer_int.o )
oprofile-y := $(DRIVER_OBJS) init.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>
#include <linux/errno.h>
extern void timer_init(struct oprofile_operations ** ops);
int __init oprofile_arch_init(struct oprofile_operations ** ops)
{
return -ENODEV;
}
void oprofile_arch_exit(void)
{
}
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/profile.h>
#include <asm/machvec.h> #include <asm/machvec.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
......
...@@ -223,6 +223,12 @@ struct switch_stack { ...@@ -223,6 +223,12 @@ struct switch_stack {
}; };
#ifdef __KERNEL__ #ifdef __KERNEL__
/*
* We use the ia64_psr(regs)->ri to determine which of the three
* instructions in bundle (16 bytes) took the sample. Generate
* the canonical representation by adding to instruction pointer.
*/
# define instruction_pointer(regs) ((regs)->cr_iip + ia64_psr(regs)->ri)
/* given a pointer to a task_struct, return the user's pt_regs */ /* given a pointer to a task_struct, return the user's pt_regs */
# define ia64_task_regs(t) (((struct pt_regs *) ((char *) (t) + IA64_STK_OFFSET)) - 1) # define ia64_task_regs(t) (((struct pt_regs *) ((char *) (t) + IA64_STK_OFFSET)) - 1)
# define ia64_psr(regs) ((struct ia64_psr *) &(regs)->cr_ipsr) # define ia64_psr(regs) ((struct ia64_psr *) &(regs)->cr_ipsr)
......
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