Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a0d76247 authored by Robert Richter's avatar Robert Richter
Browse files

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
Loading
Loading
Loading
Loading
+38 −22
Original line number Diff line number Diff line
@@ -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)
{
	hwsampler_stop_all();
	hwsampler_deallocate();
	if (!hwsampler_running) {
		timer_ops.stop();
		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;
	hwsampler_stop_all();
	hwsampler_deallocate();
	return;
}

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();
}
+0 −1
Original line number Diff line number Diff line
@@ -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);
+0 −32
Original line number Diff line number Diff line
@@ -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;
+0 −2
Original line number Diff line number Diff line
@@ -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);
+3 −12
Original line number Diff line number Diff line
@@ -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();
}
Loading