Commit d360d565 authored by Akinobu Mita's avatar Akinobu Mita Committed by Linus Torvalds

[PATCH] oprofile: falling back on timer interrupt mode

When some hardware setups or architectures do not allow OProfile to use
performance counters, OProfile operates in timer mode.

But, from 2.6.11-rc1, we need to specify the module parameter "timer=1" to
work on timer interrupt mode.  Change things so that we detect the absence of
the high-resolution timer and fall back to timer-based profiling
automatically.

Furthermore we can easily get oops by reading /dev/oprofile/cpu_type.
Signed-off-by: default avatarAkinobu Mita <amgta@yacht.ocn.ne.jp>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 3680d547
...@@ -138,7 +138,7 @@ op_axp_create_files(struct super_block * sb, struct dentry * root) ...@@ -138,7 +138,7 @@ op_axp_create_files(struct super_block * sb, struct dentry * root)
return 0; return 0;
} }
void __init int __init
oprofile_arch_init(struct oprofile_operations *ops) oprofile_arch_init(struct oprofile_operations *ops)
{ {
struct op_axp_model *lmodel = NULL; struct op_axp_model *lmodel = NULL;
...@@ -166,7 +166,7 @@ oprofile_arch_init(struct oprofile_operations *ops) ...@@ -166,7 +166,7 @@ oprofile_arch_init(struct oprofile_operations *ops)
} }
if (!lmodel) if (!lmodel)
return; return -ENODEV;
model = lmodel; model = lmodel;
ops->create_files = op_axp_create_files; ops->create_files = op_axp_create_files;
...@@ -178,6 +178,8 @@ oprofile_arch_init(struct oprofile_operations *ops) ...@@ -178,6 +178,8 @@ oprofile_arch_init(struct oprofile_operations *ops)
printk(KERN_INFO "oprofile: using %s performance monitoring.\n", printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
lmodel->cpu_type); lmodel->cpu_type);
return 0;
} }
......
...@@ -105,12 +105,13 @@ static void pmu_stop(void) ...@@ -105,12 +105,13 @@ static void pmu_stop(void)
up(&pmu_sem); up(&pmu_sem);
} }
void __init pmu_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec) int __init
pmu_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec)
{ {
init_MUTEX(&pmu_sem); init_MUTEX(&pmu_sem);
if (spec->init() < 0) if (spec->init() < 0)
return; return -ENODEV;
pmu_model = spec; pmu_model = spec;
init_driverfs(); init_driverfs();
...@@ -121,6 +122,8 @@ void __init pmu_init(struct oprofile_operations *ops, struct op_arm_model_spec * ...@@ -121,6 +122,8 @@ void __init pmu_init(struct oprofile_operations *ops, struct op_arm_model_spec *
ops->stop = pmu_stop; ops->stop = pmu_stop;
ops->cpu_type = pmu_model->name; ops->cpu_type = pmu_model->name;
printk(KERN_INFO "oprofile: using %s PMU\n", spec->name); printk(KERN_INFO "oprofile: using %s PMU\n", spec->name);
return 0;
} }
void pmu_exit(void) void pmu_exit(void)
......
...@@ -12,11 +12,15 @@ ...@@ -12,11 +12,15 @@
#include <linux/errno.h> #include <linux/errno.h>
#include "op_arm_model.h" #include "op_arm_model.h"
void __init oprofile_arch_init(struct oprofile_operations *ops) int __init oprofile_arch_init(struct oprofile_operations *ops)
{ {
int ret = -ENODEV;
#ifdef CONFIG_CPU_XSCALE #ifdef CONFIG_CPU_XSCALE
pmu_init(ops, &op_xscale_spec); ret = pmu_init(ops, &op_xscale_spec);
#endif #endif
return ret;
} }
void oprofile_arch_exit(void) void oprofile_arch_exit(void)
......
...@@ -21,7 +21,7 @@ extern void nmi_exit(void); ...@@ -21,7 +21,7 @@ extern void nmi_exit(void);
extern void x86_backtrace(struct pt_regs * const regs, unsigned int depth); extern void x86_backtrace(struct pt_regs * const regs, unsigned int depth);
void __init oprofile_arch_init(struct oprofile_operations * ops) int __init oprofile_arch_init(struct oprofile_operations * ops)
{ {
int ret; int ret;
...@@ -35,6 +35,8 @@ void __init oprofile_arch_init(struct oprofile_operations * ops) ...@@ -35,6 +35,8 @@ void __init oprofile_arch_init(struct oprofile_operations * ops)
ret = nmi_timer_init(ops); ret = nmi_timer_init(ops);
#endif #endif
ops->backtrace = x86_backtrace; ops->backtrace = x86_backtrace;
return ret;
} }
......
...@@ -16,13 +16,17 @@ extern int perfmon_init(struct oprofile_operations * ops); ...@@ -16,13 +16,17 @@ extern int perfmon_init(struct oprofile_operations * ops);
extern void perfmon_exit(void); extern void perfmon_exit(void);
extern void ia64_backtrace(struct pt_regs * const regs, unsigned int depth); extern void ia64_backtrace(struct pt_regs * const regs, unsigned int depth);
void __init oprofile_arch_init(struct oprofile_operations * ops) int __init oprofile_arch_init(struct oprofile_operations * ops)
{ {
int ret = -ENODEV;
#ifdef CONFIG_PERFMON #ifdef CONFIG_PERFMON
/* perfmon_init() can fail, but we have no way to report it */ /* perfmon_init() can fail, but we have no way to report it */
perfmon_init(ops); ret = perfmon_init(ops);
#endif #endif
ops->backtrace = ia64_backtrace; ops->backtrace = ia64_backtrace;
return ret;
} }
......
...@@ -12,8 +12,9 @@ ...@@ -12,8 +12,9 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/init.h> #include <linux/init.h>
void __init oprofile_arch_init(struct oprofile_operations * ops) int __init oprofile_arch_init(struct oprofile_operations * ops)
{ {
return -ENODEV;
} }
void oprofile_arch_exit(void) void oprofile_arch_exit(void)
......
...@@ -12,8 +12,9 @@ ...@@ -12,8 +12,9 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/oprofile.h> #include <linux/oprofile.h>
void __init oprofile_arch_init(struct oprofile_operations * ops) int __init oprofile_arch_init(struct oprofile_operations * ops)
{ {
return -ENODEV;
} }
......
...@@ -125,7 +125,7 @@ static int op_ppc64_create_files(struct super_block *sb, struct dentry *root) ...@@ -125,7 +125,7 @@ static int op_ppc64_create_files(struct super_block *sb, struct dentry *root)
return 0; return 0;
} }
void __init oprofile_arch_init(struct oprofile_operations *ops) int __init oprofile_arch_init(struct oprofile_operations *ops)
{ {
unsigned int pvr; unsigned int pvr;
...@@ -170,7 +170,7 @@ void __init oprofile_arch_init(struct oprofile_operations *ops) ...@@ -170,7 +170,7 @@ void __init oprofile_arch_init(struct oprofile_operations *ops)
break; break;
default: default:
return; return -ENODEV;
} }
ops->create_files = op_ppc64_create_files; ops->create_files = op_ppc64_create_files;
...@@ -181,6 +181,8 @@ void __init oprofile_arch_init(struct oprofile_operations *ops) ...@@ -181,6 +181,8 @@ void __init oprofile_arch_init(struct oprofile_operations *ops)
printk(KERN_INFO "oprofile: using %s performance monitoring.\n", printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
ops->cpu_type); ops->cpu_type);
return 0;
} }
void oprofile_arch_exit(void) void oprofile_arch_exit(void)
......
...@@ -12,8 +12,9 @@ ...@@ -12,8 +12,9 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/errno.h> #include <linux/errno.h>
void __init oprofile_arch_init(struct oprofile_operations* ops) int __init oprofile_arch_init(struct oprofile_operations* ops)
{ {
return -ENODEV;
} }
void oprofile_arch_exit(void) void oprofile_arch_exit(void)
......
...@@ -12,8 +12,9 @@ ...@@ -12,8 +12,9 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/errno.h> #include <linux/errno.h>
void __init oprofile_arch_init(struct oprofile_operations *ops) int __init oprofile_arch_init(struct oprofile_operations *ops)
{ {
return -ENODEV;
} }
void oprofile_arch_exit(void) void oprofile_arch_exit(void)
......
...@@ -12,8 +12,9 @@ ...@@ -12,8 +12,9 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/init.h> #include <linux/init.h>
void __init oprofile_arch_init(struct oprofile_operations * ops) int __init oprofile_arch_init(struct oprofile_operations * ops)
{ {
return -ENODEV;
} }
......
...@@ -153,11 +153,11 @@ int oprofile_set_backtrace(unsigned long val) ...@@ -153,11 +153,11 @@ int oprofile_set_backtrace(unsigned long val)
static int __init oprofile_init(void) static int __init oprofile_init(void)
{ {
int err = 0; int err;
oprofile_arch_init(&oprofile_ops); err = oprofile_arch_init(&oprofile_ops);
if (timer) { if (err < 0 || timer) {
printk(KERN_INFO "oprofile: using timer interrupt.\n"); printk(KERN_INFO "oprofile: using timer interrupt.\n");
oprofile_timer_init(&oprofile_ops); oprofile_timer_init(&oprofile_ops);
} }
......
...@@ -48,7 +48,7 @@ struct oprofile_operations { ...@@ -48,7 +48,7 @@ struct oprofile_operations {
* *
* If an error occurs, the fields should be left untouched. * If an error occurs, the fields should be left untouched.
*/ */
void oprofile_arch_init(struct oprofile_operations * ops); int oprofile_arch_init(struct oprofile_operations * ops);
/** /**
* One-time exit/cleanup for the arch. * One-time exit/cleanup for the arch.
......
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