|
@@ -816,6 +816,32 @@ static int intel_pmu_hw_config(struct perf_event *event)
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
|
+ if (event->attr.precise_ip &&
|
|
|
+ (event->hw.config & X86_RAW_EVENT_MASK) == 0x003c) {
|
|
|
+ /*
|
|
|
+ * Use an alternative encoding for CPU_CLK_UNHALTED.THREAD_P
|
|
|
+ * (0x003c) so that we can use it with PEBS.
|
|
|
+ *
|
|
|
+ * The regular CPU_CLK_UNHALTED.THREAD_P event (0x003c) isn't
|
|
|
+ * PEBS capable. However we can use INST_RETIRED.ANY_P
|
|
|
+ * (0x00c0), which is a PEBS capable event, to get the same
|
|
|
+ * count.
|
|
|
+ *
|
|
|
+ * INST_RETIRED.ANY_P counts the number of cycles that retires
|
|
|
+ * CNTMASK instructions. By setting CNTMASK to a value (16)
|
|
|
+ * larger than the maximum number of instructions that can be
|
|
|
+ * retired per cycle (4) and then inverting the condition, we
|
|
|
+ * count all cycles that retire 16 or less instructions, which
|
|
|
+ * is every cycle.
|
|
|
+ *
|
|
|
+ * Thereby we gain a PEBS capable cycle counter.
|
|
|
+ */
|
|
|
+ u64 alt_config = 0x108000c0; /* INST_RETIRED.TOTAL_CYCLES */
|
|
|
+
|
|
|
+ alt_config |= (event->hw.config & ~X86_RAW_EVENT_MASK);
|
|
|
+ event->hw.config = alt_config;
|
|
|
+ }
|
|
|
+
|
|
|
if (event->attr.type != PERF_TYPE_RAW)
|
|
|
return 0;
|
|
|
|