Commit a0d76247 authored by Robert Richter's avatar Robert Richter

oprofile, s390: Rework hwsampler implementation

This patch is a rework of the hwsampler oprofile implementation that
has been applied recently. Now there are less non-architectural
changes. The only changes are:

* introduction of oprofile_add_ext_hw_sample(), and
* removal of section attributes of oprofile_timer_init/_exit().

To setup hwsampler for oprofile we need to modify start()/stop()
callbacks and additional hwsampler control files in oprofilefs. We do
not reinitialize the timer or hwsampler mode by restarting calling
init/exit() anymore, instead hwsampler_running is used to switch the
mode directly in oprofile_hwsampler_start/_stop(). For locking reasons
there is also hwsampler_file that reflects the value in oprofilefs.

The overall diffstat of the oprofile s390 hwsampler implemenation
shows the low impact to non-architectural code:

 arch/Kconfig                         |    3 +
 arch/s390/Kconfig                    |    1 +
 arch/s390/oprofile/Makefile          |    2 +-
 arch/s390/oprofile/hwsampler.c       | 1256 ++++++++++++++++++++++++++++++++++
 arch/s390/oprofile/hwsampler.h       |  113 +++
 arch/s390/oprofile/hwsampler_files.c |  162 +++++
 arch/s390/oprofile/init.c            |    6 +-
 drivers/oprofile/cpu_buffer.c        |   24 +-
 drivers/oprofile/timer_int.c         |    4 +-
 include/linux/oprofile.h             |    7 +
 10 files changed, 1567 insertions(+), 11 deletions(-)
