perf/x86: Suppress duplicated abort LBR records
authorAndi Kleen <ak@linux.intel.com>
Fri, 20 Sep 2013 14:40:44 +0000 (07:40 -0700)
committerIngo Molnar <mingo@kernel.org>
Fri, 4 Oct 2013 08:06:16 +0000 (10:06 +0200)
Haswell always give an extra LBR record after every TSX abort.
Suppress the extra record.

This only works when the abort is visible in the LBR
If the original abort has already left the 16 LBR entries
the extra entry will will stay.

Signed-off-by: Andi Kleen <ak@linux.intel.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1379688044-14173-7-git-send-email-andi@firstfloor.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
arch/x86/kernel/cpu/perf_event.h
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_lbr.c

index ce84edeeae271c4a428e930d8f04852279f3556a..fd00bb29425d4da50194241c6ae3835775e12e6e 100644 (file)
@@ -445,6 +445,7 @@ struct x86_pmu {
        int             lbr_nr;                    /* hardware stack size */
        u64             lbr_sel_mask;              /* LBR_SELECT valid bits */
        const int       *lbr_sel_map;              /* lbr_select mappings */
+       bool            lbr_double_abort;          /* duplicated lbr aborts */
 
        /*
         * Extra registers for events
index 36b5ab884c15662638bb93a837e05a2288c3ee04..0fa4f242f0504ad53297360966e957b84a0edab8 100644 (file)
@@ -2519,6 +2519,7 @@ __init int intel_pmu_init(void)
                x86_pmu.hw_config = hsw_hw_config;
                x86_pmu.get_event_constraints = hsw_get_event_constraints;
                x86_pmu.cpu_events = hsw_events_attrs;
+               x86_pmu.lbr_double_abort = true;
                pr_cont("Haswell events, ");
                break;
 
index d5be06a5005e99eb9ac8dbe808f565013bddc929..90ee6c1d0542664dbb9955ff2570e9f338e076e6 100644 (file)
@@ -284,6 +284,7 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
        int lbr_format = x86_pmu.intel_cap.lbr_format;
        u64 tos = intel_pmu_lbr_tos();
        int i;
+       int out = 0;
 
        for (i = 0; i < x86_pmu.lbr_nr; i++) {
                unsigned long lbr_idx = (tos - i) & mask;
@@ -306,15 +307,27 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
                }
                from = (u64)((((s64)from) << skip) >> skip);
 
-               cpuc->lbr_entries[i].from       = from;
-               cpuc->lbr_entries[i].to         = to;
-               cpuc->lbr_entries[i].mispred    = mis;
-               cpuc->lbr_entries[i].predicted  = pred;
-               cpuc->lbr_entries[i].in_tx      = in_tx;
-               cpuc->lbr_entries[i].abort      = abort;
-               cpuc->lbr_entries[i].reserved   = 0;
+               /*
+                * Some CPUs report duplicated abort records,
+                * with the second entry not having an abort bit set.
+                * Skip them here. This loop runs backwards,
+                * so we need to undo the previous record.
+                * If the abort just happened outside the window
+                * the extra entry cannot be removed.
+                */
+               if (abort && x86_pmu.lbr_double_abort && out > 0)
+                       out--;
+
+               cpuc->lbr_entries[out].from      = from;
+               cpuc->lbr_entries[out].to        = to;
+               cpuc->lbr_entries[out].mispred   = mis;
+               cpuc->lbr_entries[out].predicted = pred;
+               cpuc->lbr_entries[out].in_tx     = in_tx;
+               cpuc->lbr_entries[out].abort     = abort;
+               cpuc->lbr_entries[out].reserved  = 0;
+               out++;
        }
-       cpuc->lbr_stack.nr = i;
+       cpuc->lbr_stack.nr = out;
 }
 
 void intel_pmu_lbr_read(void)