Return bool from reset_alarm_* apis.
[akaros.git] / kern / src / 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 <vfs.h>
11 #include <kfs.h>
12 #include <slab.h>
13 #include <kmalloc.h>
14 #include <kref.h>
15 #include <string.h>
16 #include <stdio.h>
17 #include <assert.h>
18 #include <error.h>
19 #include <cpio.h>
20 #include <pmap.h>
21 #include <smp.h>
22 #include <ip.h>
23
24 #include "oprof.h"
25 #include "event_buffer.h"
26 #include "cpu_buffer.h"
27 #include "buffer_sync.h"
28 #include "oprofile_stats.h"
29
30 struct oprofile_operations oprofile_ops;
31
32 unsigned long oprofile_started;
33 unsigned long oprofile_backtrace_depth;
34 static unsigned long is_setup;
35 static DEFINE_MUTEX(start_mutex);
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 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
98
99 static void switch_worker(void)
100
101 static void start_switch_worker(void)
102 {
103 //      if (oprofile_ops.switch_events)
104 //              schedule_delayed_work(&switch_work, oprofile_time_slice);
105 }
106
107 static void stop_switch_worker(void)
108 {
109 //      cancel_delayed_work_sync(&switch_work);
110 }
111
112 static void switch_worker(struct work_struct *work)
113 {
114         if (oprofile_ops.switch_events())
115                 return;
116
117         atomic_inc(&oprofile_stats.multiplex_counter);
118         start_switch_worker();
119 }
120
121 /* User inputs in ms, converts to jiffies */
122 int oprofile_set_timeout(unsigned long val_msec)
123 {
124         int err = 0;
125         unsigned long time_slice;
126
127         mutex_lock(&start_mutex);
128
129         if (oprofile_started) {
130                 err = -EBUSY;
131                 goto out;
132         }
133
134         if (!oprofile_ops.switch_events) {
135                 err = -EINVAL;
136                 goto out;
137         }
138
139         time_slice = msecs_to_jiffies(val_msec);
140         if (time_slice == MAX_JIFFY_OFFSET) {
141                 err = -EINVAL;
142                 goto out;
143         }
144
145         oprofile_time_slice = time_slice;
146
147 out:
148         mutex_unlock(&start_mutex);
149         return err;
150
151 }
152
153 #else
154
155 static inline void start_switch_worker(void) { }
156 static inline void stop_switch_worker(void) { }
157
158 #endif
159
160 /* Actually start profiling (echo 1>/dev/oprofile/enable) */
161 int oprofile_start(void)
162 {
163         int err = -EINVAL;
164
165         mutex_lock(&start_mutex);
166
167         if (!is_setup)
168                 goto out;
169
170         err = 0;
171
172         if (oprofile_started)
173                 goto out;
174
175         oprofile_reset_stats();
176
177         if ((err = oprofile_ops.start()))
178                 goto out;
179
180         start_switch_worker();
181
182         oprofile_started = 1;
183 out:
184         mutex_unlock(&start_mutex);
185         return err;
186 }
187
188
189 /* echo 0>/dev/oprofile/enable */
190 void oprofile_stop(void)
191 {
192         mutex_lock(&start_mutex);
193         if (!oprofile_started)
194                 goto out;
195         oprofile_ops.stop();
196         oprofile_started = 0;
197
198         stop_switch_worker();
199
200         /* wake up the daemon to read what remains */
201         wake_up_buffer_waiter();
202 out:
203         mutex_unlock(&start_mutex);
204 }
205
206
207 void oprofile_shutdown(void)
208 {
209         mutex_lock(&start_mutex);
210         if (oprofile_ops.sync_stop) {
211                 int sync_ret = oprofile_ops.sync_stop();
212                 switch (sync_ret) {
213                 case 0:
214                         goto post_sync;
215                 case 1:
216                         goto do_generic;
217                 default:
218                         goto post_sync;
219                 }
220         }
221 do_generic:
222         sync_stop();
223 post_sync:
224         if (oprofile_ops.shutdown)
225                 oprofile_ops.shutdown();
226         is_setup = 0;
227         free_event_buffer();
228         free_cpu_buffers();
229         mutex_unlock(&start_mutex);
230 }
231
232 int oprofile_set_ulong(unsigned long *addr, unsigned long val)
233 {
234         int err = -EBUSY;
235
236         mutex_lock(&start_mutex);
237         if (!oprofile_started) {
238                 *addr = val;
239                 err = 0;
240         }
241         mutex_unlock(&start_mutex);
242
243         return err;
244 }
245
246 static int timer_mode;
247
248 static int __init oprofile_init(void)
249 {
250         int err;
251
252         /* always init architecture to setup backtrace support */
253         timer_mode = 0;
254         err = oprofile_arch_init(&oprofile_ops);
255         if (!err) {
256                 if (!timer && !oprofilefs_register())
257                         return 0;
258                 oprofile_arch_exit();
259         }
260
261         /* setup timer mode: */
262         timer_mode = 1;
263         /* no nmi timer mode if oprofile.timer is set */
264         if (timer || op_nmi_timer_init(&oprofile_ops)) {
265                 err = oprofile_timer_init(&oprofile_ops);
266                 if (err)
267                         return err;
268         }
269
270         return oprofilefs_register();
271 }
272
273
274 static void __exit oprofile_exit(void)
275 {
276         if (!timer_mode)
277                 oprofile_arch_exit();
278 }
279
280
281 //MODULE_LICENSE("GPL");
282 //MODULE_AUTHOR("John Levon <levon@movementarian.org>");
283 //MODULE_DESCRIPTION("OProfile system profiler");