]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/oprofile/oprof.c
x86, oprofile: BUG: using smp_processor_id() in preemptible code
[mirror_ubuntu-jammy-kernel.git] / drivers / oprofile / oprof.c
CommitLineData
1da177e4
LT
1/**
2 * @file oprof.c
3 *
4 * @remark Copyright 2002 OProfile authors
5 * @remark Read the file COPYING
6 *
7 * @author John Levon <levon@movementarian.org>
8 */
9
10#include <linux/kernel.h>
11#include <linux/module.h>
12#include <linux/init.h>
13#include <linux/oprofile.h>
14#include <linux/moduleparam.h>
1a960b40
JY
15#include <linux/workqueue.h>
16#include <linux/time.h>
59cc185a 17#include <asm/mutex.h>
1da177e4
LT
18
19#include "oprof.h"
20#include "event_buffer.h"
21#include "cpu_buffer.h"
22#include "buffer_sync.h"
23#include "oprofile_stats.h"
1a960b40
JY
24
25static unsigned long is_setup;
26static void switch_worker(struct work_struct *work);
27static DECLARE_DELAYED_WORK(switch_work, switch_worker);
28static DEFINE_MUTEX(start_mutex);
1da177e4
LT
29
30struct oprofile_operations oprofile_ops;
31
1a960b40 32unsigned long timeout_jiffies;
1da177e4
LT
33unsigned long oprofile_started;
34unsigned long backtrace_depth;
1a960b40 35/* Multiplexing defaults at 1 msec*/
1da177e4
LT
36
37/* timer
38 0 - use performance monitoring hardware if available
39 1 - use the timer int mechanism regardless
40 */
41static int timer = 0;
42
43int oprofile_setup(void)
44{
45 int err;
46
59cc185a 47 mutex_lock(&start_mutex);
1da177e4
LT
48
49 if ((err = alloc_cpu_buffers()))
50 goto out;
51
52 if ((err = alloc_event_buffer()))
53 goto out1;
54
55 if (oprofile_ops.setup && (err = oprofile_ops.setup()))
56 goto out2;
57
58 /* Note even though this starts part of the
59 * profiling overhead, it's necessary to prevent
60 * us missing task deaths and eventually oopsing
61 * when trying to process the event buffer.
62 */
1474855d
BN
63 if (oprofile_ops.sync_start) {
64 int sync_ret = oprofile_ops.sync_start();
65 switch (sync_ret) {
66 case 0:
67 goto post_sync;
68 case 1:
69 goto do_generic;
70 case -1:
71 goto out3;
72 default:
73 goto out3;
74 }
75 }
76do_generic:
1da177e4
LT
77 if ((err = sync_start()))
78 goto out3;
79
1474855d 80post_sync:
1da177e4 81 is_setup = 1;
59cc185a 82 mutex_unlock(&start_mutex);
1da177e4
LT
83 return 0;
84
85out3:
86 if (oprofile_ops.shutdown)
87 oprofile_ops.shutdown();
88out2:
89 free_event_buffer();
90out1:
91 free_cpu_buffers();
92out:
59cc185a 93 mutex_unlock(&start_mutex);
1da177e4
LT
94 return err;
95}
96
1a960b40
JY
97static void start_switch_worker(void)
98{
99 schedule_delayed_work(&switch_work, timeout_jiffies);
100}
101
102static void switch_worker(struct work_struct *work)
103{
104 if (!oprofile_ops.switch_events())
105 start_switch_worker();
106}
1da177e4
LT
107
108/* Actually start profiling (echo 1>/dev/oprofile/enable) */
109int oprofile_start(void)
110{
111 int err = -EINVAL;
112
59cc185a 113 mutex_lock(&start_mutex);
1da177e4
LT
114 if (!is_setup)
115 goto out;
116
117 err = 0;
118
119 if (oprofile_started)
120 goto out;
121
122 oprofile_reset_stats();
123
124 if ((err = oprofile_ops.start()))
125 goto out;
126
1a960b40
JY
127 if (oprofile_ops.switch_events)
128 start_switch_worker();
129
1da177e4
LT
130 oprofile_started = 1;
131out:
59cc185a 132 mutex_unlock(&start_mutex);
1da177e4
LT
133 return err;
134}
135
136
137/* echo 0>/dev/oprofile/enable */
138void oprofile_stop(void)
139{
59cc185a 140 mutex_lock(&start_mutex);
1da177e4
LT
141 if (!oprofile_started)
142 goto out;
143 oprofile_ops.stop();
144 oprofile_started = 0;
1a960b40 145 cancel_delayed_work_sync(&switch_work);
1da177e4
LT
146 /* wake up the daemon to read what remains */
147 wake_up_buffer_waiter();
148out:
59cc185a 149 mutex_unlock(&start_mutex);
1da177e4
LT
150}
151
152
153void oprofile_shutdown(void)
154{
59cc185a 155 mutex_lock(&start_mutex);
1474855d
BN
156 if (oprofile_ops.sync_stop) {
157 int sync_ret = oprofile_ops.sync_stop();
158 switch (sync_ret) {
159 case 0:
160 goto post_sync;
161 case 1:
162 goto do_generic;
163 default:
164 goto post_sync;
165 }
166 }
167do_generic:
1da177e4 168 sync_stop();
1474855d 169post_sync:
1da177e4
LT
170 if (oprofile_ops.shutdown)
171 oprofile_ops.shutdown();
172 is_setup = 0;
173 free_event_buffer();
174 free_cpu_buffers();
59cc185a 175 mutex_unlock(&start_mutex);
1da177e4
LT
176}
177
1a960b40
JY
178/* User inputs in ms, converts to jiffies */
179int oprofile_set_timeout(unsigned long val_msec)
180{
181 int err = 0;
182
183 mutex_lock(&start_mutex);
184
185 if (oprofile_started) {
186 err = -EBUSY;
187 goto out;
188 }
189
190 if (!oprofile_ops.switch_events) {
191 err = -EINVAL;
192 goto out;
193 }
194
195 timeout_jiffies = msecs_to_jiffies(val_msec);
196 if (timeout_jiffies == MAX_JIFFY_OFFSET)
197 timeout_jiffies = msecs_to_jiffies(1);
198
199out:
200 mutex_unlock(&start_mutex);
201 return err;
202
203}
1da177e4
LT
204
205int oprofile_set_backtrace(unsigned long val)
206{
207 int err = 0;
208
59cc185a 209 mutex_lock(&start_mutex);
1da177e4
LT
210
211 if (oprofile_started) {
212 err = -EBUSY;
213 goto out;
214 }
215
216 if (!oprofile_ops.backtrace) {
217 err = -EINVAL;
218 goto out;
219 }
220
221 backtrace_depth = val;
222
223out:
59cc185a 224 mutex_unlock(&start_mutex);
1da177e4
LT
225 return err;
226}
227
1a960b40
JY
228static void __init oprofile_switch_timer_init(void)
229{
230 timeout_jiffies = msecs_to_jiffies(1);
231}
232
1da177e4
LT
233static int __init oprofile_init(void)
234{
235 int err;
236
1a960b40 237 oprofile_switch_timer_init();
1da177e4
LT
238 err = oprofile_arch_init(&oprofile_ops);
239
240 if (err < 0 || timer) {
241 printk(KERN_INFO "oprofile: using timer interrupt.\n");
242 oprofile_timer_init(&oprofile_ops);
243 }
244
245 err = oprofilefs_register();
246 if (err)
247 oprofile_arch_exit();
248
249 return err;
250}
251
252
253static void __exit oprofile_exit(void)
254{
255 oprofilefs_unregister();
256 oprofile_arch_exit();
257}
258
259
260module_init(oprofile_init);
261module_exit(oprofile_exit);
262
263module_param_named(timer, timer, int, 0644);
264MODULE_PARM_DESC(timer, "force use of timer interrupt");
265
266MODULE_LICENSE("GPL");
267MODULE_AUTHOR("John Levon <levon@movementarian.org>");
268MODULE_DESCRIPTION("OProfile system profiler");