diff options
Diffstat (limited to 'drivers/oprofile/cpu_buffer.c')
-rw-r--r-- | drivers/oprofile/cpu_buffer.c | 91 |
1 files changed, 39 insertions, 52 deletions
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 7ba39fe20a8..01d38e78cde 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <linux/oprofile.h> | 22 | #include <linux/oprofile.h> |
23 | #include <linux/vmalloc.h> | 23 | #include <linux/vmalloc.h> |
24 | #include <linux/errno.h> | 24 | #include <linux/errno.h> |
25 | 25 | ||
26 | #include "event_buffer.h" | 26 | #include "event_buffer.h" |
27 | #include "cpu_buffer.h" | 27 | #include "cpu_buffer.h" |
28 | #include "buffer_sync.h" | 28 | #include "buffer_sync.h" |
@@ -39,7 +39,7 @@ void free_cpu_buffers(void) | |||
39 | { | 39 | { |
40 | int i; | 40 | int i; |
41 | 41 | ||
42 | for_each_online_cpu(i) { | 42 | for_each_possible_cpu(i) { |
43 | vfree(per_cpu(cpu_buffer, i).buffer); | 43 | vfree(per_cpu(cpu_buffer, i).buffer); |
44 | per_cpu(cpu_buffer, i).buffer = NULL; | 44 | per_cpu(cpu_buffer, i).buffer = NULL; |
45 | } | 45 | } |
@@ -61,17 +61,17 @@ void oprofile_cpu_buffer_inc_smpl_lost(void) | |||
61 | int alloc_cpu_buffers(void) | 61 | int alloc_cpu_buffers(void) |
62 | { | 62 | { |
63 | int i; | 63 | int i; |
64 | 64 | ||
65 | unsigned long buffer_size = fs_cpu_buffer_size; | 65 | unsigned long buffer_size = fs_cpu_buffer_size; |
66 | 66 | ||
67 | for_each_online_cpu(i) { | 67 | for_each_possible_cpu(i) { |
68 | struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i); | 68 | struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i); |
69 | 69 | ||
70 | b->buffer = vmalloc_node(sizeof(struct op_sample) * buffer_size, | 70 | b->buffer = vmalloc_node(sizeof(struct op_sample) * buffer_size, |
71 | cpu_to_node(i)); | 71 | cpu_to_node(i)); |
72 | if (!b->buffer) | 72 | if (!b->buffer) |
73 | goto fail; | 73 | goto fail; |
74 | 74 | ||
75 | b->last_task = NULL; | 75 | b->last_task = NULL; |
76 | b->last_is_kernel = -1; | 76 | b->last_is_kernel = -1; |
77 | b->tracing = 0; | 77 | b->tracing = 0; |
@@ -125,7 +125,7 @@ void end_cpu_work(void) | |||
125 | } | 125 | } |
126 | 126 | ||
127 | /* Resets the cpu buffer to a sane state. */ | 127 | /* Resets the cpu buffer to a sane state. */ |
128 | void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf) | 128 | void cpu_buffer_reset(struct oprofile_cpu_buffer *cpu_buf) |
129 | { | 129 | { |
130 | /* reset these to invalid values; the next sample | 130 | /* reset these to invalid values; the next sample |
131 | * collected will populate the buffer with proper | 131 | * collected will populate the buffer with proper |
@@ -136,7 +136,7 @@ void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf) | |||
136 | } | 136 | } |
137 | 137 | ||
138 | /* compute number of available slots in cpu_buffer queue */ | 138 | /* compute number of available slots in cpu_buffer queue */ |
139 | static unsigned long nr_available_slots(struct oprofile_cpu_buffer const * b) | 139 | static unsigned long nr_available_slots(struct oprofile_cpu_buffer const *b) |
140 | { | 140 | { |
141 | unsigned long head = b->head_pos; | 141 | unsigned long head = b->head_pos; |
142 | unsigned long tail = b->tail_pos; | 142 | unsigned long tail = b->tail_pos; |
@@ -147,7 +147,7 @@ static unsigned long nr_available_slots(struct oprofile_cpu_buffer const * b) | |||
147 | return tail + (b->buffer_size - head) - 1; | 147 | return tail + (b->buffer_size - head) - 1; |
148 | } | 148 | } |
149 | 149 | ||
150 | static void increment_head(struct oprofile_cpu_buffer * b) | 150 | static void increment_head(struct oprofile_cpu_buffer *b) |
151 | { | 151 | { |
152 | unsigned long new_head = b->head_pos + 1; | 152 | unsigned long new_head = b->head_pos + 1; |
153 | 153 | ||
@@ -162,17 +162,17 @@ static void increment_head(struct oprofile_cpu_buffer * b) | |||
162 | } | 162 | } |
163 | 163 | ||
164 | static inline void | 164 | static inline void |
165 | add_sample(struct oprofile_cpu_buffer * cpu_buf, | 165 | add_sample(struct oprofile_cpu_buffer *cpu_buf, |
166 | unsigned long pc, unsigned long event) | 166 | unsigned long pc, unsigned long event) |
167 | { | 167 | { |
168 | struct op_sample * entry = &cpu_buf->buffer[cpu_buf->head_pos]; | 168 | struct op_sample *entry = &cpu_buf->buffer[cpu_buf->head_pos]; |
169 | entry->eip = pc; | 169 | entry->eip = pc; |
170 | entry->event = event; | 170 | entry->event = event; |
171 | increment_head(cpu_buf); | 171 | increment_head(cpu_buf); |
172 | } | 172 | } |
173 | 173 | ||
174 | static inline void | 174 | static inline void |
175 | add_code(struct oprofile_cpu_buffer * buffer, unsigned long value) | 175 | add_code(struct oprofile_cpu_buffer *buffer, unsigned long value) |
176 | { | 176 | { |
177 | add_sample(buffer, ESCAPE_CODE, value); | 177 | add_sample(buffer, ESCAPE_CODE, value); |
178 | } | 178 | } |
@@ -186,10 +186,10 @@ add_code(struct oprofile_cpu_buffer * buffer, unsigned long value) | |||
186 | * pc. We tag this in the buffer by generating kernel enter/exit | 186 | * pc. We tag this in the buffer by generating kernel enter/exit |
187 | * events whenever is_kernel changes | 187 | * events whenever is_kernel changes |
188 | */ | 188 | */ |
189 | static int log_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc, | 189 | static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, |
190 | int is_kernel, unsigned long event) | 190 | int is_kernel, unsigned long event) |
191 | { | 191 | { |
192 | struct task_struct * task; | 192 | struct task_struct *task; |
193 | 193 | ||
194 | cpu_buf->sample_received++; | 194 | cpu_buf->sample_received++; |
195 | 195 | ||
@@ -218,7 +218,7 @@ static int log_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc, | |||
218 | cpu_buf->last_task = task; | 218 | cpu_buf->last_task = task; |
219 | add_code(cpu_buf, (unsigned long)task); | 219 | add_code(cpu_buf, (unsigned long)task); |
220 | } | 220 | } |
221 | 221 | ||
222 | add_sample(cpu_buf, pc, event); | 222 | add_sample(cpu_buf, pc, event); |
223 | return 1; | 223 | return 1; |
224 | } | 224 | } |
@@ -235,7 +235,7 @@ static int oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf) | |||
235 | return 1; | 235 | return 1; |
236 | } | 236 | } |
237 | 237 | ||
238 | static void oprofile_end_trace(struct oprofile_cpu_buffer * cpu_buf) | 238 | static void oprofile_end_trace(struct oprofile_cpu_buffer *cpu_buf) |
239 | { | 239 | { |
240 | cpu_buf->tracing = 0; | 240 | cpu_buf->tracing = 0; |
241 | } | 241 | } |
@@ -270,21 +270,23 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) | |||
270 | 270 | ||
271 | #ifdef CONFIG_OPROFILE_IBS | 271 | #ifdef CONFIG_OPROFILE_IBS |
272 | 272 | ||
273 | #define MAX_IBS_SAMPLE_SIZE 14 | 273 | #define MAX_IBS_SAMPLE_SIZE 14 |
274 | static int log_ibs_sample(struct oprofile_cpu_buffer *cpu_buf, | 274 | |
275 | unsigned long pc, int is_kernel, unsigned int *ibs, int ibs_code) | 275 | void oprofile_add_ibs_sample(struct pt_regs *const regs, |
276 | unsigned int *const ibs_sample, int ibs_code) | ||
276 | { | 277 | { |
278 | int is_kernel = !user_mode(regs); | ||
279 | struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); | ||
277 | struct task_struct *task; | 280 | struct task_struct *task; |
278 | 281 | ||
279 | cpu_buf->sample_received++; | 282 | cpu_buf->sample_received++; |
280 | 283 | ||
281 | if (nr_available_slots(cpu_buf) < MAX_IBS_SAMPLE_SIZE) { | 284 | if (nr_available_slots(cpu_buf) < MAX_IBS_SAMPLE_SIZE) { |
285 | /* we can't backtrace since we lost the source of this event */ | ||
282 | cpu_buf->sample_lost_overflow++; | 286 | cpu_buf->sample_lost_overflow++; |
283 | return 0; | 287 | return; |
284 | } | 288 | } |
285 | 289 | ||
286 | is_kernel = !!is_kernel; | ||
287 | |||
288 | /* notice a switch from user->kernel or vice versa */ | 290 | /* notice a switch from user->kernel or vice versa */ |
289 | if (cpu_buf->last_is_kernel != is_kernel) { | 291 | if (cpu_buf->last_is_kernel != is_kernel) { |
290 | cpu_buf->last_is_kernel = is_kernel; | 292 | cpu_buf->last_is_kernel = is_kernel; |
@@ -294,7 +296,6 @@ static int log_ibs_sample(struct oprofile_cpu_buffer *cpu_buf, | |||
294 | /* notice a task switch */ | 296 | /* notice a task switch */ |
295 | if (!is_kernel) { | 297 | if (!is_kernel) { |
296 | task = current; | 298 | task = current; |
297 | |||
298 | if (cpu_buf->last_task != task) { | 299 | if (cpu_buf->last_task != task) { |
299 | cpu_buf->last_task = task; | 300 | cpu_buf->last_task = task; |
300 | add_code(cpu_buf, (unsigned long)task); | 301 | add_code(cpu_buf, (unsigned long)task); |
@@ -302,36 +303,17 @@ static int log_ibs_sample(struct oprofile_cpu_buffer *cpu_buf, | |||
302 | } | 303 | } |
303 | 304 | ||
304 | add_code(cpu_buf, ibs_code); | 305 | add_code(cpu_buf, ibs_code); |
305 | add_sample(cpu_buf, ibs[0], ibs[1]); | 306 | add_sample(cpu_buf, ibs_sample[0], ibs_sample[1]); |
306 | add_sample(cpu_buf, ibs[2], ibs[3]); | 307 | add_sample(cpu_buf, ibs_sample[2], ibs_sample[3]); |
307 | add_sample(cpu_buf, ibs[4], ibs[5]); | 308 | add_sample(cpu_buf, ibs_sample[4], ibs_sample[5]); |
308 | 309 | ||
309 | if (ibs_code == IBS_OP_BEGIN) { | 310 | if (ibs_code == IBS_OP_BEGIN) { |
310 | add_sample(cpu_buf, ibs[6], ibs[7]); | 311 | add_sample(cpu_buf, ibs_sample[6], ibs_sample[7]); |
311 | add_sample(cpu_buf, ibs[8], ibs[9]); | 312 | add_sample(cpu_buf, ibs_sample[8], ibs_sample[9]); |
312 | add_sample(cpu_buf, ibs[10], ibs[11]); | 313 | add_sample(cpu_buf, ibs_sample[10], ibs_sample[11]); |
313 | } | ||
314 | |||
315 | return 1; | ||
316 | } | ||
317 | |||
318 | void oprofile_add_ibs_sample(struct pt_regs *const regs, | ||
319 | unsigned int * const ibs_sample, u8 code) | ||
320 | { | ||
321 | int is_kernel = !user_mode(regs); | ||
322 | unsigned long pc = profile_pc(regs); | ||
323 | |||
324 | struct oprofile_cpu_buffer *cpu_buf = | ||
325 | &per_cpu(cpu_buffer, smp_processor_id()); | ||
326 | |||
327 | if (!backtrace_depth) { | ||
328 | log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code); | ||
329 | return; | ||
330 | } | 314 | } |
331 | 315 | ||
332 | /* if log_sample() fails we can't backtrace since we lost the source | 316 | if (backtrace_depth) |
333 | * of this event */ | ||
334 | if (log_ibs_sample(cpu_buf, pc, is_kernel, ibs_sample, code)) | ||
335 | oprofile_ops.backtrace(regs, backtrace_depth); | 317 | oprofile_ops.backtrace(regs, backtrace_depth); |
336 | } | 318 | } |
337 | 319 | ||
@@ -376,11 +358,16 @@ void oprofile_add_trace(unsigned long pc) | |||
376 | */ | 358 | */ |
377 | static void wq_sync_buffer(struct work_struct *work) | 359 | static void wq_sync_buffer(struct work_struct *work) |
378 | { | 360 | { |
379 | struct oprofile_cpu_buffer * b = | 361 | struct oprofile_cpu_buffer *b = |
380 | container_of(work, struct oprofile_cpu_buffer, work.work); | 362 | container_of(work, struct oprofile_cpu_buffer, work.work); |
381 | if (b->cpu != smp_processor_id()) { | 363 | if (b->cpu != smp_processor_id()) { |
382 | printk(KERN_DEBUG "WQ on CPU%d, prefer CPU%d\n", | 364 | printk(KERN_DEBUG "WQ on CPU%d, prefer CPU%d\n", |
383 | smp_processor_id(), b->cpu); | 365 | smp_processor_id(), b->cpu); |
366 | |||
367 | if (!cpu_online(b->cpu)) { | ||
368 | cancel_delayed_work(&b->work); | ||
369 | return; | ||
370 | } | ||
384 | } | 371 | } |
385 | sync_buffer(b->cpu); | 372 | sync_buffer(b->cpu); |
386 | 373 | ||