Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
oprof.c
Go to the documentation of this file.
1 
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>
18 
19 #include "oprof.h"
20 #include "event_buffer.h"
21 #include "cpu_buffer.h"
22 #include "buffer_sync.h"
23 #include "oprofile_stats.h"
24 
26 
27 unsigned long oprofile_started;
29 static unsigned long is_setup;
30 static DEFINE_MUTEX(start_mutex);
31 
32 /* timer
33  0 - use performance monitoring hardware if available
34  1 - use the timer int mechanism regardless
35  */
36 static int timer = 0;
37 
38 int oprofile_setup(void)
39 {
40  int err;
41 
42  mutex_lock(&start_mutex);
43 
44  if ((err = alloc_cpu_buffers()))
45  goto out;
46 
47  if ((err = alloc_event_buffer()))
48  goto out1;
49 
50  if (oprofile_ops.setup && (err = oprofile_ops.setup()))
51  goto out2;
52 
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.
57  */
58  if (oprofile_ops.sync_start) {
59  int sync_ret = oprofile_ops.sync_start();
60  switch (sync_ret) {
61  case 0:
62  goto post_sync;
63  case 1:
64  goto do_generic;
65  case -1:
66  goto out3;
67  default:
68  goto out3;
69  }
70  }
71 do_generic:
72  if ((err = sync_start()))
73  goto out3;
74 
75 post_sync:
76  is_setup = 1;
77  mutex_unlock(&start_mutex);
78  return 0;
79 
80 out3:
81  if (oprofile_ops.shutdown)
82  oprofile_ops.shutdown();
83 out2:
85 out1:
87 out:
88  mutex_unlock(&start_mutex);
89  return err;
90 }
91 
92 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
93 
94 static void switch_worker(struct work_struct *work);
95 static DECLARE_DELAYED_WORK(switch_work, switch_worker);
96 
97 static void start_switch_worker(void)
98 {
99  if (oprofile_ops.switch_events)
101 }
102 
103 static void stop_switch_worker(void)
104 {
105  cancel_delayed_work_sync(&switch_work);
106 }
107 
108 static void switch_worker(struct work_struct *work)
109 {
110  if (oprofile_ops.switch_events())
111  return;
112 
113  atomic_inc(&oprofile_stats.multiplex_counter);
114  start_switch_worker();
115 }
116 
117 /* User inputs in ms, converts to jiffies */
118 int oprofile_set_timeout(unsigned long val_msec)
119 {
120  int err = 0;
121  unsigned long time_slice;
122 
123  mutex_lock(&start_mutex);
124 
125  if (oprofile_started) {
126  err = -EBUSY;
127  goto out;
128  }
129 
130  if (!oprofile_ops.switch_events) {
131  err = -EINVAL;
132  goto out;
133  }
134 
135  time_slice = msecs_to_jiffies(val_msec);
136  if (time_slice == MAX_JIFFY_OFFSET) {
137  err = -EINVAL;
138  goto out;
139  }
140 
141  oprofile_time_slice = time_slice;
142 
143 out:
144  mutex_unlock(&start_mutex);
145  return err;
146 
147 }
148 
149 #else
150 
151 static inline void start_switch_worker(void) { }
152 static inline void stop_switch_worker(void) { }
153 
154 #endif
155 
156 /* Actually start profiling (echo 1>/dev/oprofile/enable) */
157 int oprofile_start(void)
158 {
159  int err = -EINVAL;
160 
161  mutex_lock(&start_mutex);
162 
163  if (!is_setup)
164  goto out;
165 
166  err = 0;
167 
168  if (oprofile_started)
169  goto out;
170 
172 
173  if ((err = oprofile_ops.start()))
174  goto out;
175 
176  start_switch_worker();
177 
178  oprofile_started = 1;
179 out:
180  mutex_unlock(&start_mutex);
181  return err;
182 }
183 
184 
185 /* echo 0>/dev/oprofile/enable */
186 void oprofile_stop(void)
187 {
188  mutex_lock(&start_mutex);
189  if (!oprofile_started)
190  goto out;
191  oprofile_ops.stop();
192  oprofile_started = 0;
193 
194  stop_switch_worker();
195 
196  /* wake up the daemon to read what remains */
198 out:
199  mutex_unlock(&start_mutex);
200 }
201 
202 
204 {
205  mutex_lock(&start_mutex);
206  if (oprofile_ops.sync_stop) {
207  int sync_ret = oprofile_ops.sync_stop();
208  switch (sync_ret) {
209  case 0:
210  goto post_sync;
211  case 1:
212  goto do_generic;
213  default:
214  goto post_sync;
215  }
216  }
217 do_generic:
218  sync_stop();
219 post_sync:
220  if (oprofile_ops.shutdown)
221  oprofile_ops.shutdown();
222  is_setup = 0;
225  mutex_unlock(&start_mutex);
226 }
227 
228 int oprofile_set_ulong(unsigned long *addr, unsigned long val)
229 {
230  int err = -EBUSY;
231 
232  mutex_lock(&start_mutex);
233  if (!oprofile_started) {
234  *addr = val;
235  err = 0;
236  }
237  mutex_unlock(&start_mutex);
238 
239  return err;
240 }
241 
242 static int timer_mode;
243 
244 static int __init oprofile_init(void)
245 {
246  int err;
247 
248  /* always init architecture to setup backtrace support */
249  timer_mode = 0;
251  if (!err) {
252  if (!timer && !oprofilefs_register())
253  return 0;
255  }
256 
257  /* setup timer mode: */
258  timer_mode = 1;
259  /* no nmi timer mode if oprofile.timer is set */
260  if (timer || op_nmi_timer_init(&oprofile_ops)) {
262  if (err)
263  return err;
264  }
265 
266  return oprofilefs_register();
267 }
268 
269 
270 static void __exit oprofile_exit(void)
271 {
273  if (!timer_mode)
275 }
276 
277 
278 module_init(oprofile_init);
279 module_exit(oprofile_exit);
280 
281 module_param_named(timer, timer, int, 0644);
282 MODULE_PARM_DESC(timer, "force use of timer interrupt");
283 
284 MODULE_LICENSE("GPL");
285 MODULE_AUTHOR("John Levon <[email protected]>");
286 MODULE_DESCRIPTION("OProfile system profiler");