aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/oprofile/op_model_amd.c8
-rw-r--r--drivers/oprofile/buffer_sync.c42
-rw-r--r--drivers/oprofile/cpu_buffer.c139
-rw-r--r--drivers/oprofile/cpu_buffer.h12
4 files changed, 106 insertions, 95 deletions
diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c
index 423a95438cbc..f101724db80a 100644
--- a/arch/x86/oprofile/op_model_amd.c
+++ b/arch/x86/oprofile/op_model_amd.c
@@ -2,7 +2,7 @@
2 * @file op_model_amd.c 2 * @file op_model_amd.c
3 * athlon / K7 / K8 / Family 10h model-specific MSR operations 3 * athlon / K7 / K8 / Family 10h model-specific MSR operations
4 * 4 *
5 * @remark Copyright 2002-2008 OProfile authors 5 * @remark Copyright 2002-2009 OProfile authors
6 * @remark Read the file COPYING 6 * @remark Read the file COPYING
7 * 7 *
8 * @author John Levon 8 * @author John Levon
@@ -10,7 +10,7 @@
10 * @author Graydon Hoare 10 * @author Graydon Hoare
11 * @author Robert Richter <robert.richter@amd.com> 11 * @author Robert Richter <robert.richter@amd.com>
12 * @author Barry Kasindorf 12 * @author Barry Kasindorf
13*/ 13 */
14 14
15#include <linux/oprofile.h> 15#include <linux/oprofile.h>
16#include <linux/device.h> 16#include <linux/device.h>
@@ -62,8 +62,8 @@ static unsigned long reset_value[NUM_COUNTERS];
62 62
63/* Codes used in cpu_buffer.c */ 63/* Codes used in cpu_buffer.c */
64/* This produces duplicate code, need to be fixed */ 64/* This produces duplicate code, need to be fixed */
65#define IBS_FETCH_BEGIN 3 65#define IBS_FETCH_BEGIN (1UL << 4)
66#define IBS_OP_BEGIN 4 66#define IBS_OP_BEGIN (1UL << 5)
67 67
68/* 68/*
69 * The function interface needs to be fixed, something like add 69 * The function interface needs to be fixed, something like add
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index 908202afbae9..d969bb13a252 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -1,11 +1,12 @@
1/** 1/**
2 * @file buffer_sync.c 2 * @file buffer_sync.c
3 * 3 *
4 * @remark Copyright 2002 OProfile authors 4 * @remark Copyright 2002-2009 OProfile authors
5 * @remark Read the file COPYING 5 * @remark Read the file COPYING
6 * 6 *
7 * @author John Levon <levon@movementarian.org> 7 * @author John Levon <levon@movementarian.org>
8 * @author Barry Kasindorf 8 * @author Barry Kasindorf
9 * @author Robert Richter <robert.richter@amd.com>
9 * 10 *
10 * This is the core of the buffer management. Each 11 * This is the core of the buffer management. Each
11 * CPU buffer is processed and entered into the 12 * CPU buffer is processed and entered into the
@@ -529,6 +530,7 @@ void sync_buffer(int cpu)
529 sync_buffer_state state = sb_buffer_start; 530 sync_buffer_state state = sb_buffer_start;
530 unsigned int i; 531 unsigned int i;
531 unsigned long available; 532 unsigned long available;
533 unsigned long flags;
532 struct op_entry entry; 534 struct op_entry entry;
533 struct op_sample *sample; 535 struct op_sample *sample;
534 536
@@ -545,38 +547,34 @@ void sync_buffer(int cpu)
545 break; 547 break;
546 548
547 if (is_code(sample->eip)) { 549 if (is_code(sample->eip)) {
548 switch (sample->event) { 550 flags = sample->event;
549 case 0: 551 if (flags & TRACE_BEGIN) {
550 case CPU_IS_KERNEL: 552 state = sb_bt_start;
553 add_trace_begin();
554 }
555 if (flags & KERNEL_CTX_SWITCH) {
551 /* kernel/userspace switch */ 556 /* kernel/userspace switch */
552 in_kernel = sample->event; 557 in_kernel = flags & IS_KERNEL;
553 if (state == sb_buffer_start) 558 if (state == sb_buffer_start)
554 state = sb_sample_start; 559 state = sb_sample_start;
555 add_kernel_ctx_switch(sample->event); 560 add_kernel_ctx_switch(flags & IS_KERNEL);
556 break; 561 }
557 case CPU_TRACE_BEGIN: 562 if (flags & USER_CTX_SWITCH) {
558 state = sb_bt_start;
559 add_trace_begin();
560 break;
561#ifdef CONFIG_OPROFILE_IBS
562 case IBS_FETCH_BEGIN:
563 add_ibs_begin(cpu, IBS_FETCH_CODE, mm);
564 break;
565 case IBS_OP_BEGIN:
566 add_ibs_begin(cpu, IBS_OP_CODE, mm);
567 break;
568#endif
569 default:
570 /* userspace context switch */ 563 /* userspace context switch */
571 oldmm = mm; 564 oldmm = mm;
572 new = (struct task_struct *)sample->event; 565 new = (struct task_struct *)sample->data[0];
573 release_mm(oldmm); 566 release_mm(oldmm);
574 mm = take_tasks_mm(new); 567 mm = take_tasks_mm(new);
575 if (mm != oldmm) 568 if (mm != oldmm)
576 cookie = get_exec_dcookie(mm); 569 cookie = get_exec_dcookie(mm);
577 add_user_ctx_switch(new, cookie); 570 add_user_ctx_switch(new, cookie);
578 break;
579 } 571 }
572#ifdef CONFIG_OPROFILE_IBS
573 if (flags & IBS_FETCH_BEGIN)
574 add_ibs_begin(cpu, IBS_FETCH_CODE, mm);
575 if (flags & IBS_OP_BEGIN)
576 add_ibs_begin(cpu, IBS_OP_CODE, mm);
577#endif
580 continue; 578 continue;
581 } 579 }
582 580
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
index 400f7fcffdbe..e859d23cfc57 100644
--- a/drivers/oprofile/cpu_buffer.c
+++ b/drivers/oprofile/cpu_buffer.c
@@ -212,6 +212,59 @@ unsigned long op_cpu_buffer_entries(int cpu)
212 + ring_buffer_entries_cpu(op_ring_buffer_write, cpu); 212 + ring_buffer_entries_cpu(op_ring_buffer_write, cpu);
213} 213}
214 214
215static int
216op_add_code(struct oprofile_cpu_buffer *cpu_buf, unsigned long backtrace,
217 int is_kernel, struct task_struct *task)
218{
219 struct op_entry entry;
220 struct op_sample *sample;
221 unsigned long flags;
222 int size;
223
224 flags = 0;
225
226 if (backtrace)
227 flags |= TRACE_BEGIN;
228
229 /* notice a switch from user->kernel or vice versa */
230 is_kernel = !!is_kernel;
231 if (cpu_buf->last_is_kernel != is_kernel) {
232 cpu_buf->last_is_kernel = is_kernel;
233 flags |= KERNEL_CTX_SWITCH;
234 if (is_kernel)
235 flags |= IS_KERNEL;
236 }
237
238 /* notice a task switch */
239 if (cpu_buf->last_task != task) {
240 cpu_buf->last_task = task;
241 flags |= USER_CTX_SWITCH;
242 }
243
244 if (!flags)
245 /* nothing to do */
246 return 0;
247
248 if (flags & USER_CTX_SWITCH)
249 size = 1;
250 else
251 size = 0;
252
253 sample = op_cpu_buffer_write_reserve(&entry, size);
254 if (!sample)
255 return -ENOMEM;
256
257 sample->eip = ESCAPE_CODE;
258 sample->event = flags;
259
260 if (size)
261 sample->data[0] = (unsigned long)task;
262
263 op_cpu_buffer_write_commit(&entry);
264
265 return 0;
266}
267
215static inline int 268static inline int
216op_add_sample(struct oprofile_cpu_buffer *cpu_buf, 269op_add_sample(struct oprofile_cpu_buffer *cpu_buf,
217 unsigned long pc, unsigned long event) 270 unsigned long pc, unsigned long event)
@@ -229,26 +282,18 @@ op_add_sample(struct oprofile_cpu_buffer *cpu_buf,
229 return op_cpu_buffer_write_commit(&entry); 282 return op_cpu_buffer_write_commit(&entry);
230} 283}
231 284
232static inline int 285/*
233add_code(struct oprofile_cpu_buffer *buffer, unsigned long value) 286 * This must be safe from any context.
234{
235 return op_add_sample(buffer, ESCAPE_CODE, value);
236}
237
238/* This must be safe from any context. It's safe writing here
239 * because of the head/tail separation of the writer and reader
240 * of the CPU buffer.
241 * 287 *
242 * is_kernel is needed because on some architectures you cannot 288 * is_kernel is needed because on some architectures you cannot
243 * tell if you are in kernel or user space simply by looking at 289 * tell if you are in kernel or user space simply by looking at
244 * pc. We tag this in the buffer by generating kernel enter/exit 290 * pc. We tag this in the buffer by generating kernel enter/exit
245 * events whenever is_kernel changes 291 * events whenever is_kernel changes
246 */ 292 */
247static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, 293static int
248 int is_kernel, unsigned long event) 294log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc,
295 unsigned long backtrace, int is_kernel, unsigned long event)
249{ 296{
250 struct task_struct *task;
251
252 cpu_buf->sample_received++; 297 cpu_buf->sample_received++;
253 298
254 if (pc == ESCAPE_CODE) { 299 if (pc == ESCAPE_CODE) {
@@ -256,23 +301,8 @@ static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc,
256 return 0; 301 return 0;
257 } 302 }
258 303
259 is_kernel = !!is_kernel; 304 if (op_add_code(cpu_buf, backtrace, is_kernel, current))
260 305 goto fail;
261 task = current;
262
263 /* notice a switch from user->kernel or vice versa */
264 if (cpu_buf->last_is_kernel != is_kernel) {
265 cpu_buf->last_is_kernel = is_kernel;
266 if (add_code(cpu_buf, is_kernel))
267 goto fail;
268 }
269
270 /* notice a task switch */
271 if (cpu_buf->last_task != task) {
272 cpu_buf->last_task = task;
273 if (add_code(cpu_buf, (unsigned long)task))
274 goto fail;
275 }
276 306
277 if (op_add_sample(cpu_buf, pc, event)) 307 if (op_add_sample(cpu_buf, pc, event))
278 goto fail; 308 goto fail;
@@ -286,7 +316,6 @@ fail:
286 316
287static inline void oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf) 317static inline void oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf)
288{ 318{
289 add_code(cpu_buf, CPU_TRACE_BEGIN);
290 cpu_buf->tracing = 1; 319 cpu_buf->tracing = 1;
291} 320}
292 321
@@ -300,21 +329,21 @@ __oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
300 unsigned long event, int is_kernel) 329 unsigned long event, int is_kernel)
301{ 330{
302 struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); 331 struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
303 332 unsigned long backtrace = oprofile_backtrace_depth;
304 if (!oprofile_backtrace_depth) {
305 log_sample(cpu_buf, pc, is_kernel, event);
306 return;
307 }
308
309 oprofile_begin_trace(cpu_buf);
310 333
311 /* 334 /*
312 * if log_sample() fail we can't backtrace since we lost the 335 * if log_sample() fail we can't backtrace since we lost the
313 * source of this event 336 * source of this event
314 */ 337 */
315 if (log_sample(cpu_buf, pc, is_kernel, event)) 338 if (!log_sample(cpu_buf, pc, backtrace, is_kernel, event))
316 oprofile_ops.backtrace(regs, oprofile_backtrace_depth); 339 /* failed */
340 return;
317 341
342 if (!backtrace)
343 return;
344
345 oprofile_begin_trace(cpu_buf);
346 oprofile_ops.backtrace(regs, backtrace);
318 oprofile_end_trace(cpu_buf); 347 oprofile_end_trace(cpu_buf);
319} 348}
320 349
@@ -339,29 +368,14 @@ void oprofile_add_ibs_sample(struct pt_regs * const regs,
339{ 368{
340 int is_kernel = !user_mode(regs); 369 int is_kernel = !user_mode(regs);
341 struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); 370 struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
342 struct task_struct *task;
343 int fail = 0; 371 int fail = 0;
344 372
345 cpu_buf->sample_received++; 373 cpu_buf->sample_received++;
346 374
347 /* notice a switch from user->kernel or vice versa */ 375 /* backtraces disabled for ibs */
348 if (cpu_buf->last_is_kernel != is_kernel) { 376 fail = fail || op_add_code(cpu_buf, 0, is_kernel, current);
349 if (add_code(cpu_buf, is_kernel))
350 goto fail;
351 cpu_buf->last_is_kernel = is_kernel;
352 }
353 377
354 /* notice a task switch */ 378 fail = fail || op_add_sample(cpu_buf, ESCAPE_CODE, ibs_code);
355 if (!is_kernel) {
356 task = current;
357 if (cpu_buf->last_task != task) {
358 if (add_code(cpu_buf, (unsigned long)task))
359 goto fail;
360 cpu_buf->last_task = task;
361 }
362 }
363
364 fail = fail || add_code(cpu_buf, ibs_code);
365 fail = fail || op_add_sample(cpu_buf, ibs_sample[0], ibs_sample[1]); 379 fail = fail || op_add_sample(cpu_buf, ibs_sample[0], ibs_sample[1]);
366 fail = fail || op_add_sample(cpu_buf, ibs_sample[2], ibs_sample[3]); 380 fail = fail || op_add_sample(cpu_buf, ibs_sample[2], ibs_sample[3]);
367 fail = fail || op_add_sample(cpu_buf, ibs_sample[4], ibs_sample[5]); 381 fail = fail || op_add_sample(cpu_buf, ibs_sample[4], ibs_sample[5]);
@@ -372,11 +386,8 @@ void oprofile_add_ibs_sample(struct pt_regs * const regs,
372 fail = fail || op_add_sample(cpu_buf, ibs_sample[10], ibs_sample[11]); 386 fail = fail || op_add_sample(cpu_buf, ibs_sample[10], ibs_sample[11]);
373 } 387 }
374 388
375 if (!fail) 389 if (fail)
376 return; 390 cpu_buf->sample_lost_overflow++;
377
378fail:
379 cpu_buf->sample_lost_overflow++;
380} 391}
381 392
382#endif 393#endif
@@ -384,7 +395,7 @@ fail:
384void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) 395void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event)
385{ 396{
386 struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); 397 struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
387 log_sample(cpu_buf, pc, is_kernel, event); 398 log_sample(cpu_buf, pc, 0, is_kernel, event);
388} 399}
389 400
390void oprofile_add_trace(unsigned long pc) 401void oprofile_add_trace(unsigned long pc)
diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h
index d7c0545ef8b2..e634dcf2f26f 100644
--- a/drivers/oprofile/cpu_buffer.h
+++ b/drivers/oprofile/cpu_buffer.h
@@ -78,10 +78,12 @@ int op_cpu_buffer_write_commit(struct op_entry *entry);
78struct op_sample *op_cpu_buffer_read_entry(struct op_entry *entry, int cpu); 78struct op_sample *op_cpu_buffer_read_entry(struct op_entry *entry, int cpu);
79unsigned long op_cpu_buffer_entries(int cpu); 79unsigned long op_cpu_buffer_entries(int cpu);
80 80
81/* transient events for the CPU buffer -> event buffer */ 81/* extra data flags */
82#define CPU_IS_KERNEL 1 82#define KERNEL_CTX_SWITCH (1UL << 0)
83#define CPU_TRACE_BEGIN 2 83#define IS_KERNEL (1UL << 1)
84#define IBS_FETCH_BEGIN 3 84#define TRACE_BEGIN (1UL << 2)
85#define IBS_OP_BEGIN 4 85#define USER_CTX_SWITCH (1UL << 3)
86#define IBS_FETCH_BEGIN (1UL << 4)
87#define IBS_OP_BEGIN (1UL << 5)
86 88
87#endif /* OPROFILE_CPU_BUFFER_H */ 89#endif /* OPROFILE_CPU_BUFFER_H */