4 * @remark Copyright 2002 OProfile authors
5 * @remark Read the file COPYING
7 * @author John Levon <levon@movementarian.org>
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>
20 #include "event_buffer.h"
21 #include "cpu_buffer.h"
22 #include "buffer_sync.h"
23 #include "oprofile_stats.h"
25 struct oprofile_operations oprofile_ops
;
27 unsigned long oprofile_started
;
28 unsigned long oprofile_backtrace_depth
;
29 static unsigned long is_setup
;
30 static DEFINE_MUTEX(start_mutex
);
32 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
34 static void switch_worker(struct work_struct
*work
);
35 static DECLARE_DELAYED_WORK(switch_work
, switch_worker
);
36 unsigned long timeout_jiffies
;
37 #define MULTIPLEXING_TIMER_DEFAULT 1
42 0 - use performance monitoring hardware if available
43 1 - use the timer int mechanism regardless
47 int oprofile_setup(void)
51 mutex_lock(&start_mutex
);
53 if ((err
= alloc_cpu_buffers()))
56 if ((err
= alloc_event_buffer()))
59 if (oprofile_ops
.setup
&& (err
= oprofile_ops
.setup()))
62 /* Note even though this starts part of the
63 * profiling overhead, it's necessary to prevent
64 * us missing task deaths and eventually oopsing
65 * when trying to process the event buffer.
67 if (oprofile_ops
.sync_start
) {
68 int sync_ret
= oprofile_ops
.sync_start();
81 if ((err
= sync_start()))
86 mutex_unlock(&start_mutex
);
90 if (oprofile_ops
.shutdown
)
91 oprofile_ops
.shutdown();
97 mutex_unlock(&start_mutex
);
101 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
103 static void start_switch_worker(void)
105 schedule_delayed_work(&switch_work
, timeout_jiffies
);
108 static void switch_worker(struct work_struct
*work
)
110 if (!oprofile_ops
.switch_events())
111 start_switch_worker();
116 /* Actually start profiling (echo 1>/dev/oprofile/enable) */
117 int oprofile_start(void)
121 mutex_lock(&start_mutex
);
128 if (oprofile_started
)
131 oprofile_reset_stats();
133 if ((err
= oprofile_ops
.start()))
136 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
137 if (oprofile_ops
.switch_events
)
138 start_switch_worker();
141 oprofile_started
= 1;
143 mutex_unlock(&start_mutex
);
148 /* echo 0>/dev/oprofile/enable */
149 void oprofile_stop(void)
151 mutex_lock(&start_mutex
);
152 if (!oprofile_started
)
155 oprofile_started
= 0;
157 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
158 cancel_delayed_work_sync(&switch_work
);
161 /* wake up the daemon to read what remains */
162 wake_up_buffer_waiter();
164 mutex_unlock(&start_mutex
);
168 void oprofile_shutdown(void)
170 mutex_lock(&start_mutex
);
171 if (oprofile_ops
.sync_stop
) {
172 int sync_ret
= oprofile_ops
.sync_stop();
185 if (oprofile_ops
.shutdown
)
186 oprofile_ops
.shutdown();
190 mutex_unlock(&start_mutex
);
193 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
195 /* User inputs in ms, converts to jiffies */
196 int oprofile_set_timeout(unsigned long val_msec
)
199 unsigned long time_slice
;
201 mutex_lock(&start_mutex
);
203 if (oprofile_started
) {
208 if (!oprofile_ops
.switch_events
) {
213 time_slice
= msecs_to_jiffies(val_msec
);
214 if (time_slice
== MAX_JIFFY_OFFSET
) {
219 timeout_jiffies
= time_slice
;
222 mutex_unlock(&start_mutex
);
229 int oprofile_set_backtrace(unsigned long val
)
233 mutex_lock(&start_mutex
);
235 if (oprofile_started
) {
240 if (!oprofile_ops
.backtrace
) {
245 oprofile_backtrace_depth
= val
;
248 mutex_unlock(&start_mutex
);
252 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
254 static void __init
oprofile_multiplexing_init(void)
256 timeout_jiffies
= msecs_to_jiffies(MULTIPLEXING_TIMER_DEFAULT
);
261 static int __init
oprofile_init(void)
265 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
266 oprofile_multiplexing_init();
269 err
= oprofile_arch_init(&oprofile_ops
);
271 if (err
< 0 || timer
) {
272 printk(KERN_INFO
"oprofile: using timer interrupt.\n");
273 oprofile_timer_init(&oprofile_ops
);
276 err
= oprofilefs_register();
278 oprofile_arch_exit();
284 static void __exit
oprofile_exit(void)
286 oprofilefs_unregister();
287 oprofile_arch_exit();
291 module_init(oprofile_init
);
292 module_exit(oprofile_exit
);
294 module_param_named(timer
, timer
, int, 0644);
295 MODULE_PARM_DESC(timer
, "force use of timer interrupt");
297 MODULE_LICENSE("GPL");
298 MODULE_AUTHOR("John Levon <levon@movementarian.org>");
299 MODULE_DESCRIPTION("OProfile system profiler");