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 <linux/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_ulong(unsigned long *addr, unsigned long val)
232 mutex_lock(&start_mutex);
233 if (!oprofile_started) {
237 mutex_unlock(&start_mutex);
242 static int timer_mode;
244 static int __init oprofile_init(void)
248 /* always init architecture to setup backtrace support */
250 err = oprofile_arch_init(&oprofile_ops);
252 if (!timer && !oprofilefs_register())
254 oprofile_arch_exit();
257 /* setup timer mode: */
259 /* no nmi timer mode if oprofile.timer is set */
260 if (timer || op_nmi_timer_init(&oprofile_ops)) {
261 err = oprofile_timer_init(&oprofile_ops);
266 return oprofilefs_register();
270 static void __exit oprofile_exit(void)
272 oprofilefs_unregister();
274 oprofile_arch_exit();
278 module_init(oprofile_init);
279 module_exit(oprofile_exit);
281 module_param_named(timer, timer, int, 0644);
282 MODULE_PARM_DESC(timer, "force use of timer interrupt");
284 MODULE_LICENSE("GPL");
285 MODULE_AUTHOR("John Levon <levon@movementarian.org>");
286 MODULE_DESCRIPTION("OProfile system profiler");