oprofile: Rename variable timeout_jiffies and move to oprofile_files.c
[safe/jmp/linux-2.6] / drivers / oprofile / oprof.c
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>
15 #include <linux/workqueue.h>
16 #include <linux/time.h>
17 #include <asm/mutex.h>
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"
24
25 struct oprofile_operations oprofile_ops;
26
27 unsigned long oprofile_started;
28 unsigned long oprofile_backtrace_depth;
29 static unsigned long is_setup;
30 static DEFINE_MUTEX(start_mutex);
31
32 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
33
34 static void switch_worker(struct work_struct *work);
35 static DECLARE_DELAYED_WORK(switch_work, switch_worker);
36 #define TIME_SLICE_DEFAULT              1
37
38 #endif
39
40 /* timer
41    0 - use performance monitoring hardware if available
42    1 - use the timer int mechanism regardless
43  */
44 static int timer = 0;
45
46 int oprofile_setup(void)
47 {
48         int err;
49
50         mutex_lock(&start_mutex);
51
52         if ((err = alloc_cpu_buffers()))
53                 goto out;
54
55         if ((err = alloc_event_buffer()))
56                 goto out1;
57
58         if (oprofile_ops.setup && (err = oprofile_ops.setup()))
59                 goto out2;
60
61         /* Note even though this starts part of the
62          * profiling overhead, it's necessary to prevent
63          * us missing task deaths and eventually oopsing
64          * when trying to process the event buffer.
65          */
66         if (oprofile_ops.sync_start) {
67                 int sync_ret = oprofile_ops.sync_start();
68                 switch (sync_ret) {
69                 case 0:
70                         goto post_sync;
71                 case 1:
72                         goto do_generic;
73                 case -1:
74                         goto out3;
75                 default:
76                         goto out3;
77                 }
78         }
79 do_generic:
80         if ((err = sync_start()))
81                 goto out3;
82
83 post_sync:
84         is_setup = 1;
85         mutex_unlock(&start_mutex);
86         return 0;
87
88 out3:
89         if (oprofile_ops.shutdown)
90                 oprofile_ops.shutdown();
91 out2:
92         free_event_buffer();
93 out1:
94         free_cpu_buffers();
95 out:
96         mutex_unlock(&start_mutex);
97         return err;
98 }
99
100 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
101
102 static void start_switch_worker(void)
103 {
104         schedule_delayed_work(&switch_work, oprofile_time_slice);
105 }
106
107 static void switch_worker(struct work_struct *work)
108 {
109         if (!oprofile_ops.switch_events())
110                 start_switch_worker();
111 }
112
113 #endif
114
115 /* Actually start profiling (echo 1>/dev/oprofile/enable) */
116 int oprofile_start(void)
117 {
118         int err = -EINVAL;
119
120         mutex_lock(&start_mutex);
121
122         if (!is_setup)
123                 goto out;
124
125         err = 0;
126
127         if (oprofile_started)
128                 goto out;
129
130         oprofile_reset_stats();
131
132         if ((err = oprofile_ops.start()))
133                 goto out;
134
135 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
136         if (oprofile_ops.switch_events)
137                 start_switch_worker();
138 #endif
139
140         oprofile_started = 1;
141 out:
142         mutex_unlock(&start_mutex);
143         return err;
144 }
145
146
147 /* echo 0>/dev/oprofile/enable */
148 void oprofile_stop(void)
149 {
150         mutex_lock(&start_mutex);
151         if (!oprofile_started)
152                 goto out;
153         oprofile_ops.stop();
154         oprofile_started = 0;
155
156 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
157         cancel_delayed_work_sync(&switch_work);
158 #endif
159
160         /* wake up the daemon to read what remains */
161         wake_up_buffer_waiter();
162 out:
163         mutex_unlock(&start_mutex);
164 }
165
166
167 void oprofile_shutdown(void)
168 {
169         mutex_lock(&start_mutex);
170         if (oprofile_ops.sync_stop) {
171                 int sync_ret = oprofile_ops.sync_stop();
172                 switch (sync_ret) {
173                 case 0:
174                         goto post_sync;
175                 case 1:
176                         goto do_generic;
177                 default:
178                         goto post_sync;
179                 }
180         }
181 do_generic:
182         sync_stop();
183 post_sync:
184         if (oprofile_ops.shutdown)
185                 oprofile_ops.shutdown();
186         is_setup = 0;
187         free_event_buffer();
188         free_cpu_buffers();
189         mutex_unlock(&start_mutex);
190 }
191
192 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
193
194 /* User inputs in ms, converts to jiffies */
195 int oprofile_set_timeout(unsigned long val_msec)
196 {
197         int err = 0;
198         unsigned long time_slice;
199
200         mutex_lock(&start_mutex);
201
202         if (oprofile_started) {
203                 err = -EBUSY;
204                 goto out;
205         }
206
207         if (!oprofile_ops.switch_events) {
208                 err = -EINVAL;
209                 goto out;
210         }
211
212         time_slice = msecs_to_jiffies(val_msec);
213         if (time_slice == MAX_JIFFY_OFFSET) {
214                 err = -EINVAL;
215                 goto out;
216         }
217
218         oprofile_time_slice = time_slice;
219
220 out:
221         mutex_unlock(&start_mutex);
222         return err;
223
224 }
225
226 #endif
227
228 int oprofile_set_backtrace(unsigned long val)
229 {
230         int err = 0;
231
232         mutex_lock(&start_mutex);
233
234         if (oprofile_started) {
235                 err = -EBUSY;
236                 goto out;
237         }
238
239         if (!oprofile_ops.backtrace) {
240                 err = -EINVAL;
241                 goto out;
242         }
243
244         oprofile_backtrace_depth = val;
245
246 out:
247         mutex_unlock(&start_mutex);
248         return err;
249 }
250
251 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
252
253 static void __init oprofile_multiplexing_init(void)
254 {
255         oprofile_time_slice = msecs_to_jiffies(TIME_SLICE_DEFAULT);
256 }
257
258 #endif
259
260 static int __init oprofile_init(void)
261 {
262         int err;
263
264 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
265         oprofile_multiplexing_init();
266 #endif
267
268         err = oprofile_arch_init(&oprofile_ops);
269
270         if (err < 0 || timer) {
271                 printk(KERN_INFO "oprofile: using timer interrupt.\n");
272                 oprofile_timer_init(&oprofile_ops);
273         }
274
275         err = oprofilefs_register();
276         if (err)
277                 oprofile_arch_exit();
278
279         return err;
280 }
281
282
283 static void __exit oprofile_exit(void)
284 {
285         oprofilefs_unregister();
286         oprofile_arch_exit();
287 }
288
289
290 module_init(oprofile_init);
291 module_exit(oprofile_exit);
292
293 module_param_named(timer, timer, int, 0644);
294 MODULE_PARM_DESC(timer, "force use of timer interrupt");
295
296 MODULE_LICENSE("GPL");
297 MODULE_AUTHOR("John Levon <levon@movementarian.org>");
298 MODULE_DESCRIPTION("OProfile system profiler");