aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Shishkin <alexander.shishkin@linux.intel.com>2015-05-22 11:30:22 -0400
committerIngo Molnar <mingo@kernel.org>2015-05-27 03:16:20 -0400
commitf73ec48c90016f89d05726f6c48e66991a790fd7 (patch)
tree22b8ce22d244c0eed554cb09777661699d85fa33
parentaa319bcd366349c6f72fcd331da89d3d06090651 (diff)
perf/x86/intel/pt: Untangle pt_buffer_reset_markers()
Currently, pt_buffer_reset_markers() is a difficult to read knot of arithmetics with a redundant check for multiple-entry TOPA capability, a commented out wakeup marker placement and a logical error wrt to stop marker placement. The latter happens when write head is not page aligned and results in stop marker being placed one page earlier than it actually should. All these problems only affect PT implementations that support multiple-entry TOPA tables (read: proper scatter-gather). For single-entry TOPA implementations, there is no functional impact. This patch deals with all of the above. Tested on both single-entry and multiple-entry TOPA PT implementations. Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: acme@infradead.org Cc: adrian.hunter@intel.com Cc: hpa@zytor.com Link: http://lkml.kernel.org/r/1432308626-18845-4-git-send-email-alexander.shishkin@linux.intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_pt.c34
1 files changed, 22 insertions, 12 deletions
diff --git a/arch/x86/kernel/cpu/perf_event_intel_pt.c b/arch/x86/kernel/cpu/perf_event_intel_pt.c
index ffe666c2c6b5..5b804f96ad66 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_pt.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_pt.c
@@ -615,7 +615,8 @@ static int pt_buffer_reset_markers(struct pt_buffer *buf,
615 struct perf_output_handle *handle) 615 struct perf_output_handle *handle)
616 616
617{ 617{
618 unsigned long idx, npages, end; 618 unsigned long head = local64_read(&buf->head);
619 unsigned long idx, npages, wakeup;
619 620
620 if (buf->snapshot) 621 if (buf->snapshot)
621 return 0; 622 return 0;
@@ -634,17 +635,26 @@ static int pt_buffer_reset_markers(struct pt_buffer *buf,
634 buf->topa_index[buf->stop_pos]->stop = 0; 635 buf->topa_index[buf->stop_pos]->stop = 0;
635 buf->topa_index[buf->intr_pos]->intr = 0; 636 buf->topa_index[buf->intr_pos]->intr = 0;
636 637
637 if (pt_cap_get(PT_CAP_topa_multiple_entries)) { 638 /* how many pages till the STOP marker */
638 npages = (handle->size + 1) >> PAGE_SHIFT; 639 npages = handle->size >> PAGE_SHIFT;
639 end = (local64_read(&buf->head) >> PAGE_SHIFT) + npages; 640
640 /*if (end > handle->wakeup >> PAGE_SHIFT) 641 /* if it's on a page boundary, fill up one more page */
641 end = handle->wakeup >> PAGE_SHIFT;*/ 642 if (!offset_in_page(head + handle->size + 1))
642 idx = end & (buf->nr_pages - 1); 643 npages++;
643 buf->stop_pos = idx; 644
644 idx = (local64_read(&buf->head) >> PAGE_SHIFT) + npages - 1; 645 idx = (head >> PAGE_SHIFT) + npages;
645 idx &= buf->nr_pages - 1; 646 idx &= buf->nr_pages - 1;
646 buf->intr_pos = idx; 647 buf->stop_pos = idx;
647 } 648
649 wakeup = handle->wakeup >> PAGE_SHIFT;
650
651 /* in the worst case, wake up the consumer one page before hard stop */
652 idx = (head >> PAGE_SHIFT) + npages - 1;
653 if (idx > wakeup)
654 idx = wakeup;
655
656 idx &= buf->nr_pages - 1;
657 buf->intr_pos = idx;
648 658
649 buf->topa_index[buf->stop_pos]->stop = 1; 659 buf->topa_index[buf->stop_pos]->stop = 1;
650 buf->topa_index[buf->intr_pos]->intr = 1; 660 buf->topa_index[buf->intr_pos]->intr = 1;