aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeinz Graalfs <graalfs@linux.vnet.ibm.com>2011-01-21 05:06:53 -0500
committerRobert Richter <robert.richter@amd.com>2011-02-15 05:08:50 -0500
commit997dbb4967da248808850c250182ef2528fff2d1 (patch)
treeb41497541383c2e569b629fbab09fb2280611965
parentec6a3df1c008d9e8664e53b0363f6847c5c0dc3f (diff)
oprofile, s390: Enhance OProfile to support System zs hardware sampling feature
OProfile is enhanced to export all files for controlling System z's hardware sampling, and to invoke hwsampler exported functions to initialize and use System z's hardware sampling. The patch invokes hwsampler_setup() during oprofile init and exports following hwsampler files under oprofilefs if hwsampler's setup succeeded: A new directory for hardware sampling based files /dev/oprofile/hwsampling/ The userland daemon must explicitly write to the following files to disable (or enable) hardware based sampling /dev/oprofile/hwsampling/hwsampler to modify the actual sampling rate /dev/oprofile/hwsampling/hw_interval to modify the amount of sampling memory (measured in 4K pages) /dev/oprofile/hwsampling/hw_sdbt_blocks The following files are read only and show the possible minimum sampling rate /dev/oprofile/hwsampling/hw_min_interval the possible maximum sampling rate /dev/oprofile/hwsampling/hw_max_interval The patch splits the oprofile_timer_[init/exit] function so that it can be also called through user context (oprofilefs) to avoid kernel oops. Applied with following changes: * whitespace changes in Makefile and timer_int.c Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> Signed-off-by: Maran Pakkirisamy <maranp@linux.vnet.ibm.com> Signed-off-by: Heinz Graalfs <graalfs@linux.vnet.ibm.com> Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Robert Richter <robert.richter@amd.com>
-rw-r--r--arch/s390/oprofile/Makefile2
-rw-r--r--arch/s390/oprofile/hwsampler_files.c146
-rw-r--r--arch/s390/oprofile/init.c7
-rw-r--r--drivers/oprofile/oprof.c32
-rw-r--r--drivers/oprofile/oprof.h2
-rw-r--r--drivers/oprofile/timer_int.c15
-rw-r--r--include/linux/oprofile.h21
7 files changed, 220 insertions, 5 deletions
diff --git a/arch/s390/oprofile/Makefile b/arch/s390/oprofile/Makefile
index d698cddcfbdd..00d8fc8e4429 100644
--- a/arch/s390/oprofile/Makefile
+++ b/arch/s390/oprofile/Makefile
@@ -6,4 +6,4 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
6 oprofilefs.o oprofile_stats.o \ 6 oprofilefs.o oprofile_stats.o \
7 timer_int.o ) 7 timer_int.o )
8 8
9oprofile-y := $(DRIVER_OBJS) init.o backtrace.o hwsampler.o 9oprofile-y := $(DRIVER_OBJS) init.o backtrace.o hwsampler.o hwsampler_files.o
diff --git a/arch/s390/oprofile/hwsampler_files.c b/arch/s390/oprofile/hwsampler_files.c
new file mode 100644
index 000000000000..493f7cc4e861
--- /dev/null
+++ b/arch/s390/oprofile/hwsampler_files.c
@@ -0,0 +1,146 @@
1/**
2 * arch/s390/oprofile/hwsampler_files.c
3 *
4 * Copyright IBM Corp. 2010
5 * Author: Mahesh Salgaonkar (mahesh@linux.vnet.ibm.com)
6 */
7#include <linux/oprofile.h>
8#include <linux/errno.h>
9#include <linux/fs.h>
10
11#include "hwsampler.h"
12
13#define DEFAULT_INTERVAL 4096
14
15#define DEFAULT_SDBT_BLOCKS 1
16#define DEFAULT_SDB_BLOCKS 511
17
18static unsigned long oprofile_hw_interval = DEFAULT_INTERVAL;
19static unsigned long oprofile_min_interval;
20static unsigned long oprofile_max_interval;
21
22static unsigned long oprofile_sdbt_blocks = DEFAULT_SDBT_BLOCKS;
23static unsigned long oprofile_sdb_blocks = DEFAULT_SDB_BLOCKS;
24
25static unsigned long oprofile_hwsampler;
26
27static int oprofile_hwsampler_start(void)
28{
29 int retval;
30
31 retval = hwsampler_allocate(oprofile_sdbt_blocks, oprofile_sdb_blocks);
32 if (retval)
33 return retval;
34
35 retval = hwsampler_start_all(oprofile_hw_interval);
36 if (retval)
37 hwsampler_deallocate();
38
39 return retval;
40}
41
42static void oprofile_hwsampler_stop(void)
43{
44 hwsampler_stop_all();
45 hwsampler_deallocate();
46 return;
47}
48
49int oprofile_arch_set_hwsampler(struct oprofile_operations *ops)
50{
51 printk(KERN_INFO "oprofile: using hardware sampling\n");
52 ops->start = oprofile_hwsampler_start;
53 ops->stop = oprofile_hwsampler_stop;
54 ops->cpu_type = "timer";
55
56 return 0;
57}
58
59static ssize_t hwsampler_read(struct file *file, char __user *buf,
60 size_t count, loff_t *offset)
61{
62 return oprofilefs_ulong_to_user(oprofile_hwsampler, buf, count, offset);
63}
64
65static ssize_t hwsampler_write(struct file *file, char const __user *buf,
66 size_t count, loff_t *offset)
67{
68 unsigned long val;
69 int retval;
70
71 if (*offset)
72 return -EINVAL;
73
74 retval = oprofilefs_ulong_from_user(&val, buf, count);
75 if (retval)
76 return retval;
77
78 if (oprofile_hwsampler == val)
79 return -EINVAL;
80
81 retval = oprofile_set_hwsampler(val);
82
83 if (retval)
84 return retval;
85
86 oprofile_hwsampler = val;
87 return count;
88}
89
90static const struct file_operations hwsampler_fops = {
91 .read = hwsampler_read,
92 .write = hwsampler_write,
93};
94
95static int oprofile_create_hwsampling_files(struct super_block *sb,
96 struct dentry *root)
97{
98 struct dentry *hw_dir;
99
100 /* reinitialize default values */
101 oprofile_hwsampler = 1;
102
103 hw_dir = oprofilefs_mkdir(sb, root, "hwsampling");
104 if (!hw_dir)
105 return -EINVAL;
106
107 oprofilefs_create_file(sb, hw_dir, "hwsampler", &hwsampler_fops);
108 oprofilefs_create_ulong(sb, hw_dir, "hw_interval",
109 &oprofile_hw_interval);
110 oprofilefs_create_ro_ulong(sb, hw_dir, "hw_min_interval",
111 &oprofile_min_interval);
112 oprofilefs_create_ro_ulong(sb, hw_dir, "hw_max_interval",
113 &oprofile_max_interval);
114 oprofilefs_create_ulong(sb, hw_dir, "hw_sdbt_blocks",
115 &oprofile_sdbt_blocks);
116
117 return 0;
118}
119
120int oprofile_hwsampler_init(struct oprofile_operations* ops)
121{
122 if (hwsampler_setup())
123 return -ENODEV;
124
125 /*
126 * create hwsampler files only if hwsampler_setup() succeeds.
127 */
128 ops->create_files = oprofile_create_hwsampling_files;
129 oprofile_min_interval = hwsampler_query_min_interval();
130 if (oprofile_min_interval < 0) {
131 oprofile_min_interval = 0;
132 return -ENODEV;
133 }
134 oprofile_max_interval = hwsampler_query_max_interval();
135 if (oprofile_max_interval < 0) {
136 oprofile_max_interval = 0;
137 return -ENODEV;
138 }
139 oprofile_arch_set_hwsampler(ops);
140 return 0;
141}
142
143void oprofile_hwsampler_exit(void)
144{
145 hwsampler_shutdown();
146}
diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c
index 7a995113b918..f6b3f724f590 100644
--- a/arch/s390/oprofile/init.c
+++ b/arch/s390/oprofile/init.c
@@ -11,16 +11,21 @@
11#include <linux/oprofile.h> 11#include <linux/oprofile.h>
12#include <linux/init.h> 12#include <linux/init.h>
13#include <linux/errno.h> 13#include <linux/errno.h>
14#include <linux/fs.h>
14 15
16extern int oprofile_hwsampler_init(struct oprofile_operations* ops);
17extern void oprofile_hwsampler_exit(void);
15 18
16extern void s390_backtrace(struct pt_regs * const regs, unsigned int depth); 19extern void s390_backtrace(struct pt_regs * const regs, unsigned int depth);
17 20
18int __init oprofile_arch_init(struct oprofile_operations* ops) 21int __init oprofile_arch_init(struct oprofile_operations* ops)
19{ 22{
20 ops->backtrace = s390_backtrace; 23 ops->backtrace = s390_backtrace;
21 return -ENODEV; 24
25 return oprofile_hwsampler_init(ops);
22} 26}
23 27
24void oprofile_arch_exit(void) 28void oprofile_arch_exit(void)
25{ 29{
30 oprofile_hwsampler_exit();
26} 31}
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
index f9bda64fcd1b..43b01daa91e1 100644
--- a/drivers/oprofile/oprof.c
+++ b/drivers/oprofile/oprof.c
@@ -239,6 +239,38 @@ int oprofile_set_ulong(unsigned long *addr, unsigned long val)
239 return err; 239 return err;
240} 240}
241 241
242#ifdef CONFIG_HAVE_HWSAMPLER
243int oprofile_set_hwsampler(unsigned long val)
244{
245 int err = 0;
246
247 mutex_lock(&start_mutex);
248
249 if (oprofile_started) {
250 err = -EBUSY;
251 goto out;
252 }
253
254 switch (val) {
255 case 1:
256 /* Switch to hardware sampling. */
257 __oprofile_timer_exit();
258 err = oprofile_arch_set_hwsampler(&oprofile_ops);
259 break;
260 case 0:
261 printk(KERN_INFO "oprofile: using timer interrupt.\n");
262 err = __oprofile_timer_init(&oprofile_ops);
263 break;
264 default:
265 err = -EINVAL;
266 }
267
268out:
269 mutex_unlock(&start_mutex);
270 return err;
271}
272#endif /* CONFIG_HAVE_HWSAMPLER */
273
242static int __init oprofile_init(void) 274static int __init oprofile_init(void)
243{ 275{
244 int err; 276 int err;
diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h
index 177b73de5e5f..5a6ceb1954a2 100644
--- a/drivers/oprofile/oprof.h
+++ b/drivers/oprofile/oprof.h
@@ -35,7 +35,9 @@ struct dentry;
35 35
36void oprofile_create_files(struct super_block *sb, struct dentry *root); 36void oprofile_create_files(struct super_block *sb, struct dentry *root);
37int oprofile_timer_init(struct oprofile_operations *ops); 37int oprofile_timer_init(struct oprofile_operations *ops);
38int __oprofile_timer_init(struct oprofile_operations *ops);
38void oprofile_timer_exit(void); 39void oprofile_timer_exit(void);
40void __oprofile_timer_exit(void);
39 41
40int oprofile_set_ulong(unsigned long *addr, unsigned long val); 42int oprofile_set_ulong(unsigned long *addr, unsigned long val);
41int oprofile_set_timeout(unsigned long time); 43int oprofile_set_timeout(unsigned long time);
diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c
index 010725117dbb..0099a458fd37 100644
--- a/drivers/oprofile/timer_int.c
+++ b/drivers/oprofile/timer_int.c
@@ -97,14 +97,13 @@ static struct notifier_block __refdata oprofile_cpu_notifier = {
97 .notifier_call = oprofile_cpu_notify, 97 .notifier_call = oprofile_cpu_notify,
98}; 98};
99 99
100int __init oprofile_timer_init(struct oprofile_operations *ops) 100int __oprofile_timer_init(struct oprofile_operations *ops)
101{ 101{
102 int rc; 102 int rc;
103 103
104 rc = register_hotcpu_notifier(&oprofile_cpu_notifier); 104 rc = register_hotcpu_notifier(&oprofile_cpu_notifier);
105 if (rc) 105 if (rc)
106 return rc; 106 return rc;
107 ops->create_files = NULL;
108 ops->setup = NULL; 107 ops->setup = NULL;
109 ops->shutdown = NULL; 108 ops->shutdown = NULL;
110 ops->start = oprofile_hrtimer_start; 109 ops->start = oprofile_hrtimer_start;
@@ -113,7 +112,17 @@ int __init oprofile_timer_init(struct oprofile_operations *ops)
113 return 0; 112 return 0;
114} 113}
115 114
116void __exit oprofile_timer_exit(void) 115int __init oprofile_timer_init(struct oprofile_operations *ops)
116{
117 return __oprofile_timer_init(ops);
118}
119
120void __oprofile_timer_exit(void)
117{ 121{
118 unregister_hotcpu_notifier(&oprofile_cpu_notifier); 122 unregister_hotcpu_notifier(&oprofile_cpu_notifier);
119} 123}
124
125void __exit oprofile_timer_exit(void)
126{
127 __oprofile_timer_exit();
128}
diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h
index 7f5cfd3b37dd..b517d869e1ad 100644
--- a/include/linux/oprofile.h
+++ b/include/linux/oprofile.h
@@ -91,6 +91,27 @@ int oprofile_arch_init(struct oprofile_operations * ops);
91 */ 91 */
92void oprofile_arch_exit(void); 92void oprofile_arch_exit(void);
93 93
94#ifdef CONFIG_HAVE_HWSAMPLER
95/**
96 * setup hardware sampler for oprofiling.
97 */
98
99int oprofile_set_hwsampler(unsigned long);
100
101/**
102 * hardware sampler module initialization for the s390 arch
103 */
104
105int oprofile_arch_set_hwsampler(struct oprofile_operations *ops);
106
107/**
108 * Add an s390 hardware sample.
109 */
110void oprofile_add_ext_hw_sample(unsigned long pc, struct pt_regs * const regs,
111 unsigned long event, int is_kernel,
112 struct task_struct *task);
113#endif /* CONFIG_HAVE_HWSAMPLER */
114
94/** 115/**
95 * Add a sample. This may be called from any context. 116 * Add a sample. This may be called from any context.
96 */ 117 */