Commit f3549b15 authored by William Lee Irwin III's avatar William Lee Irwin III Committed by Linus Torvalds

[PATCH] introduce profile_pc()

The program counter calculation from pt_regs is the only portion of profile
accounting that differs across various architectures.  This is usually
instruction_pointer(regs), but to handle the few arches where it isn't,
introduce profile_pc().
Signed-off-by: default avatarWilliam Irwin <wli@holomorphy.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 423284ee
...@@ -195,7 +195,7 @@ EXPORT_SYMBOL(do_gettimeofday); ...@@ -195,7 +195,7 @@ EXPORT_SYMBOL(do_gettimeofday);
static inline void static inline void
ia64_do_profile (struct pt_regs * regs) ia64_do_profile (struct pt_regs * regs)
{ {
unsigned long ip, slot; unsigned long ip;
profile_hook(regs); profile_hook(regs);
...@@ -205,12 +205,10 @@ ia64_do_profile (struct pt_regs * regs) ...@@ -205,12 +205,10 @@ ia64_do_profile (struct pt_regs * regs)
if (!prof_buffer) if (!prof_buffer)
return; return;
ip = instruction_pointer(regs);
/* Conserve space in histogram by encoding slot bits in address /* Conserve space in histogram by encoding slot bits in address
* bits 2 and 3 rather than bits 0 and 1. * bits 2 and 3 rather than bits 0 and 1.
*/ */
slot = ip & 3; ip = profile_pc(regs);
ip = (ip & ~3UL) + 4*slot;
/* /*
* Only measure the CPUs specified by /proc/irq/prof_cpu_mask. * Only measure the CPUs specified by /proc/irq/prof_cpu_mask.
......
...@@ -262,9 +262,6 @@ static inline void sh_do_profile(unsigned long pc) ...@@ -262,9 +262,6 @@ static inline void sh_do_profile(unsigned long pc)
if (!prof_buffer || !current->pid) if (!prof_buffer || !current->pid)
return; return;
if (pc >= 0xa0000000UL && pc < 0xc0000000UL)
pc -= 0x20000000;
pc -= (unsigned long)&_stext; pc -= (unsigned long)&_stext;
pc >>= prof_shift; pc >>= prof_shift;
...@@ -288,7 +285,7 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *reg ...@@ -288,7 +285,7 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *reg
do_timer(regs); do_timer(regs);
if (!user_mode(regs)) if (!user_mode(regs))
sh_do_profile(regs->pc); sh_do_profile(profile_pc(regs));
#ifdef CONFIG_HEARTBEAT #ifdef CONFIG_HEARTBEAT
if (sh_mv.mv_heartbeat != NULL) if (sh_mv.mv_heartbeat != NULL)
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/profile.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/atomic.h> #include <asm/atomic.h>
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/profile.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
......
...@@ -79,6 +79,26 @@ struct intersil *intersil_clock; ...@@ -79,6 +79,26 @@ struct intersil *intersil_clock;
#endif #endif
unsigned long profile_pc(struct pt_regs *regs)
{
extern int __copy_user_begin, __copy_user_end;
extern int __atomic_begin, __atomic_end;
extern int __bzero_begin, __bzero_end;
extern int __bitops_begin, __bitops_end;
unsigned long pc = regs->pc;
if ((pc >= (unsigned long) &__copy_user_begin &&
pc < (unsigned long) &__copy_user_end) ||
(pc >= (unsigned long) &__atomic_begin &&
pc < (unsigned long) &__atomic_end) ||
(pc >= (unsigned long) &__bzero_begin &&
pc < (unsigned long) &__bzero_end) ||
(pc >= (unsigned long) &__bitops_begin &&
pc < (unsigned long) &__bitops_end))
pc = regs->u_regs[UREG_RETPC];
return pc;
}
static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED; static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
/* 32-bit Sparc specific profiling function. */ /* 32-bit Sparc specific profiling function. */
...@@ -86,20 +106,6 @@ void sparc_do_profile(unsigned long pc, unsigned long o7) ...@@ -86,20 +106,6 @@ void sparc_do_profile(unsigned long pc, unsigned long o7)
{ {
if(prof_buffer && current->pid) { if(prof_buffer && current->pid) {
extern int _stext; extern int _stext;
extern int __copy_user_begin, __copy_user_end;
extern int __atomic_begin, __atomic_end;
extern int __bzero_begin, __bzero_end;
extern int __bitops_begin, __bitops_end;
if ((pc >= (unsigned long) &__copy_user_begin &&
pc < (unsigned long) &__copy_user_end) ||
(pc >= (unsigned long) &__atomic_begin &&
pc < (unsigned long) &__atomic_end) ||
(pc >= (unsigned long) &__bzero_begin &&
pc < (unsigned long) &__bzero_end) ||
(pc >= (unsigned long) &__bitops_begin &&
pc < (unsigned long) &__bitops_end))
pc = o7;
pc -= (unsigned long) &_stext; pc -= (unsigned long) &_stext;
pc >>= prof_shift; pc >>= prof_shift;
...@@ -130,7 +136,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -130,7 +136,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
#ifndef CONFIG_SMP #ifndef CONFIG_SMP
if(!user_mode(regs)) if(!user_mode(regs))
sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]); sparc_do_profile(profile_pc(regs));
#endif #endif
/* Protect counter clear so that do_gettimeoffset works */ /* Protect counter clear so that do_gettimeoffset works */
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/cache.h> #include <linux/cache.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/profile.h>
#include <asm/head.h> #include <asm/head.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/profile.h>
#include <asm/oplib.h> #include <asm/oplib.h>
#include <asm/mostek.h> #include <asm/mostek.h>
...@@ -453,14 +454,8 @@ void sparc64_do_profile(struct pt_regs *regs) ...@@ -453,14 +454,8 @@ void sparc64_do_profile(struct pt_regs *regs)
if (!prof_buffer) if (!prof_buffer)
return; return;
pc = regs->tpc; pc = (profile_pc(regs) - (unsigned long)_stext) >> prof_shift;
atomic_inc((atomic_t *)&prof_buffer[min(pc, prof_len-1)]);
pc -= (unsigned long) _stext;
pc >>= prof_shift;
if(pc >= prof_len)
pc = prof_len - 1;
atomic_inc((atomic_t *)&prof_buffer[pc]);
} }
static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
......
...@@ -69,6 +69,7 @@ struct switch_stack { ...@@ -69,6 +69,7 @@ struct switch_stack {
#ifdef __KERNEL__ #ifdef __KERNEL__
#define user_mode(regs) (((regs)->ps & 8) != 0) #define user_mode(regs) (((regs)->ps & 8) != 0)
#define instruction_pointer(regs) ((regs)->pc) #define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *); extern void show_regs(struct pt_regs *);
#define alpha_task_regs(task) \ #define alpha_task_regs(task) \
......
...@@ -130,6 +130,7 @@ static inline int valid_user_regs(struct pt_regs *regs) ...@@ -130,6 +130,7 @@ static inline int valid_user_regs(struct pt_regs *regs)
#define instruction_pointer(regs) \ #define instruction_pointer(regs) \
(pc_pointer((regs)->ARM_pc)) (pc_pointer((regs)->ARM_pc))
#define profile_pc(regs) instruction_pointer(regs)
#ifdef __KERNEL__ #ifdef __KERNEL__
extern void show_regs(struct pt_regs *); extern void show_regs(struct pt_regs *);
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#define pc_pointer(v) ((v) & ~PCMASK) /* convert v to pc type address */ #define pc_pointer(v) ((v) & ~PCMASK) /* convert v to pc type address */
#define instruction_pointer(regs) (pc_pointer((regs)->ARM_pc)) /* get pc */ #define instruction_pointer(regs) (pc_pointer((regs)->ARM_pc)) /* get pc */
#define profile_pc(regs) instruction_pointer(regs)
/* this struct defines the way the registers are stored on the /* this struct defines the way the registers are stored on the
stack during a system call. */ stack during a system call. */
......
...@@ -109,6 +109,7 @@ struct switch_stack { ...@@ -109,6 +109,7 @@ struct switch_stack {
/* bit 8 is user-mode flag */ /* bit 8 is user-mode flag */
#define user_mode(regs) (((regs)->dccr & 0x100) != 0) #define user_mode(regs) (((regs)->dccr & 0x100) != 0)
#define instruction_pointer(regs) ((regs)->irp) #define instruction_pointer(regs) ((regs)->irp)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *); extern void show_regs(struct pt_regs *);
#endif #endif
...@@ -57,6 +57,7 @@ struct pt_regs { ...@@ -57,6 +57,7 @@ struct pt_regs {
#define user_mode(regs) (!((regs)->ccr & PS_S)) #define user_mode(regs) (!((regs)->ccr & PS_S))
#define instruction_pointer(regs) ((regs)->pc) #define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *); extern void show_regs(struct pt_regs *);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
......
...@@ -57,6 +57,7 @@ struct pt_regs { ...@@ -57,6 +57,7 @@ struct pt_regs {
#ifdef __KERNEL__ #ifdef __KERNEL__
#define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs)) #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs))
#define instruction_pointer(regs) ((regs)->eip) #define instruction_pointer(regs) ((regs)->eip)
#define profile_pc(regs) instruction_pointer(regs)
#endif #endif
#endif #endif
...@@ -229,6 +229,15 @@ struct switch_stack { ...@@ -229,6 +229,15 @@ struct switch_stack {
* the canonical representation by adding to instruction pointer. * the canonical representation by adding to instruction pointer.
*/ */
# define instruction_pointer(regs) ((regs)->cr_iip + ia64_psr(regs)->ri) # define instruction_pointer(regs) ((regs)->cr_iip + ia64_psr(regs)->ri)
/* Conserve space in histogram by encoding slot bits in address
* bits 2 and 3 rather than bits 0 and 1.
*/
#define profile_pc(regs) \
({ \
unsigned long __ip = instruction_pointer(regs); \
(__ip & ~3UL) + ((__ip & 3UL) << 2); \
})
/* 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)
......
...@@ -73,6 +73,7 @@ struct switch_stack { ...@@ -73,6 +73,7 @@ struct switch_stack {
#define user_mode(regs) (!((regs)->sr & PS_S)) #define user_mode(regs) (!((regs)->sr & PS_S))
#define instruction_pointer(regs) ((regs)->pc) #define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *); extern void show_regs(struct pt_regs *);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
......
...@@ -84,6 +84,7 @@ struct switch_stack { ...@@ -84,6 +84,7 @@ struct switch_stack {
#define user_mode(regs) (!((regs)->sr & PS_S)) #define user_mode(regs) (!((regs)->sr & PS_S))
#define instruction_pointer(regs) ((regs)->pc) #define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *); extern void show_regs(struct pt_regs *);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
......
...@@ -66,6 +66,7 @@ struct pt_regs { ...@@ -66,6 +66,7 @@ struct pt_regs {
#define user_mode(regs) (((regs)->cp0_status & KU_MASK) == KU_USER) #define user_mode(regs) (((regs)->cp0_status & KU_MASK) == KU_USER)
#define instruction_pointer(regs) ((regs)->cp0_epc) #define instruction_pointer(regs) ((regs)->cp0_epc)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *); extern void show_regs(struct pt_regs *);
......
...@@ -48,6 +48,7 @@ struct pt_regs { ...@@ -48,6 +48,7 @@ struct pt_regs {
/* XXX should we use iaoq[1] or iaoq[0] ? */ /* XXX should we use iaoq[1] or iaoq[0] ? */
#define user_mode(regs) (((regs)->iaoq[0] & 3) ? 1 : 0) #define user_mode(regs) (((regs)->iaoq[0] & 3) ? 1 : 0)
#define instruction_pointer(regs) ((regs)->iaoq[0] & ~3) #define instruction_pointer(regs) ((regs)->iaoq[0] & ~3)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *); extern void show_regs(struct pt_regs *);
#endif #endif
......
...@@ -47,6 +47,7 @@ struct pt_regs { ...@@ -47,6 +47,7 @@ struct pt_regs {
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#define instruction_pointer(regs) ((regs)->nip) #define instruction_pointer(regs) ((regs)->nip)
#define profile_pc(regs) instruction_pointer(regs)
#define user_mode(regs) (((regs)->msr & MSR_PR) != 0) #define user_mode(regs) (((regs)->msr & MSR_PR) != 0)
#define force_successful_syscall_return() \ #define force_successful_syscall_return() \
......
...@@ -69,6 +69,7 @@ struct pt_regs32 { ...@@ -69,6 +69,7 @@ struct pt_regs32 {
#define __SIGNAL_FRAMESIZE32 64 #define __SIGNAL_FRAMESIZE32 64
#define instruction_pointer(regs) ((regs)->nip) #define instruction_pointer(regs) ((regs)->nip)
#define profile_pc(regs) instruction_pointer(regs)
#define user_mode(regs) ((((regs)->msr) >> MSR_PR_LG) & 0x1) #define user_mode(regs) ((((regs)->msr) >> MSR_PR_LG) & 0x1)
#define force_successful_syscall_return() \ #define force_successful_syscall_return() \
......
...@@ -466,6 +466,7 @@ struct user_regs_struct ...@@ -466,6 +466,7 @@ struct user_regs_struct
#ifdef __KERNEL__ #ifdef __KERNEL__
#define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0) #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
#define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN) #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs * regs); extern void show_regs(struct pt_regs * regs);
#endif #endif
......
...@@ -90,6 +90,15 @@ struct pt_dspregs { ...@@ -90,6 +90,15 @@ struct pt_dspregs {
#define user_mode(regs) (((regs)->sr & 0x40000000)==0) #define user_mode(regs) (((regs)->sr & 0x40000000)==0)
#define instruction_pointer(regs) ((regs)->pc) #define instruction_pointer(regs) ((regs)->pc)
extern void show_regs(struct pt_regs *); extern void show_regs(struct pt_regs *);
static inline unsigned long profile_pc(struct pt_regs *regs)
{
unsigned long pc = instruction_pointer(regs);
if (pc >= 0xa0000000UL && pc < 0xc0000000UL)
pc -= 0x20000000;
return pc;
}
#endif #endif
#endif /* __ASM_SH_PTRACE_H */ #endif /* __ASM_SH_PTRACE_H */
...@@ -28,6 +28,7 @@ struct pt_regs { ...@@ -28,6 +28,7 @@ struct pt_regs {
#ifdef __KERNEL__ #ifdef __KERNEL__
#define user_mode(regs) (((regs)->sr & 0x40000000)==0) #define user_mode(regs) (((regs)->sr & 0x40000000)==0)
#define instruction_pointer(regs) ((regs)->pc) #define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *); extern void show_regs(struct pt_regs *);
#endif #endif
......
...@@ -62,6 +62,7 @@ struct sparc_stackf { ...@@ -62,6 +62,7 @@ struct sparc_stackf {
#ifdef __KERNEL__ #ifdef __KERNEL__
#define user_mode(regs) (!((regs)->psr & PSR_PS)) #define user_mode(regs) (!((regs)->psr & PSR_PS))
#define instruction_pointer(regs) ((regs)->pc) #define instruction_pointer(regs) ((regs)->pc)
unsigned long profile_pc(struct pt_regs *);
extern void show_regs(struct pt_regs *); extern void show_regs(struct pt_regs *);
#endif #endif
......
...@@ -98,6 +98,7 @@ struct sparc_trapf { ...@@ -98,6 +98,7 @@ struct sparc_trapf {
set_thread_flag(TIF_SYSCALL_SUCCESS) set_thread_flag(TIF_SYSCALL_SUCCESS)
#define user_mode(regs) (!((regs)->tstate & TSTATE_PRIV)) #define user_mode(regs) (!((regs)->tstate & TSTATE_PRIV))
#define instruction_pointer(regs) ((regs)->tpc) #define instruction_pointer(regs) ((regs)->tpc)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *); extern void show_regs(struct pt_regs *);
#endif #endif
......
...@@ -76,6 +76,7 @@ struct pt_regs ...@@ -76,6 +76,7 @@ struct pt_regs
#define instruction_pointer(regs) ((regs)->pc) #define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs)
#define user_mode(regs) (!(regs)->kernel_mode) #define user_mode(regs) (!(regs)->kernel_mode)
/* When a struct pt_regs is used to save user state for a system call in /* When a struct pt_regs is used to save user state for a system call in
......
...@@ -83,6 +83,7 @@ struct pt_regs { ...@@ -83,6 +83,7 @@ struct pt_regs {
#if defined(__KERNEL__) && !defined(__ASSEMBLY__) #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
#define user_mode(regs) (!!((regs)->cs & 3)) #define user_mode(regs) (!!((regs)->cs & 3))
#define instruction_pointer(regs) ((regs)->rip) #define instruction_pointer(regs) ((regs)->rip)
#define profile_pc(regs) instruction_pointer(regs)
void signal_fault(struct pt_regs *regs, void __user *frame, char *where); void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
enum { enum {
......
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