From: Andi Kleen <a...@linux.intel.com>

When a weighted sample is requested, first try to report the TSX abort cost
on Haswell. If that is not available report the memory latency. This
allows profiling both by abort cost and by memory latencies.

Memory latencies requires enabling a different PEBS mode (LL).
When both address and weight is requested address wins.

The LL mode only works for memory related PEBS events, so add a
separate event constraint table for those.

I only did this for Haswell for now, but it could be added
for several other Intel CPUs too by just adding the right
table for them.

Signed-off-by: Andi Kleen <a...@linux.intel.com>
---
 arch/x86/kernel/cpu/perf_event.h          |    4 ++
 arch/x86/kernel/cpu/perf_event_intel.c    |    4 ++
 arch/x86/kernel/cpu/perf_event_intel_ds.c |   47 +++++++++++++++++++++++++++-
 3 files changed, 53 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index 17cb08f..89394e1 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -168,6 +168,7 @@ struct cpu_hw_events {
        u64                             perf_ctr_virt_mask;
 
        void                            *kfree_on_online;
+       u8                              *memory_latency_events;
 };
 
 #define __EVENT_CONSTRAINT(c, n, m, w, o) {\
@@ -388,6 +389,7 @@ struct x86_pmu {
        struct event_constraint *pebs_constraints;
        void            (*pebs_aliases)(struct perf_event *event);
        int             max_pebs_events;
+       struct event_constraint *memory_lat_events;
 
        /*
         * Intel LBR
@@ -594,6 +596,8 @@ extern struct event_constraint 
intel_ivb_pebs_event_constraints[];
 
 extern struct event_constraint intel_hsw_pebs_event_constraints[];
 
+extern struct event_constraint intel_hsw_memory_latency_events[];
+
 struct event_constraint *intel_pebs_constraints(struct perf_event *event);
 
 void intel_pmu_pebs_enable(struct perf_event *event);
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c 
b/arch/x86/kernel/cpu/perf_event_intel.c
index bbd00cc..3a7b962 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -1644,6 +1644,9 @@ static int hsw_hw_config(struct perf_event *event)
 
        if (ret)
                return ret;
+       /* PEBS cannot capture both */
+       if (event->attr.sample_type & PERF_SAMPLE_ADDR)
+               event->attr.sample_type &= ~PERF_SAMPLE_WEIGHT;
        if (!boot_cpu_has(X86_FEATURE_RTM) && !boot_cpu_has(X86_FEATURE_HLE))
                return 0;
        event->hw.config |= event->attr.config & 
(HSW_INTX|HSW_INTX_CHECKPOINTED);
@@ -2220,6 +2223,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.format_attrs = intel_hsw_formats_attr;
+               x86_pmu.memory_lat_events = intel_hsw_memory_latency_events;
                pr_cont("Haswell events, ");
                break;
 
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c 
b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index aa0f5fa..3094caa 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -456,6 +456,17 @@ struct event_constraint intel_hsw_pebs_event_constraints[] 
= {
        EVENT_CONSTRAINT_END
 };
 
+/* Subset of PEBS events supporting memory latency. Not used for scheduling */
+
+struct event_constraint intel_hsw_memory_latency_events[] = {
+       INTEL_EVENT_CONSTRAINT(0xcd, 0), /* MEM_TRANS_RETIRED.* */
+       INTEL_EVENT_CONSTRAINT(0xd0, 0), /* MEM_UOPS_RETIRED.* */
+       INTEL_EVENT_CONSTRAINT(0xd1, 0), /* MEM_LOAD_UOPS_RETIRED.* */
+       INTEL_EVENT_CONSTRAINT(0xd2, 0), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
+       INTEL_EVENT_CONSTRAINT(0xd3, 0), /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */
+       EVENT_CONSTRAINT_END
+};
+
 struct event_constraint *intel_pebs_constraints(struct perf_event *event)
 {
        struct event_constraint *c;
@@ -473,6 +484,21 @@ struct event_constraint *intel_pebs_constraints(struct 
perf_event *event)
        return &emptyconstraint;
 }
 
+static bool is_memory_lat_event(struct perf_event *event)
+{
+       struct event_constraint *c;
+
+       if (x86_pmu.intel_cap.pebs_format < 1)
+               return false;
+       if (!x86_pmu.memory_lat_events)
+               return false;
+       for_each_event_constraint(c, x86_pmu.memory_lat_events) {
+               if ((event->hw.config & c->cmask) == c->code)
+                       return true;
+       }
+       return false;
+}
+
 void intel_pmu_pebs_enable(struct perf_event *event)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
@@ -480,7 +506,12 @@ void intel_pmu_pebs_enable(struct perf_event *event)
 
        hwc->config &= ~ARCH_PERFMON_EVENTSEL_INT;
 
-       cpuc->pebs_enabled |= 1ULL << hwc->idx;
+       /* When weight is requested enable LL instead of normal PEBS */
+       if ((event->attr.sample_type & PERF_SAMPLE_WEIGHT) &&
+               is_memory_lat_event(event))
+               cpuc->pebs_enabled |= 1ULL << (32 + hwc->idx);
+       else
+               cpuc->pebs_enabled |= 1ULL << hwc->idx;
 }
 
 void intel_pmu_pebs_disable(struct perf_event *event)
@@ -488,7 +519,11 @@ void intel_pmu_pebs_disable(struct perf_event *event)
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        struct hw_perf_event *hwc = &event->hw;
 
-       cpuc->pebs_enabled &= ~(1ULL << hwc->idx);
+       if ((event->attr.sample_type & PERF_SAMPLE_WEIGHT) &&
+               is_memory_lat_event(event))
+               cpuc->pebs_enabled &= ~(1ULL << (32 + hwc->idx));
+       else
+               cpuc->pebs_enabled &= ~(1ULL << hwc->idx);
        if (cpuc->enabled)
                wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled);
 
@@ -634,6 +669,14 @@ static void __intel_pmu_pebs_event(struct perf_event 
*event,
                x86_pmu.intel_cap.pebs_format >= 2)
                data.addr = ((struct pebs_record_v2 *)pebs)->nhm.dla;
 
+       if ((event->attr.sample_type & PERF_SAMPLE_WEIGHT) &&
+           x86_pmu.intel_cap.pebs_format >= 2) {
+               data.weight = ((struct pebs_record_v2 *)pebs)->tsx_tuning &
+                               0xffffffff;
+               if (!data.weight)
+                       data.weight = ((struct pebs_record_v2 *)pebs)->nhm.lat;
+       }
+
        if (has_branch_stack(event))
                data.br_stack = &cpuc->lbr_stack;
 
-- 
1.7.7.6

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to