4 * @remark Copyright 2002 OProfile authors
5 * @remark Read the file COPYING
7 * @author John Levon <levon@movementarian.org>
9 * Modified by Aravind Menon for Xen
10 * These modifications are:
11 * Copyright (C) 2005 Hewlett-Packard Co.
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/init.h>
17 #include <linux/oprofile.h>
18 #include <linux/moduleparam.h>
19 #include <linux/workqueue.h>
20 #include <linux/time.h>
21 #include <linux/mutex.h>
24 #include "event_buffer.h"
25 #include "cpu_buffer.h"
26 #include "buffer_sync.h"
27 #include "oprofile_stats.h"
29 struct oprofile_operations oprofile_ops;
31 unsigned long oprofile_started;
32 unsigned long oprofile_backtrace_depth;
33 static unsigned long is_setup;
34 static DEFINE_MUTEX(start_mutex);
37 0 - use performance monitoring hardware if available
38 1 - use the timer int mechanism regardless
43 int oprofile_set_active(int active_domains[], unsigned int adomains)
47 if (!oprofile_ops.set_active)
50 mutex_lock(&start_mutex);
51 err = oprofile_ops.set_active(active_domains, adomains);
52 mutex_unlock(&start_mutex);
56 int oprofile_set_passive(int passive_domains[], unsigned int pdomains)
60 if (!oprofile_ops.set_passive)
63 mutex_lock(&start_mutex);
64 err = oprofile_ops.set_passive(passive_domains, pdomains);
65 mutex_unlock(&start_mutex);
70 int oprofile_setup(void)
74 mutex_lock(&start_mutex);
76 if ((err = alloc_cpu_buffers()))
79 if ((err = alloc_event_buffer()))
82 if (oprofile_ops.setup && (err = oprofile_ops.setup()))
85 /* Note even though this starts part of the
86 * profiling overhead, it's necessary to prevent
87 * us missing task deaths and eventually oopsing
88 * when trying to process the event buffer.
90 if (oprofile_ops.sync_start) {
91 int sync_ret = oprofile_ops.sync_start();
104 if ((err = sync_start()))
109 mutex_unlock(&start_mutex);
113 if (oprofile_ops.shutdown)
114 oprofile_ops.shutdown();
120 mutex_unlock(&start_mutex);
124 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
126 static void switch_worker(struct work_struct *work);
127 static DECLARE_DELAYED_WORK(switch_work, switch_worker);
129 static void start_switch_worker(void)
131 if (oprofile_ops.switch_events)
132 schedule_delayed_work(&switch_work, oprofile_time_slice);
135 static void stop_switch_worker(void)
137 cancel_delayed_work_sync(&switch_work);
140 static void switch_worker(struct work_struct *work)
142 if (oprofile_ops.switch_events())
145 atomic_inc(&oprofile_stats.multiplex_counter);
146 start_switch_worker();
149 /* User inputs in ms, converts to jiffies */
150 int oprofile_set_timeout(unsigned long val_msec)
153 unsigned long time_slice;
155 mutex_lock(&start_mutex);
157 if (oprofile_started) {
162 if (!oprofile_ops.switch_events) {
167 time_slice = msecs_to_jiffies(val_msec);
168 if (time_slice == MAX_JIFFY_OFFSET) {
173 oprofile_time_slice = time_slice;
176 mutex_unlock(&start_mutex);
183 static inline void start_switch_worker(void) { }
184 static inline void stop_switch_worker(void) { }
188 /* Actually start profiling (echo 1>/dev/oprofile/enable) */
189 int oprofile_start(void)
193 mutex_lock(&start_mutex);
200 if (oprofile_started)
203 oprofile_reset_stats();
205 if ((err = oprofile_ops.start()))
208 start_switch_worker();
210 oprofile_started = 1;
212 mutex_unlock(&start_mutex);
217 /* echo 0>/dev/oprofile/enable */
218 void oprofile_stop(void)
220 mutex_lock(&start_mutex);
221 if (!oprofile_started)
224 oprofile_started = 0;
226 stop_switch_worker();
228 /* wake up the daemon to read what remains */
229 wake_up_buffer_waiter();
231 mutex_unlock(&start_mutex);
235 void oprofile_shutdown(void)
237 mutex_lock(&start_mutex);
238 if (oprofile_ops.sync_stop) {
239 int sync_ret = oprofile_ops.sync_stop();
252 if (oprofile_ops.shutdown)
253 oprofile_ops.shutdown();
257 mutex_unlock(&start_mutex);
260 int oprofile_set_ulong(unsigned long *addr, unsigned long val)
264 mutex_lock(&start_mutex);
265 if (!oprofile_started) {
269 mutex_unlock(&start_mutex);
274 static int timer_mode;
276 static int __init oprofile_init(void)
280 /* always init architecture to setup backtrace support */
282 err = oprofile_arch_init(&oprofile_ops);
284 if (!timer && !oprofilefs_register())
286 oprofile_arch_exit();
289 /* setup timer mode: */
291 /* no nmi timer mode if oprofile.timer is set */
292 if (timer || op_nmi_timer_init(&oprofile_ops)) {
293 err = oprofile_timer_init(&oprofile_ops);
298 return oprofilefs_register();
302 static void __exit oprofile_exit(void)
304 oprofilefs_unregister();
306 oprofile_arch_exit();
310 module_init(oprofile_init);
311 module_exit(oprofile_exit);
313 module_param_named(timer, timer, int, 0644);
314 MODULE_PARM_DESC(timer, "force use of timer interrupt");
316 MODULE_LICENSE("GPL");
317 MODULE_AUTHOR("John Levon <levon@movementarian.org>");
318 MODULE_DESCRIPTION("OProfile system profiler");