diff options
author | Robert Richter <robert.richter@amd.com> | 2011-02-11 11:31:44 -0500 |
---|---|---|
committer | Robert Richter <robert.richter@amd.com> | 2011-02-15 05:10:20 -0500 |
commit | a0d76247e07abd14968adc4486aaa8e270e9c209 (patch) | |
tree | bec9fa0f5a3c7b3d1f3c3032900d74f41941ed2d | |
parent | 997dbb4967da248808850c250182ef2528fff2d1 (diff) |
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: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Robert Richter <robert.richter@amd.com>
-rw-r--r-- | arch/s390/oprofile/hwsampler_files.c | 60 | ||||
-rw-r--r-- | arch/s390/oprofile/init.c | 1 | ||||
-rw-r--r-- | drivers/oprofile/oprof.c | 32 | ||||
-rw-r--r-- | drivers/oprofile/oprof.h | 2 | ||||
-rw-r--r-- | drivers/oprofile/timer_int.c | 15 | ||||
-rw-r--r-- | include/linux/oprofile.h | 21 |
6 files changed, 41 insertions, 90 deletions
diff --git a/arch/s390/oprofile/hwsampler_files.c b/arch/s390/oprofile/hwsampler_files.c index 493f7cc4e861..2e1da2449ba9 100644 --- a/arch/s390/oprofile/hwsampler_files.c +++ b/arch/s390/oprofile/hwsampler_files.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/errno.h> | 8 | #include <linux/errno.h> |
9 | #include <linux/fs.h> | 9 | #include <linux/fs.h> |
10 | 10 | ||
11 | #include "../../../drivers/oprofile/oprof.h" | ||
11 | #include "hwsampler.h" | 12 | #include "hwsampler.h" |
12 | 13 | ||
13 | #define DEFAULT_INTERVAL 4096 | 14 | #define DEFAULT_INTERVAL 4096 |
@@ -22,12 +23,20 @@ static unsigned long oprofile_max_interval; | |||
22 | static unsigned long oprofile_sdbt_blocks = DEFAULT_SDBT_BLOCKS; | 23 | static unsigned long oprofile_sdbt_blocks = DEFAULT_SDBT_BLOCKS; |
23 | static unsigned long oprofile_sdb_blocks = DEFAULT_SDB_BLOCKS; | 24 | static unsigned long oprofile_sdb_blocks = DEFAULT_SDB_BLOCKS; |
24 | 25 | ||
25 | static unsigned long oprofile_hwsampler; | 26 | static int hwsampler_file; |
27 | static int hwsampler_running; /* start_mutex must be held to change */ | ||
28 | |||
29 | static struct oprofile_operations timer_ops; | ||
26 | 30 | ||
27 | static int oprofile_hwsampler_start(void) | 31 | static int oprofile_hwsampler_start(void) |
28 | { | 32 | { |
29 | int retval; | 33 | int retval; |
30 | 34 | ||
35 | hwsampler_running = hwsampler_file; | ||
36 | |||
37 | if (!hwsampler_running) | ||
38 | return timer_ops.start(); | ||
39 | |||
31 | retval = hwsampler_allocate(oprofile_sdbt_blocks, oprofile_sdb_blocks); | 40 | retval = hwsampler_allocate(oprofile_sdbt_blocks, oprofile_sdb_blocks); |
32 | if (retval) | 41 | if (retval) |
33 | return retval; | 42 | return retval; |
@@ -41,25 +50,20 @@ static int oprofile_hwsampler_start(void) | |||
41 | 50 | ||
42 | static void oprofile_hwsampler_stop(void) | 51 | static void oprofile_hwsampler_stop(void) |
43 | { | 52 | { |
53 | if (!hwsampler_running) { | ||
54 | timer_ops.stop(); | ||
55 | return; | ||
56 | } | ||
57 | |||
44 | hwsampler_stop_all(); | 58 | hwsampler_stop_all(); |
45 | hwsampler_deallocate(); | 59 | hwsampler_deallocate(); |
46 | return; | 60 | return; |
47 | } | 61 | } |
48 | 62 | ||
49 | int 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 | |||
59 | static ssize_t hwsampler_read(struct file *file, char __user *buf, | 63 | static ssize_t hwsampler_read(struct file *file, char __user *buf, |
60 | size_t count, loff_t *offset) | 64 | size_t count, loff_t *offset) |
61 | { | 65 | { |
62 | return oprofilefs_ulong_to_user(oprofile_hwsampler, buf, count, offset); | 66 | return oprofilefs_ulong_to_user(hwsampler_file, buf, count, offset); |
63 | } | 67 | } |
64 | 68 | ||
65 | static ssize_t hwsampler_write(struct file *file, char const __user *buf, | 69 | 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, | |||
75 | if (retval) | 79 | if (retval) |
76 | return retval; | 80 | return retval; |
77 | 81 | ||
78 | if (oprofile_hwsampler == val) | 82 | if (oprofile_started) |
79 | return -EINVAL; | 83 | /* |
80 | 84 | * save to do without locking as we set | |
81 | retval = oprofile_set_hwsampler(val); | 85 | * hwsampler_running in start() when start_mutex is |
86 | * held | ||
87 | */ | ||
88 | return -EBUSY; | ||
82 | 89 | ||
83 | if (retval) | 90 | hwsampler_file = val; |
84 | return retval; | ||
85 | 91 | ||
86 | oprofile_hwsampler = val; | ||
87 | return count; | 92 | return count; |
88 | } | 93 | } |
89 | 94 | ||
@@ -98,7 +103,7 @@ static int oprofile_create_hwsampling_files(struct super_block *sb, | |||
98 | struct dentry *hw_dir; | 103 | struct dentry *hw_dir; |
99 | 104 | ||
100 | /* reinitialize default values */ | 105 | /* reinitialize default values */ |
101 | oprofile_hwsampler = 1; | 106 | hwsampler_file = 1; |
102 | 107 | ||
103 | hw_dir = oprofilefs_mkdir(sb, root, "hwsampling"); | 108 | hw_dir = oprofilefs_mkdir(sb, root, "hwsampling"); |
104 | if (!hw_dir) | 109 | if (!hw_dir) |
@@ -125,7 +130,6 @@ int oprofile_hwsampler_init(struct oprofile_operations* ops) | |||
125 | /* | 130 | /* |
126 | * create hwsampler files only if hwsampler_setup() succeeds. | 131 | * create hwsampler files only if hwsampler_setup() succeeds. |
127 | */ | 132 | */ |
128 | ops->create_files = oprofile_create_hwsampling_files; | ||
129 | oprofile_min_interval = hwsampler_query_min_interval(); | 133 | oprofile_min_interval = hwsampler_query_min_interval(); |
130 | if (oprofile_min_interval < 0) { | 134 | if (oprofile_min_interval < 0) { |
131 | oprofile_min_interval = 0; | 135 | oprofile_min_interval = 0; |
@@ -136,11 +140,23 @@ int oprofile_hwsampler_init(struct oprofile_operations* ops) | |||
136 | oprofile_max_interval = 0; | 140 | oprofile_max_interval = 0; |
137 | return -ENODEV; | 141 | return -ENODEV; |
138 | } | 142 | } |
139 | oprofile_arch_set_hwsampler(ops); | 143 | |
144 | if (oprofile_timer_init(ops)) | ||
145 | return -ENODEV; | ||
146 | |||
147 | printk(KERN_INFO "oprofile: using hardware sampling\n"); | ||
148 | |||
149 | memcpy(&timer_ops, ops, sizeof(timer_ops)); | ||
150 | |||
151 | ops->start = oprofile_hwsampler_start; | ||
152 | ops->stop = oprofile_hwsampler_stop; | ||
153 | ops->create_files = oprofile_create_hwsampling_files; | ||
154 | |||
140 | return 0; | 155 | return 0; |
141 | } | 156 | } |
142 | 157 | ||
143 | void oprofile_hwsampler_exit(void) | 158 | void oprofile_hwsampler_exit(void) |
144 | { | 159 | { |
160 | oprofile_timer_exit(); | ||
145 | hwsampler_shutdown(); | 161 | hwsampler_shutdown(); |
146 | } | 162 | } |
diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c index f6b3f724f590..059b44b9f171 100644 --- a/arch/s390/oprofile/init.c +++ b/arch/s390/oprofile/init.c | |||
@@ -11,7 +11,6 @@ | |||
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> | ||
15 | 14 | ||
16 | extern int oprofile_hwsampler_init(struct oprofile_operations* ops); | 15 | extern int oprofile_hwsampler_init(struct oprofile_operations* ops); |
17 | extern void oprofile_hwsampler_exit(void); | 16 | extern void oprofile_hwsampler_exit(void); |
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index 43b01daa91e1..f9bda64fcd1b 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c | |||
@@ -239,38 +239,6 @@ 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 | ||
243 | int 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 | |||
268 | out: | ||
269 | mutex_unlock(&start_mutex); | ||
270 | return err; | ||
271 | } | ||
272 | #endif /* CONFIG_HAVE_HWSAMPLER */ | ||
273 | |||
274 | static int __init oprofile_init(void) | 242 | static int __init oprofile_init(void) |
275 | { | 243 | { |
276 | int err; | 244 | int err; |
diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h index 5a6ceb1954a2..177b73de5e5f 100644 --- a/drivers/oprofile/oprof.h +++ b/drivers/oprofile/oprof.h | |||
@@ -35,9 +35,7 @@ struct dentry; | |||
35 | 35 | ||
36 | void oprofile_create_files(struct super_block *sb, struct dentry *root); | 36 | void oprofile_create_files(struct super_block *sb, struct dentry *root); |
37 | int oprofile_timer_init(struct oprofile_operations *ops); | 37 | int oprofile_timer_init(struct oprofile_operations *ops); |
38 | int __oprofile_timer_init(struct oprofile_operations *ops); | ||
39 | void oprofile_timer_exit(void); | 38 | void oprofile_timer_exit(void); |
40 | void __oprofile_timer_exit(void); | ||
41 | 39 | ||
42 | int oprofile_set_ulong(unsigned long *addr, unsigned long val); | 40 | int oprofile_set_ulong(unsigned long *addr, unsigned long val); |
43 | int oprofile_set_timeout(unsigned long time); | 41 | int oprofile_set_timeout(unsigned long time); |
diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c index 0099a458fd37..3ef44624f510 100644 --- a/drivers/oprofile/timer_int.c +++ b/drivers/oprofile/timer_int.c | |||
@@ -97,13 +97,14 @@ static struct notifier_block __refdata oprofile_cpu_notifier = { | |||
97 | .notifier_call = oprofile_cpu_notify, | 97 | .notifier_call = oprofile_cpu_notify, |
98 | }; | 98 | }; |
99 | 99 | ||
100 | int __oprofile_timer_init(struct oprofile_operations *ops) | 100 | int 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; | ||
107 | ops->setup = NULL; | 108 | ops->setup = NULL; |
108 | ops->shutdown = NULL; | 109 | ops->shutdown = NULL; |
109 | ops->start = oprofile_hrtimer_start; | 110 | ops->start = oprofile_hrtimer_start; |
@@ -112,17 +113,7 @@ int __oprofile_timer_init(struct oprofile_operations *ops) | |||
112 | return 0; | 113 | return 0; |
113 | } | 114 | } |
114 | 115 | ||
115 | int __init oprofile_timer_init(struct oprofile_operations *ops) | 116 | void oprofile_timer_exit(void) |
116 | { | ||
117 | return __oprofile_timer_init(ops); | ||
118 | } | ||
119 | |||
120 | void __oprofile_timer_exit(void) | ||
121 | { | 117 | { |
122 | unregister_hotcpu_notifier(&oprofile_cpu_notifier); | 118 | unregister_hotcpu_notifier(&oprofile_cpu_notifier); |
123 | } | 119 | } |
124 | |||
125 | void __exit oprofile_timer_exit(void) | ||
126 | { | ||
127 | __oprofile_timer_exit(); | ||
128 | } | ||
diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h index b517d869e1ad..7f5cfd3b37dd 100644 --- a/include/linux/oprofile.h +++ b/include/linux/oprofile.h | |||
@@ -91,27 +91,6 @@ int oprofile_arch_init(struct oprofile_operations * ops); | |||
91 | */ | 91 | */ |
92 | void oprofile_arch_exit(void); | 92 | void oprofile_arch_exit(void); |
93 | 93 | ||
94 | #ifdef CONFIG_HAVE_HWSAMPLER | ||
95 | /** | ||
96 | * setup hardware sampler for oprofiling. | ||
97 | */ | ||
98 | |||
99 | int oprofile_set_hwsampler(unsigned long); | ||
100 | |||
101 | /** | ||
102 | * hardware sampler module initialization for the s390 arch | ||
103 | */ | ||
104 | |||
105 | int oprofile_arch_set_hwsampler(struct oprofile_operations *ops); | ||
106 | |||
107 | /** | ||
108 | * Add an s390 hardware sample. | ||
109 | */ | ||
110 | void 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 | |||
115 | /** | 94 | /** |
116 | * Add a sample. This may be called from any context. | 95 | * Add a sample. This may be called from any context. |
117 | */ | 96 | */ |