Acked-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarRobert Richter <robert.richter@amd.com>
parent 997dbb49
......@@ -8,6 +8,7 @@
#include <linux/errno.h>
#include <linux/fs.h>
#include "../../../drivers/oprofile/oprof.h"
#include "hwsampler.h"
#define DEFAULT_INTERVAL 4096
......@@ -22,12 +23,20 @@ static unsigned long oprofile_max_interval;
static unsigned long oprofile_sdbt_blocks = DEFAULT_SDBT_BLOCKS;
static unsigned long oprofile_sdb_blocks = DEFAULT_SDB_BLOCKS;
static unsigned long oprofile_hwsampler;
static int hwsampler_file;
static int hwsampler_running; /* start_mutex must be held to change */
static struct oprofile_operations timer_ops;
static int oprofile_hwsampler_start(void)
{
int retval;
hwsampler_running = hwsampler_file;
if (!hwsampler_running)
return timer_ops.start();
retval = hwsampler_allocate(oprofile_sdbt_blocks, oprofile_sdb_blocks);
if (retval)
return retval;
......@@ -41,25 +50,20 @@ static int oprofile_hwsampler_start(void)
static void oprofile_hwsampler_stop(void)
{
if (!hwsampler_running) {
timer_ops.stop();
return;
}
hwsampler_stop_all();
hwsampler_deallocate();
return;
}
int oprofile_arch_set_hwsampler(struct oprofile_operations *ops)
{
printk(KERN_INFO "oprofile: using hardware sampling\n");
ops->start = oprofile_hwsampler_start;
ops->stop = oprofile_hwsampler_stop;
ops->cpu_type = "timer";
return 0;
}
static ssize_t hwsampler_read(struct file *file, char __user *buf,
size_t count, loff_t *offset)
{
return oprofilefs_ulong_to_user(oprofile_hwsampler, buf, count, offset);
return oprofilefs_ulong_to_user(hwsampler_file, buf, count, offset);
}
static ssize_t hwsampler_write(struct file *file, char const __user *buf,
......@@ -75,15 +79,16 @@ static ssize_t hwsampler_write(struct file *file, char const __user *buf,
if (retval)
return retval;
if (oprofile_hwsampler == val)
return -EINVAL;
retval = oprofile_set_hwsampler(val);
if (oprofile_started)
/*
* save to do without locking as we set
* hwsampler_running in start() when start_mutex is
* held
*/
return -EBUSY;
if (retval)
return retval;
hwsampler_file = val;
oprofile_hwsampler = val;
return count;
}
......@@ -98,7 +103,7 @@ static int oprofile_create_hwsampling_files(struct super_block *sb,
struct dentry *hw_dir;
/* reinitialize default values */
oprofile_hwsampler = 1;
hwsampler_file = 1;
hw_dir = oprofilefs_mkdir(sb, root, "hwsampling");
if (!hw_dir)
......@@ -125,7 +130,6 @@ int oprofile_hwsampler_init(struct oprofile_operations* ops)
/*
* create hwsampler files only if hwsampler_setup() succeeds.
*/
ops->create_files = oprofile_create_hwsampling_files;
oprofile_min_interval = hwsampler_query_min_interval();
if (oprofile_min_interval < 0) {
oprofile_min_interval = 0;
......@@ -136,11 +140,23 @@ int oprofile_hwsampler_init(struct oprofile_operations* ops)
oprofile_max_interval = 0;
return -ENODEV;
}
oprofile_arch_set_hwsampler(ops);
if (oprofile_timer_init(ops))
return -ENODEV;
printk(KERN_INFO "oprofile: using hardware sampling\n");
memcpy(&timer_ops, ops, sizeof(timer_ops));
ops->start = oprofile_hwsampler_start;
ops->stop = oprofile_hwsampler_stop;
ops->create_files = oprofile_create_hwsampling_files;
return 0;
}
void oprofile_hwsampler_exit(void)
{
oprofile_timer_exit();
hwsampler_shutdown();
}
......@@ -11,7 +11,6 @@
#include <linux/oprofile.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/fs.h>
extern int oprofile_hwsampler_init(struct oprofile_operations* ops);
extern void oprofile_hwsampler_exit(void);
......
......@@ -239,38 +239,6 @@ int oprofile_set_ulong(unsigned long *addr, unsigned long val)
return err;
}
#ifdef CONFIG_HAVE_HWSAMPLER
int oprofile_set_hwsampler(unsigned long val)
{
int err = 0;
mutex_lock(&start_mutex);
if (oprofile_started) {
err = -EBUSY;
goto out;
}
switch (val) {
case 1:
/* Switch to hardware sampling. */
__oprofile_timer_exit();
err = oprofile_arch_set_hwsampler(&oprofile_ops);
break;
case 0:
printk(KERN_INFO "oprofile: using timer interrupt.\n");
err = __oprofile_timer_init(&oprofile_ops);
break;
default:
err = -EINVAL;
}
out:
mutex_unlock(&start_mutex);
return err;
}
#endif /* CONFIG_HAVE_HWSAMPLER */
static int __init oprofile_init(void)
{
int err;
......
......@@ -35,9 +35,7 @@ struct dentry;
void oprofile_create_files(struct super_block *sb, struct dentry *root);
int oprofile_timer_init(struct oprofile_operations *ops);
int __oprofile_timer_init(struct oprofile_operations *ops);
void oprofile_timer_exit(void);
void __oprofile_timer_exit(void);
int oprofile_set_ulong(unsigned long *addr, unsigned long val);
int oprofile_set_timeout(unsigned long time);
......
......@@ -97,13 +97,14 @@ static struct notifier_block __refdata oprofile_cpu_notifier = {
.notifier_call = oprofile_cpu_notify,
};
int __oprofile_timer_init(struct oprofile_operations *ops)
int oprofile_timer_init(struct oprofile_operations *ops)
{
int rc;
rc = register_hotcpu_notifier(&oprofile_cpu_notifier);
if (rc)
return rc;
ops->create_files = NULL;
ops->setup = NULL;
ops->shutdown = NULL;
ops->start = oprofile_hrtimer_start;
......@@ -112,17 +113,7 @@ int __oprofile_timer_init(struct oprofile_operations *ops)
return 0;
}
int __init oprofile_timer_init(struct oprofile_operations *ops)
{
return __oprofile_timer_init(ops);
}
void __oprofile_timer_exit(void)
void oprofile_timer_exit(void)
{
unregister_hotcpu_notifier(&oprofile_cpu_notifier);
}
void __exit oprofile_timer_exit(void)
{
__oprofile_timer_exit();
}
......@@ -91,27 +91,6 @@ int oprofile_arch_init(struct oprofile_operations * ops);
*/
void oprofile_arch_exit(void);
#ifdef CONFIG_HAVE_HWSAMPLER
/**
* setup hardware sampler for oprofiling.
*/
int oprofile_set_hwsampler(unsigned long);
/**
* hardware sampler module initialization for the s390 arch
*/
int oprofile_arch_set_hwsampler(struct oprofile_operations *ops);
/**
* Add an s390 hardware sample.
*/
void oprofile_add_ext_hw_sample(unsigned long pc, struct pt_regs * const regs,
unsigned long event, int is_kernel,
struct task_struct *task);
#endif /* CONFIG_HAVE_HWSAMPLER */
/**
* Add a sample. This may be called from any context.
*/
......
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