Skip to content

Commit

Permalink
oprofile, s390: Rework hwsampler implementation
Browse files Browse the repository at this point in the history
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: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Robert Richter <robert.richter@amd.com>
  • Loading branch information
Robert Richter committed Feb 15, 2011
1 parent 997dbb4 commit a0d7624
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 90 deletions.
60 changes: 38 additions & 22 deletions arch/s390/oprofile/hwsampler_files.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <linux/errno.h>
#include <linux/fs.h>

#include "../../../drivers/oprofile/oprof.h"
#include "hwsampler.h"

#define DEFAULT_INTERVAL 4096
Expand All @@ -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;
Expand All @@ -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,
Expand All @@ -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;
}

Expand All @@ -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)
Expand All @@ -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;
Expand All @@ -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();
}
1 change: 0 additions & 1 deletion arch/s390/oprofile/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
32 changes: 0 additions & 32 deletions drivers/oprofile/oprof.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 0 additions & 2 deletions drivers/oprofile/oprof.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
15 changes: 3 additions & 12 deletions drivers/oprofile/timer_int.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
}
21 changes: 0 additions & 21 deletions include/linux/oprofile.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down

0 comments on commit a0d7624

Please sign in to comment.