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
);
33 0 - use performance monitoring hardware if available
34 1 - use the timer int mechanism regardless
38 int oprofile_setup(void)
42 mutex_lock(&start_mutex
);
44 if ((err
= alloc_cpu_buffers()))
47 if ((err
= alloc_event_buffer()))
50 if (oprofile_ops
.setup
&& (err
= oprofile_ops
.setup()))
53 /* Note even though this starts part of the
54 * profiling overhead, it's necessary to prevent
55 * us missing task deaths and eventually oopsing
56 * when trying to process the event buffer.
58 if (oprofile_ops
.sync_start
) {
59 int sync_ret
= oprofile_ops
.sync_start();
72 if ((err
= sync_start()))
77 mutex_unlock(&start_mutex
);
81 if (oprofile_ops
.shutdown
)
82 oprofile_ops
.shutdown();
88 mutex_unlock(&start_mutex
);
92 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
94 static void switch_worker(struct work_struct
*work
);
95 static DECLARE_DELAYED_WORK(switch_work
, switch_worker
);
97 static void start_switch_worker(void)
99 if (oprofile_ops
.switch_events
)
100 schedule_delayed_work(&switch_work
, oprofile_time_slice
);
103 static void stop_switch_worker(void)
105 cancel_delayed_work_sync(&switch_work
);
108 static void switch_worker(struct work_struct
*work
)
110 if (oprofile_ops
.switch_events())
113 atomic_inc(&oprofile_stats
.multiplex_counter
);
114 start_switch_worker();
117 /* User inputs in ms, converts to jiffies */
118 int oprofile_set_timeout(unsigned long val_msec
)
121 unsigned long time_slice
;
123 mutex_lock(&start_mutex
);
125 if (oprofile_started
) {
130 if (!oprofile_ops
.switch_events
) {
135 time_slice
= msecs_to_jiffies(val_msec
);
136 if (time_slice
== MAX_JIFFY_OFFSET
) {
141 oprofile_time_slice
= time_slice
;
144 mutex_unlock(&start_mutex
);
151 static inline void start_switch_worker(void) { }
152 static inline void stop_switch_worker(void) { }
156 /* Actually start profiling (echo 1>/dev/oprofile/enable) */
157 int oprofile_start(void)
161 mutex_lock(&start_mutex
);
168 if (oprofile_started
)
171 oprofile_reset_stats();
173 if ((err
= oprofile_ops
.start()))
176 start_switch_worker();
178 oprofile_started
= 1;
180 mutex_unlock(&start_mutex
);
185 /* echo 0>/dev/oprofile/enable */
186 void oprofile_stop(void)
188 mutex_lock(&start_mutex
);
189 if (!oprofile_started
)
192 oprofile_started
= 0;
194 stop_switch_worker();
196 /* wake up the daemon to read what remains */
197 wake_up_buffer_waiter();
199 mutex_unlock(&start_mutex
);
203 void oprofile_shutdown(void)
205 mutex_lock(&start_mutex
);
206 if (oprofile_ops
.sync_stop
) {
207 int sync_ret
= oprofile_ops
.sync_stop();
220 if (oprofile_ops
.shutdown
)
221 oprofile_ops
.shutdown();
225 mutex_unlock(&start_mutex
);
228 int oprofile_set_backtrace(unsigned long val
)
232 mutex_lock(&start_mutex
);
234 if (oprofile_started
) {
239 if (!oprofile_ops
.backtrace
) {
244 oprofile_backtrace_depth
= val
;
247 mutex_unlock(&start_mutex
);
251 static int __init
oprofile_init(void)
255 err
= oprofile_arch_init(&oprofile_ops
);
256 if (err
< 0 || timer
) {
257 printk(KERN_INFO
"oprofile: using timer interrupt.\n");
258 err
= oprofile_timer_init(&oprofile_ops
);
262 err
= oprofilefs_register();
268 oprofile_arch_exit();
273 static void __exit
oprofile_exit(void)
275 oprofile_timer_exit();
276 oprofilefs_unregister();
277 oprofile_arch_exit();
281 module_init(oprofile_init
);
282 module_exit(oprofile_exit
);
284 module_param_named(timer
, timer
, int, 0644);
285 MODULE_PARM_DESC(timer
, "force use of timer interrupt");
287 MODULE_LICENSE("GPL");
288 MODULE_AUTHOR("John Levon <levon@movementarian.org>");
289 MODULE_DESCRIPTION("OProfile system profiler");