Blame view

drivers/oprofile/oprof.c 5.04 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /**
   * @file oprof.c
   *
   * @remark Copyright 2002 OProfile authors
   * @remark Read the file COPYING
   *
   * @author John Levon <levon@movementarian.org>
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/oprofile.h>
  #include <linux/moduleparam.h>
4d4036e0e   Jason Yeh   oprofile: Impleme...
15
16
  #include <linux/workqueue.h>
  #include <linux/time.h>
b76a06e08   Anton Blanchard   oprofile: Use lin...
17
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
22
23
  
  #include "oprof.h"
  #include "event_buffer.h"
  #include "cpu_buffer.h"
  #include "buffer_sync.h"
  #include "oprofile_stats.h"
c92960fcc   Robert Richter   oprofile: whitesp...
24

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
  struct oprofile_operations oprofile_ops;
  
  unsigned long oprofile_started;
bd2172f58   Robert Richter   oprofile: rename ...
28
  unsigned long oprofile_backtrace_depth;
4c168eaf7   Robert Richter   Revert "Oprofile ...
29
30
  static unsigned long is_setup;
  static DEFINE_MUTEX(start_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
35
36
37
38
39
40
  
  /* timer
     0 - use performance monitoring hardware if available
     1 - use the timer int mechanism regardless
   */
  static int timer = 0;
  
  int oprofile_setup(void)
  {
  	int err;
c92960fcc   Robert Richter   oprofile: whitesp...
41

59cc185ad   Markus Armbruster   [PATCH] oprofile:...
42
  	mutex_lock(&start_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
46
47
48
  
  	if ((err = alloc_cpu_buffers()))
  		goto out;
  
  	if ((err = alloc_event_buffer()))
  		goto out1;
c92960fcc   Robert Richter   oprofile: whitesp...
49

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
  	if (oprofile_ops.setup && (err = oprofile_ops.setup()))
  		goto out2;
c92960fcc   Robert Richter   oprofile: whitesp...
52

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
55
56
57
  	/* Note even though this starts part of the
  	 * profiling overhead, it's necessary to prevent
  	 * us missing task deaths and eventually oopsing
  	 * when trying to process the event buffer.
  	 */
1474855d0   Bob Nelson   [CELL] oprofile: ...
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  	if (oprofile_ops.sync_start) {
  		int sync_ret = oprofile_ops.sync_start();
  		switch (sync_ret) {
  		case 0:
  			goto post_sync;
  		case 1:
  			goto do_generic;
  		case -1:
  			goto out3;
  		default:
  			goto out3;
  		}
  	}
  do_generic:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
  	if ((err = sync_start()))
  		goto out3;
1474855d0   Bob Nelson   [CELL] oprofile: ...
74
  post_sync:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  	is_setup = 1;
59cc185ad   Markus Armbruster   [PATCH] oprofile:...
76
  	mutex_unlock(&start_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
  	return 0;
c92960fcc   Robert Richter   oprofile: whitesp...
78

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
81
82
83
84
85
86
  out3:
  	if (oprofile_ops.shutdown)
  		oprofile_ops.shutdown();
  out2:
  	free_event_buffer();
  out1:
  	free_cpu_buffers();
  out:
59cc185ad   Markus Armbruster   [PATCH] oprofile:...
87
  	mutex_unlock(&start_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
  	return err;
  }
4d4036e0e   Jason Yeh   oprofile: Impleme...
90
  #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
a5659d17a   Robert Richter   oprofile: Groupin...
91
92
  static void switch_worker(struct work_struct *work);
  static DECLARE_DELAYED_WORK(switch_work, switch_worker);
4d4036e0e   Jason Yeh   oprofile: Impleme...
93
94
  static void start_switch_worker(void)
  {
a5659d17a   Robert Richter   oprofile: Groupin...
95
96
97
98
99
100
101
  	if (oprofile_ops.switch_events)
  		schedule_delayed_work(&switch_work, oprofile_time_slice);
  }
  
  static void stop_switch_worker(void)
  {
  	cancel_delayed_work_sync(&switch_work);
4d4036e0e   Jason Yeh   oprofile: Impleme...
102
103
104
105
  }
  
  static void switch_worker(struct work_struct *work)
  {
1b294f596   Robert Richter   oprofile: Adding ...
106
107
108
109
110
  	if (oprofile_ops.switch_events())
  		return;
  
  	atomic_inc(&oprofile_stats.multiplex_counter);
  	start_switch_worker();
4d4036e0e   Jason Yeh   oprofile: Impleme...
111
  }
a5659d17a   Robert Richter   oprofile: Groupin...
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  /* User inputs in ms, converts to jiffies */
  int oprofile_set_timeout(unsigned long val_msec)
  {
  	int err = 0;
  	unsigned long time_slice;
  
  	mutex_lock(&start_mutex);
  
  	if (oprofile_started) {
  		err = -EBUSY;
  		goto out;
  	}
  
  	if (!oprofile_ops.switch_events) {
  		err = -EINVAL;
  		goto out;
  	}
  
  	time_slice = msecs_to_jiffies(val_msec);
  	if (time_slice == MAX_JIFFY_OFFSET) {
  		err = -EINVAL;
  		goto out;
  	}
  
  	oprofile_time_slice = time_slice;
  
  out:
  	mutex_unlock(&start_mutex);
  	return err;
  
  }
  
  #else
  
  static inline void start_switch_worker(void) { }
  static inline void stop_switch_worker(void) { }
4d4036e0e   Jason Yeh   oprofile: Impleme...
148
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
152
153
  
  /* Actually start profiling (echo 1>/dev/oprofile/enable) */
  int oprofile_start(void)
  {
  	int err = -EINVAL;
c92960fcc   Robert Richter   oprofile: whitesp...
154

59cc185ad   Markus Armbruster   [PATCH] oprofile:...
155
  	mutex_lock(&start_mutex);
6a18037d4   Robert Richter   oprofile: fixing ...
156

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
  	if (!is_setup)
  		goto out;
c92960fcc   Robert Richter   oprofile: whitesp...
159
  	err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
  	if (oprofile_started)
  		goto out;
c92960fcc   Robert Richter   oprofile: whitesp...
162

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
166
  	oprofile_reset_stats();
  
  	if ((err = oprofile_ops.start()))
  		goto out;
a5659d17a   Robert Richter   oprofile: Groupin...
167
  	start_switch_worker();
4d4036e0e   Jason Yeh   oprofile: Impleme...
168

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
  	oprofile_started = 1;
  out:
59cc185ad   Markus Armbruster   [PATCH] oprofile:...
171
  	mutex_unlock(&start_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
173
  	return err;
  }
c92960fcc   Robert Richter   oprofile: whitesp...
174

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
  /* echo 0>/dev/oprofile/enable */
  void oprofile_stop(void)
  {
59cc185ad   Markus Armbruster   [PATCH] oprofile:...
178
  	mutex_lock(&start_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
  	if (!oprofile_started)
  		goto out;
  	oprofile_ops.stop();
  	oprofile_started = 0;
4d4036e0e   Jason Yeh   oprofile: Impleme...
183

a5659d17a   Robert Richter   oprofile: Groupin...
184
  	stop_switch_worker();
4d4036e0e   Jason Yeh   oprofile: Impleme...
185

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
188
  	/* wake up the daemon to read what remains */
  	wake_up_buffer_waiter();
  out:
59cc185ad   Markus Armbruster   [PATCH] oprofile:...
189
  	mutex_unlock(&start_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
193
194
  }
  
  
  void oprofile_shutdown(void)
  {
59cc185ad   Markus Armbruster   [PATCH] oprofile:...
195
  	mutex_lock(&start_mutex);
1474855d0   Bob Nelson   [CELL] oprofile: ...
196
197
198
199
200
201
202
203
204
205
206
207
  	if (oprofile_ops.sync_stop) {
  		int sync_ret = oprofile_ops.sync_stop();
  		switch (sync_ret) {
  		case 0:
  			goto post_sync;
  		case 1:
  			goto do_generic;
  		default:
  			goto post_sync;
  		}
  	}
  do_generic:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
  	sync_stop();
1474855d0   Bob Nelson   [CELL] oprofile: ...
209
  post_sync:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
212
213
214
  	if (oprofile_ops.shutdown)
  		oprofile_ops.shutdown();
  	is_setup = 0;
  	free_event_buffer();
  	free_cpu_buffers();
59cc185ad   Markus Armbruster   [PATCH] oprofile:...
215
  	mutex_unlock(&start_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
  }
7df01d96b   Robert Richter   oprofile: disable...
217
  int oprofile_set_ulong(unsigned long *addr, unsigned long val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  {
7df01d96b   Robert Richter   oprofile: disable...
219
  	int err = -EBUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220

59cc185ad   Markus Armbruster   [PATCH] oprofile:...
221
  	mutex_lock(&start_mutex);
7df01d96b   Robert Richter   oprofile: disable...
222
223
224
  	if (!oprofile_started) {
  		*addr = val;
  		err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  	}
59cc185ad   Markus Armbruster   [PATCH] oprofile:...
226
  	mutex_unlock(&start_mutex);
7df01d96b   Robert Richter   oprofile: disable...
227

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
  	return err;
  }
87121ca50   Robert Richter   oprofile: Fix cra...
230
  static int timer_mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
232
233
  static int __init oprofile_init(void)
  {
  	int err;
87121ca50   Robert Richter   oprofile: Fix cra...
234
  	/* always init architecture to setup backtrace support */
dcfce4a09   Robert Richter   oprofile, x86: Re...
235
  	timer_mode = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
  	err = oprofile_arch_init(&oprofile_ops);
dcfce4a09   Robert Richter   oprofile, x86: Re...
237
238
239
240
241
  	if (!err) {
  		if (!timer && !oprofilefs_register())
  			return 0;
  		oprofile_arch_exit();
  	}
87121ca50   Robert Richter   oprofile: Fix cra...
242

dcfce4a09   Robert Richter   oprofile, x86: Re...
243
244
245
246
  	/* setup timer mode: */
  	timer_mode = 1;
  	/* no nmi timer mode if oprofile.timer is set */
  	if (timer || op_nmi_timer_init(&oprofile_ops)) {
bc078e4ea   Martin Schwidefsky   oprofile: convert...
247
248
  		err = oprofile_timer_init(&oprofile_ops);
  		if (err)
979048e1f   Will Deacon   oprofile: don't c...
249
  			return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
  	}
87121ca50   Robert Richter   oprofile: Fix cra...
251

dcfce4a09   Robert Richter   oprofile, x86: Re...
252
  	return oprofilefs_register();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
255
256
257
258
  }
  
  
  static void __exit oprofile_exit(void)
  {
  	oprofilefs_unregister();
75c43a20b   Robert Richter   oprofile: Remove ...
259
  	if (!timer_mode)
87121ca50   Robert Richter   oprofile: Fix cra...
260
  		oprofile_arch_exit();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
  }
c92960fcc   Robert Richter   oprofile: whitesp...
262

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
265
266
267
  module_init(oprofile_init);
  module_exit(oprofile_exit);
  
  module_param_named(timer, timer, int, 0644);
  MODULE_PARM_DESC(timer, "force use of timer interrupt");
c92960fcc   Robert Richter   oprofile: whitesp...
268

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
270
271
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("John Levon <levon@movementarian.org>");
  MODULE_DESCRIPTION("OProfile system profiler");