]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/oprofile/oprof.c
Merge commit 'v2.6.27-rc8' into oprofile
[linux-2.6-omap-h63xx.git] / 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 static unsigned long is_setup;
26 static void switch_worker(struct work_struct *work);
27 static DECLARE_DELAYED_WORK(switch_work, switch_worker);
28 static DEFINE_MUTEX(start_mutex);
29  
30 struct oprofile_operations oprofile_ops;
31
32 unsigned long timeout_jiffies;
33 unsigned long oprofile_started;
34 unsigned long backtrace_depth;
35 /* Multiplexing defaults at 1 msec*/
36
37 /* timer
38    0 - use performance monitoring hardware if available
39    1 - use the timer int mechanism regardless
40  */
41 static int timer = 0;
42
43 int oprofile_setup(void)
44 {
45         int err;
46  
47         mutex_lock(&start_mutex);
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          */
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         }
76 do_generic:
77         if ((err = sync_start()))
78                 goto out3;
79
80 post_sync:
81         is_setup = 1;
82         mutex_unlock(&start_mutex);
83         return 0;
84  
85 out3:
86         if (oprofile_ops.shutdown)
87                 oprofile_ops.shutdown();
88 out2:
89         free_event_buffer();
90 out1:
91         free_cpu_buffers();
92 out:
93         mutex_unlock(&start_mutex);
94         return err;
95 }
96
97 static void start_switch_worker(void)
98 {
99         schedule_delayed_work(&switch_work, timeout_jiffies);
100 }
101
102 static void switch_worker(struct work_struct *work)
103 {
104         if (!oprofile_ops.switch_events())
105                 start_switch_worker();
106 }
107
108 /* Actually start profiling (echo 1>/dev/oprofile/enable) */
109 int oprofile_start(void)
110 {
111         int err = -EINVAL;
112  
113         mutex_lock(&start_mutex);
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
127         if (oprofile_ops.switch_events)
128                 start_switch_worker();
129
130         oprofile_started = 1;
131 out:
132         mutex_unlock(&start_mutex);
133         return err;
134 }
135
136  
137 /* echo 0>/dev/oprofile/enable */
138 void oprofile_stop(void)
139 {
140         mutex_lock(&start_mutex);
141         if (!oprofile_started)
142                 goto out;
143         oprofile_ops.stop();
144         oprofile_started = 0;
145         cancel_delayed_work_sync(&switch_work);
146         /* wake up the daemon to read what remains */
147         wake_up_buffer_waiter();
148 out:
149         mutex_unlock(&start_mutex);
150 }
151
152
153 void oprofile_shutdown(void)
154 {
155         mutex_lock(&start_mutex);
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         }
167 do_generic:
168         sync_stop();
169 post_sync:
170         if (oprofile_ops.shutdown)
171                 oprofile_ops.shutdown();
172         is_setup = 0;
173         free_event_buffer();
174         free_cpu_buffers();
175         mutex_unlock(&start_mutex);
176 }
177
178 /* User inputs in ms, converts to jiffies */
179 int 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
199 out:
200         mutex_unlock(&start_mutex);
201         return err;
202
203 }
204
205 int oprofile_set_backtrace(unsigned long val)
206 {
207         int err = 0;
208
209         mutex_lock(&start_mutex);
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
223 out:
224         mutex_unlock(&start_mutex);
225         return err;
226 }
227
228 static void __init oprofile_switch_timer_init(void)
229 {
230         timeout_jiffies = msecs_to_jiffies(1);
231 }
232
233 static int __init oprofile_init(void)
234 {
235         int err;
236
237         oprofile_switch_timer_init();
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
253 static void __exit oprofile_exit(void)
254 {
255         oprofilefs_unregister();
256         oprofile_arch_exit();
257 }
258
259  
260 module_init(oprofile_init);
261 module_exit(oprofile_exit);
262
263 module_param_named(timer, timer, int, 0644);
264 MODULE_PARM_DESC(timer, "force use of timer interrupt");
265  
266 MODULE_LICENSE("GPL");
267 MODULE_AUTHOR("John Levon <levon@movementarian.org>");
268 MODULE_DESCRIPTION("OProfile system profiler");