Commit a0d76247e07abd14968adc4486aaa8e270e9c209
1 parent
997dbb4967
Exists in
master
and in
4 other branches
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>
Showing 6 changed files with 41 additions and 90 deletions Side-by-side Diff
arch/s390/oprofile/hwsampler_files.c
... | ... | @@ -8,6 +8,7 @@ |
8 | 8 | #include <linux/errno.h> |
9 | 9 | #include <linux/fs.h> |
10 | 10 | |
11 | +#include "../../../drivers/oprofile/oprof.h" | |
11 | 12 | #include "hwsampler.h" |
12 | 13 | |
13 | 14 | #define DEFAULT_INTERVAL 4096 |
14 | 15 | |
15 | 16 | |
... | ... | @@ -22,12 +23,20 @@ |
22 | 23 | static unsigned long oprofile_sdbt_blocks = DEFAULT_SDBT_BLOCKS; |
23 | 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 */ | |
26 | 28 | |
29 | +static struct oprofile_operations timer_ops; | |
30 | + | |
27 | 31 | static int oprofile_hwsampler_start(void) |
28 | 32 | { |
29 | 33 | int retval; |
30 | 34 | |
35 | + hwsampler_running = hwsampler_file; | |
36 | + | |
37 | + if (!hwsampler_running) | |
38 | + return timer_ops.start(); | |
39 | + | |
31 | 40 | retval = hwsampler_allocate(oprofile_sdbt_blocks, oprofile_sdb_blocks); |
32 | 41 | if (retval) |
33 | 42 | return retval; |
34 | 43 | |
35 | 44 | |
... | ... | @@ -41,25 +50,20 @@ |
41 | 50 | |
42 | 51 | static void oprofile_hwsampler_stop(void) |
43 | 52 | { |
53 | + if (!hwsampler_running) { | |
54 | + timer_ops.stop(); | |
55 | + return; | |
56 | + } | |
57 | + | |
44 | 58 | hwsampler_stop_all(); |
45 | 59 | hwsampler_deallocate(); |
46 | 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 | 63 | static ssize_t hwsampler_read(struct file *file, char __user *buf, |
60 | 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 | 69 | static ssize_t hwsampler_write(struct file *file, char const __user *buf, |
66 | 70 | |
67 | 71 | |
... | ... | @@ -75,15 +79,16 @@ |
75 | 79 | if (retval) |
76 | 80 | return retval; |
77 | 81 | |
78 | - if (oprofile_hwsampler == val) | |
79 | - return -EINVAL; | |
82 | + if (oprofile_started) | |
83 | + /* | |
84 | + * save to do without locking as we set | |
85 | + * hwsampler_running in start() when start_mutex is | |
86 | + * held | |
87 | + */ | |
88 | + return -EBUSY; | |
80 | 89 | |
81 | - retval = oprofile_set_hwsampler(val); | |
90 | + hwsampler_file = val; | |
82 | 91 | |
83 | - if (retval) | |
84 | - return retval; | |
85 | - | |
86 | - oprofile_hwsampler = val; | |
87 | 92 | return count; |
88 | 93 | } |
89 | 94 | |
... | ... | @@ -98,7 +103,7 @@ |
98 | 103 | struct dentry *hw_dir; |
99 | 104 | |
100 | 105 | /* reinitialize default values */ |
101 | - oprofile_hwsampler = 1; | |
106 | + hwsampler_file = 1; | |
102 | 107 | |
103 | 108 | hw_dir = oprofilefs_mkdir(sb, root, "hwsampling"); |
104 | 109 | if (!hw_dir) |
... | ... | @@ -125,7 +130,6 @@ |
125 | 130 | /* |
126 | 131 | * create hwsampler files only if hwsampler_setup() succeeds. |
127 | 132 | */ |
128 | - ops->create_files = oprofile_create_hwsampling_files; | |
129 | 133 | oprofile_min_interval = hwsampler_query_min_interval(); |
130 | 134 | if (oprofile_min_interval < 0) { |
131 | 135 | oprofile_min_interval = 0; |
132 | 136 | |
... | ... | @@ -136,12 +140,24 @@ |
136 | 140 | oprofile_max_interval = 0; |
137 | 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 | 155 | return 0; |
141 | 156 | } |
142 | 157 | |
143 | 158 | void oprofile_hwsampler_exit(void) |
144 | 159 | { |
160 | + oprofile_timer_exit(); | |
145 | 161 | hwsampler_shutdown(); |
146 | 162 | } |
arch/s390/oprofile/init.c
drivers/oprofile/oprof.c
... | ... | @@ -239,38 +239,6 @@ |
239 | 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 | 242 | static int __init oprofile_init(void) |
275 | 243 | { |
276 | 244 | int err; |
drivers/oprofile/oprof.h
... | ... | @@ -35,9 +35,7 @@ |
35 | 35 | |
36 | 36 | void oprofile_create_files(struct super_block *sb, struct dentry *root); |
37 | 37 | int oprofile_timer_init(struct oprofile_operations *ops); |
38 | -int __oprofile_timer_init(struct oprofile_operations *ops); | |
39 | 38 | void oprofile_timer_exit(void); |
40 | -void __oprofile_timer_exit(void); | |
41 | 39 | |
42 | 40 | int oprofile_set_ulong(unsigned long *addr, unsigned long val); |
43 | 41 | int oprofile_set_timeout(unsigned long time); |
drivers/oprofile/timer_int.c
... | ... | @@ -97,13 +97,14 @@ |
97 | 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 | 102 | int rc; |
103 | 103 | |
104 | 104 | rc = register_hotcpu_notifier(&oprofile_cpu_notifier); |
105 | 105 | if (rc) |
106 | 106 | return rc; |
107 | + ops->create_files = NULL; | |
107 | 108 | ops->setup = NULL; |
108 | 109 | ops->shutdown = NULL; |
109 | 110 | ops->start = oprofile_hrtimer_start; |
110 | 111 | |
111 | 112 | |
... | ... | @@ -112,18 +113,8 @@ |
112 | 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 | { |
117 | - return __oprofile_timer_init(ops); | |
118 | -} | |
119 | - | |
120 | -void __oprofile_timer_exit(void) | |
121 | -{ | |
122 | 118 | unregister_hotcpu_notifier(&oprofile_cpu_notifier); |
123 | -} | |
124 | - | |
125 | -void __exit oprofile_timer_exit(void) | |
126 | -{ | |
127 | - __oprofile_timer_exit(); | |
128 | 119 | } |
include/linux/oprofile.h
... | ... | @@ -91,27 +91,6 @@ |
91 | 91 | */ |
92 | 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 | 95 | * Add a sample. This may be called from any context. |
117 | 96 | */ |