aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/oprofile/buffer_sync.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/oprofile/buffer_sync.c')
-rw-r--r--drivers/oprofile/buffer_sync.c229
1 files changed, 81 insertions, 148 deletions
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index b55cd23ffdef..ac014cb27915 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
@@ -268,18 +269,6 @@ lookup_dcookie(struct mm_struct *mm, unsigned long addr, off_t *offset)
268 return cookie; 269 return cookie;
269} 270}
270 271
271static void increment_tail(struct oprofile_cpu_buffer *b)
272{
273 unsigned long new_tail = b->tail_pos + 1;
274
275 rmb(); /* be sure fifo pointers are synchromized */
276
277 if (new_tail < b->buffer_size)
278 b->tail_pos = new_tail;
279 else
280 b->tail_pos = 0;
281}
282
283static unsigned long last_cookie = INVALID_COOKIE; 272static unsigned long last_cookie = INVALID_COOKIE;
284 273
285static void add_cpu_switch(int i) 274static void add_cpu_switch(int i)
@@ -327,84 +316,73 @@ static void add_trace_begin(void)
327 add_event_entry(TRACE_BEGIN_CODE); 316 add_event_entry(TRACE_BEGIN_CODE);
328} 317}
329 318
330#ifdef CONFIG_OPROFILE_IBS 319static void add_data(struct op_entry *entry, struct mm_struct *mm)
331
332#define IBS_FETCH_CODE_SIZE 2
333#define IBS_OP_CODE_SIZE 5
334#define IBS_EIP(offset) \
335 (((struct op_sample *)&cpu_buf->buffer[(offset)])->eip)
336#define IBS_EVENT(offset) \
337 (((struct op_sample *)&cpu_buf->buffer[(offset)])->event)
338
339/*
340 * Add IBS fetch and op entries to event buffer
341 */
342static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code,
343 struct mm_struct *mm)
344{ 320{
345 unsigned long rip; 321 unsigned long code, pc, val;
346 int i, count; 322 unsigned long cookie;
347 unsigned long ibs_cookie = 0;
348 off_t offset; 323 off_t offset;
349 324
350 increment_tail(cpu_buf); /* move to RIP entry */ 325 if (!op_cpu_buffer_get_data(entry, &code))
351 326 return;
352 rip = IBS_EIP(cpu_buf->tail_pos); 327 if (!op_cpu_buffer_get_data(entry, &pc))
353 328 return;
354#ifdef __LP64__ 329 if (!op_cpu_buffer_get_size(entry))
355 rip += IBS_EVENT(cpu_buf->tail_pos) << 32; 330 return;
356#endif
357 331
358 if (mm) { 332 if (mm) {
359 ibs_cookie = lookup_dcookie(mm, rip, &offset); 333 cookie = lookup_dcookie(mm, pc, &offset);
360 334
361 if (ibs_cookie == NO_COOKIE) 335 if (cookie == NO_COOKIE)
362 offset = rip; 336 offset = pc;
363 if (ibs_cookie == INVALID_COOKIE) { 337 if (cookie == INVALID_COOKIE) {
364 atomic_inc(&oprofile_stats.sample_lost_no_mapping); 338 atomic_inc(&oprofile_stats.sample_lost_no_mapping);
365 offset = rip; 339 offset = pc;
366 } 340 }
367 if (ibs_cookie != last_cookie) { 341 if (cookie != last_cookie) {
368 add_cookie_switch(ibs_cookie); 342 add_cookie_switch(cookie);
369 last_cookie = ibs_cookie; 343 last_cookie = cookie;
370 } 344 }
371 } else 345 } else
372 offset = rip; 346 offset = pc;
373 347
374 add_event_entry(ESCAPE_CODE); 348 add_event_entry(ESCAPE_CODE);
375 add_event_entry(code); 349 add_event_entry(code);
376 add_event_entry(offset); /* Offset from Dcookie */ 350 add_event_entry(offset); /* Offset from Dcookie */
377 351
378 /* we send the Dcookie offset, but send the raw Linear Add also*/ 352 while (op_cpu_buffer_get_data(entry, &val))
379 add_event_entry(IBS_EIP(cpu_buf->tail_pos)); 353 add_event_entry(val);
380 add_event_entry(IBS_EVENT(cpu_buf->tail_pos));
381
382 if (code == IBS_FETCH_CODE)
383 count = IBS_FETCH_CODE_SIZE; /*IBS FETCH is 2 int64s*/
384 else
385 count = IBS_OP_CODE_SIZE; /*IBS OP is 5 int64s*/
386
387 for (i = 0; i < count; i++) {
388 increment_tail(cpu_buf);
389 add_event_entry(IBS_EIP(cpu_buf->tail_pos));
390 add_event_entry(IBS_EVENT(cpu_buf->tail_pos));
391 }
392} 354}
393 355
394#endif 356static inline void add_sample_entry(unsigned long offset, unsigned long event)
395
396static void add_sample_entry(unsigned long offset, unsigned long event)
397{ 357{
398 add_event_entry(offset); 358 add_event_entry(offset);
399 add_event_entry(event); 359 add_event_entry(event);
400} 360}
401 361
402 362
403static int add_us_sample(struct mm_struct *mm, struct op_sample *s) 363/*
364 * Add a sample to the global event buffer. If possible the
365 * sample is converted into a persistent dentry/offset pair
366 * for later lookup from userspace. Return 0 on failure.
367 */
368static int
369add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel)
404{ 370{
405 unsigned long cookie; 371 unsigned long cookie;
406 off_t offset; 372 off_t offset;
407 373
374 if (in_kernel) {
375 add_sample_entry(s->eip, s->event);
376 return 1;
377 }
378
379 /* add userspace sample */
380
381 if (!mm) {
382 atomic_inc(&oprofile_stats.sample_lost_no_mm);
383 return 0;
384 }
385
408 cookie = lookup_dcookie(mm, s->eip, &offset); 386 cookie = lookup_dcookie(mm, s->eip, &offset);
409 387
410 if (cookie == INVALID_COOKIE) { 388 if (cookie == INVALID_COOKIE) {
@@ -423,25 +401,6 @@ static int add_us_sample(struct mm_struct *mm, struct op_sample *s)
423} 401}
424 402
425 403
426/* Add a sample to the global event buffer. If possible the
427 * sample is converted into a persistent dentry/offset pair
428 * for later lookup from userspace.
429 */
430static int
431add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel)
432{
433 if (in_kernel) {
434 add_sample_entry(s->eip, s->event);
435 return 1;
436 } else if (mm) {
437 return add_us_sample(mm, s);
438 } else {
439 atomic_inc(&oprofile_stats.sample_lost_no_mm);
440 }
441 return 0;
442}
443
444
445static void release_mm(struct mm_struct *mm) 404static void release_mm(struct mm_struct *mm)
446{ 405{
447 if (!mm) 406 if (!mm)
@@ -466,33 +425,6 @@ static inline int is_code(unsigned long val)
466} 425}
467 426
468 427
469/* "acquire" as many cpu buffer slots as we can */
470static unsigned long get_slots(struct oprofile_cpu_buffer *b)
471{
472 unsigned long head = b->head_pos;
473 unsigned long tail = b->tail_pos;
474
475 /*
476 * Subtle. This resets the persistent last_task
477 * and in_kernel values used for switching notes.
478 * BUT, there is a small window between reading
479 * head_pos, and this call, that means samples
480 * can appear at the new head position, but not
481 * be prefixed with the notes for switching
482 * kernel mode or a task switch. This small hole
483 * can lead to mis-attribution or samples where
484 * we don't know if it's in the kernel or not,
485 * at the start of an event buffer.
486 */
487 cpu_buffer_reset(b);
488
489 if (head >= tail)
490 return head - tail;
491
492 return head + (b->buffer_size - tail);
493}
494
495
496/* Move tasks along towards death. Any tasks on dead_tasks 428/* Move tasks along towards death. Any tasks on dead_tasks
497 * will definitely have no remaining references in any 429 * will definitely have no remaining references in any
498 * CPU buffers at this point, because we use two lists, 430 * CPU buffers at this point, because we use two lists,
@@ -559,71 +491,72 @@ typedef enum {
559 */ 491 */
560void sync_buffer(int cpu) 492void sync_buffer(int cpu)
561{ 493{
562 struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu);
563 struct mm_struct *mm = NULL; 494 struct mm_struct *mm = NULL;
495 struct mm_struct *oldmm;
496 unsigned long val;
564 struct task_struct *new; 497 struct task_struct *new;
565 unsigned long cookie = 0; 498 unsigned long cookie = 0;
566 int in_kernel = 1; 499 int in_kernel = 1;
567 sync_buffer_state state = sb_buffer_start; 500 sync_buffer_state state = sb_buffer_start;
568#ifndef CONFIG_OPROFILE_IBS
569 unsigned int i; 501 unsigned int i;
570 unsigned long available; 502 unsigned long available;
571#endif 503 unsigned long flags;
504 struct op_entry entry;
505 struct op_sample *sample;
572 506
573 mutex_lock(&buffer_mutex); 507 mutex_lock(&buffer_mutex);
574 508
575 add_cpu_switch(cpu); 509 add_cpu_switch(cpu);
576 510
577 /* Remember, only we can modify tail_pos */ 511 op_cpu_buffer_reset(cpu);
578 512 available = op_cpu_buffer_entries(cpu);
579#ifndef CONFIG_OPROFILE_IBS
580 available = get_slots(cpu_buf);
581 513
582 for (i = 0; i < available; ++i) { 514 for (i = 0; i < available; ++i) {
583#else 515 sample = op_cpu_buffer_read_entry(&entry, cpu);
584 while (get_slots(cpu_buf)) { 516 if (!sample)
585#endif 517 break;
586 struct op_sample *s = &cpu_buf->buffer[cpu_buf->tail_pos];
587 518
588 if (is_code(s->eip)) { 519 if (is_code(sample->eip)) {
589 if (s->event <= CPU_IS_KERNEL) { 520 flags = sample->event;
521 if (flags & TRACE_BEGIN) {
522 state = sb_bt_start;
523 add_trace_begin();
524 }
525 if (flags & KERNEL_CTX_SWITCH) {
590 /* kernel/userspace switch */ 526 /* kernel/userspace switch */
591 in_kernel = s->event; 527 in_kernel = flags & IS_KERNEL;
592 if (state == sb_buffer_start) 528 if (state == sb_buffer_start)
593 state = sb_sample_start; 529 state = sb_sample_start;
594 add_kernel_ctx_switch(s->event); 530 add_kernel_ctx_switch(flags & IS_KERNEL);
595 } else if (s->event == CPU_TRACE_BEGIN) { 531 }
596 state = sb_bt_start; 532 if (flags & USER_CTX_SWITCH
597 add_trace_begin(); 533 && op_cpu_buffer_get_data(&entry, &val)) {
598#ifdef CONFIG_OPROFILE_IBS
599 } else if (s->event == IBS_FETCH_BEGIN) {
600 state = sb_bt_start;
601 add_ibs_begin(cpu_buf, IBS_FETCH_CODE, mm);
602 } else if (s->event == IBS_OP_BEGIN) {
603 state = sb_bt_start;
604 add_ibs_begin(cpu_buf, IBS_OP_CODE, mm);
605#endif
606 } else {
607 struct mm_struct *oldmm = mm;
608
609 /* userspace context switch */ 534 /* userspace context switch */
610 new = (struct task_struct *)s->event; 535 new = (struct task_struct *)val;
611 536 oldmm = mm;
612 release_mm(oldmm); 537 release_mm(oldmm);
613 mm = take_tasks_mm(new); 538 mm = take_tasks_mm(new);
614 if (mm != oldmm) 539 if (mm != oldmm)
615 cookie = get_exec_dcookie(mm); 540 cookie = get_exec_dcookie(mm);
616 add_user_ctx_switch(new, cookie); 541 add_user_ctx_switch(new, cookie);
617 } 542 }
618 } else if (state >= sb_bt_start && 543 if (op_cpu_buffer_get_size(&entry))
619 !add_sample(mm, s, in_kernel)) { 544 add_data(&entry, mm);
620 if (state == sb_bt_start) { 545 continue;
621 state = sb_bt_ignore;
622 atomic_inc(&oprofile_stats.bt_lost_no_mapping);
623 }
624 } 546 }
625 547
626 increment_tail(cpu_buf); 548 if (state < sb_bt_start)
549 /* ignore sample */
550 continue;
551
552 if (add_sample(mm, sample, in_kernel))
553 continue;
554
555 /* ignore backtraces if failed to add a sample */
556 if (state == sb_bt_start) {
557 state = sb_bt_ignore;
558 atomic_inc(&oprofile_stats.bt_lost_no_mapping);
559 }
627 } 560 }
628 release_mm(mm); 561 release_mm(mm);
629 562