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);
static inline void
ia64_do_profile (struct pt_regs * regs)
{
unsigned long ip, slot;
unsigned long ip;
profile_hook(regs);
......@@ -205,12 +205,10 @@ ia64_do_profile (struct pt_regs * regs)
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;
ip = profile_pc(regs);
/*
* Only measure the CPUs specified by /proc/irq/prof_cpu_mask.
......
......@@ -262,9 +262,6 @@ static inline void sh_do_profile(unsigned long pc)
if (!prof_buffer || !current->pid)
return;
if (pc >= 0xa0000000UL && pc < 0xc0000000UL)
pc -= 0x20000000;
pc -= (unsigned long)&_stext;
pc >>= prof_shift;
......@@ -288,7 +285,7 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *reg
do_timer(regs);
if (!user_mode(regs))
sh_do_profile(regs->pc);
sh_do_profile(profile_pc(regs));
#ifdef CONFIG_HEARTBEAT
if (sh_mv.mv_heartbeat != NULL)
......
......@@ -19,6 +19,7 @@
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/profile.h>
#include <asm/ptrace.h>
#include <asm/atomic.h>
......
......@@ -16,6 +16,7 @@
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/profile.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
......
......@@ -79,6 +79,26 @@ struct intersil *intersil_clock;
#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;
/* 32-bit Sparc specific profiling function. */
......@@ -86,20 +106,6 @@ void sparc_do_profile(unsigned long pc, unsigned long o7)
{
if(prof_buffer && current->pid) {
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 >>= prof_shift;
......@@ -130,7 +136,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
#ifndef CONFIG_SMP
if(!user_mode(regs))
sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]);
sparc_do_profile(profile_pc(regs));
#endif
/* Protect counter clear so that do_gettimeoffset works */
......
......@@ -19,6 +19,7 @@
#include <linux/seq_file.h>
#include <linux/cache.h>
#include <linux/jiffies.h>
#include <linux/profile.h>
#include <asm/head.h>
#include <asm/ptrace.h>
......
......@@ -29,6 +29,7 @@
#include <linux/jiffies.h>
#include <linux/cpufreq.h>
#include <linux/percpu.h>
#include <linux/profile.h>
#include <asm/oplib.h>
#include <asm/mostek.h>
......@@ -453,14 +454,8 @@ void sparc64_do_profile(struct pt_regs *regs)
if (!prof_buffer)
return;
pc = regs->tpc;
pc -= (unsigned long) _stext;
pc >>= prof_shift;
if(pc >= prof_len)
pc = prof_len - 1;
atomic_inc((atomic_t *)&prof_buffer[pc]);
pc = (profile_pc(regs) - (unsigned long)_stext) >> prof_shift;
atomic_inc((atomic_t *)&prof_buffer[min(pc, prof_len-1)]);
}
static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
......
......@@ -69,6 +69,7 @@ struct switch_stack {
#ifdef __KERNEL__
#define user_mode(regs) (((regs)->ps & 8) != 0)
#define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *);
#define alpha_task_regs(task) \
......
......@@ -130,6 +130,7 @@ static inline int valid_user_regs(struct pt_regs *regs)
#define instruction_pointer(regs) \
(pc_pointer((regs)->ARM_pc))
#define profile_pc(regs) instruction_pointer(regs)
#ifdef __KERNEL__
extern void show_regs(struct pt_regs *);
......
......@@ -30,6 +30,7 @@
#define pc_pointer(v) ((v) & ~PCMASK) /* convert v to pc type address */
#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
stack during a system call. */
......
......@@ -109,6 +109,7 @@ struct switch_stack {
/* bit 8 is user-mode flag */
#define user_mode(regs) (((regs)->dccr & 0x100) != 0)
#define instruction_pointer(regs) ((regs)->irp)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *);
#endif
......@@ -57,6 +57,7 @@ struct pt_regs {
#define user_mode(regs) (!((regs)->ccr & PS_S))
#define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *);
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
......
......@@ -57,6 +57,7 @@ struct pt_regs {
#ifdef __KERNEL__
#define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs))
#define instruction_pointer(regs) ((regs)->eip)
#define profile_pc(regs) instruction_pointer(regs)
#endif
#endif
......@@ -229,6 +229,15 @@ struct switch_stack {
* the canonical representation by adding to instruction pointer.
*/
# 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 */
# define ia64_task_regs(t) (((struct pt_regs *) ((char *) (t) + IA64_STK_OFFSET)) - 1)
# define ia64_psr(regs) ((struct ia64_psr *) &(regs)->cr_ipsr)
......
......@@ -73,6 +73,7 @@ struct switch_stack {
#define user_mode(regs) (!((regs)->sr & PS_S))
#define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *);
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
......
......@@ -84,6 +84,7 @@ struct switch_stack {
#define user_mode(regs) (!((regs)->sr & PS_S))
#define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *);
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
......
......@@ -66,6 +66,7 @@ struct pt_regs {
#define user_mode(regs) (((regs)->cp0_status & KU_MASK) == KU_USER)
#define instruction_pointer(regs) ((regs)->cp0_epc)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *);
......
......@@ -48,6 +48,7 @@ struct pt_regs {
/* XXX should we use iaoq[1] or iaoq[0] ? */
#define user_mode(regs) (((regs)->iaoq[0] & 3) ? 1 : 0)
#define instruction_pointer(regs) ((regs)->iaoq[0] & ~3)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *);
#endif
......
......@@ -47,6 +47,7 @@ struct pt_regs {
#ifndef __ASSEMBLY__
#define instruction_pointer(regs) ((regs)->nip)
#define profile_pc(regs) instruction_pointer(regs)
#define user_mode(regs) (((regs)->msr & MSR_PR) != 0)
#define force_successful_syscall_return() \
......
......@@ -69,6 +69,7 @@ struct pt_regs32 {
#define __SIGNAL_FRAMESIZE32 64
#define instruction_pointer(regs) ((regs)->nip)
#define profile_pc(regs) instruction_pointer(regs)
#define user_mode(regs) ((((regs)->msr) >> MSR_PR_LG) & 0x1)
#define force_successful_syscall_return() \
......
......@@ -466,6 +466,7 @@ struct user_regs_struct
#ifdef __KERNEL__
#define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
#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);
#endif
......
......@@ -90,6 +90,15 @@ struct pt_dspregs {
#define user_mode(regs) (((regs)->sr & 0x40000000)==0)
#define instruction_pointer(regs) ((regs)->pc)
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 /* __ASM_SH_PTRACE_H */
......@@ -28,6 +28,7 @@ struct pt_regs {
#ifdef __KERNEL__
#define user_mode(regs) (((regs)->sr & 0x40000000)==0)
#define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *);
#endif
......
......@@ -62,6 +62,7 @@ struct sparc_stackf {
#ifdef __KERNEL__
#define user_mode(regs) (!((regs)->psr & PSR_PS))
#define instruction_pointer(regs) ((regs)->pc)
unsigned long profile_pc(struct pt_regs *);
extern void show_regs(struct pt_regs *);
#endif
......
......@@ -98,6 +98,7 @@ struct sparc_trapf {
set_thread_flag(TIF_SYSCALL_SUCCESS)
#define user_mode(regs) (!((regs)->tstate & TSTATE_PRIV))
#define instruction_pointer(regs) ((regs)->tpc)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *);
#endif
......
......@@ -76,6 +76,7 @@ struct pt_regs
#define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs)
#define user_mode(regs) (!(regs)->kernel_mode)
/* When a struct pt_regs is used to save user state for a system call in
......
......@@ -83,6 +83,7 @@ struct pt_regs {
#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
#define user_mode(regs) (!!((regs)->cs & 3))
#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);
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