diff options
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event.h | 1 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel.c | 50 |
2 files changed, 43 insertions, 8 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 83794d8e6af0..7241e2fc3c17 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h | |||
| @@ -365,6 +365,7 @@ struct x86_pmu { | |||
| 365 | int pebs_record_size; | 365 | int pebs_record_size; |
| 366 | void (*drain_pebs)(struct pt_regs *regs); | 366 | void (*drain_pebs)(struct pt_regs *regs); |
| 367 | struct event_constraint *pebs_constraints; | 367 | struct event_constraint *pebs_constraints; |
| 368 | void (*pebs_aliases)(struct perf_event *event); | ||
| 368 | 369 | ||
| 369 | /* | 370 | /* |
| 370 | * Intel LBR | 371 | * Intel LBR |
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 965baa2fa790..2312c1ff1b19 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c | |||
| @@ -1336,15 +1336,9 @@ static void intel_put_event_constraints(struct cpu_hw_events *cpuc, | |||
| 1336 | intel_put_shared_regs_event_constraints(cpuc, event); | 1336 | intel_put_shared_regs_event_constraints(cpuc, event); |
| 1337 | } | 1337 | } |
| 1338 | 1338 | ||
| 1339 | static int intel_pmu_hw_config(struct perf_event *event) | 1339 | static void intel_pebs_aliases_core2(struct perf_event *event) |
| 1340 | { | 1340 | { |
| 1341 | int ret = x86_pmu_hw_config(event); | 1341 | if ((event->hw.config & X86_RAW_EVENT_MASK) == 0x003c) { |
| 1342 | |||
| 1343 | if (ret) | ||
| 1344 | return ret; | ||
| 1345 | |||
| 1346 | if (event->attr.precise_ip && | ||
| 1347 | (event->hw.config & X86_RAW_EVENT_MASK) == 0x003c) { | ||
| 1348 | /* | 1342 | /* |
| 1349 | * Use an alternative encoding for CPU_CLK_UNHALTED.THREAD_P | 1343 | * Use an alternative encoding for CPU_CLK_UNHALTED.THREAD_P |
| 1350 | * (0x003c) so that we can use it with PEBS. | 1344 | * (0x003c) so that we can use it with PEBS. |
| @@ -1365,10 +1359,48 @@ static int intel_pmu_hw_config(struct perf_event *event) | |||
| 1365 | */ | 1359 | */ |
| 1366 | u64 alt_config = X86_CONFIG(.event=0xc0, .inv=1, .cmask=16); | 1360 | u64 alt_config = X86_CONFIG(.event=0xc0, .inv=1, .cmask=16); |
| 1367 | 1361 | ||
| 1362 | alt_config |= (event->hw.config & ~X86_RAW_EVENT_MASK); | ||
| 1363 | event->hw.config = alt_config; | ||
| 1364 | } | ||
| 1365 | } | ||
| 1366 | |||
| 1367 | static void intel_pebs_aliases_snb(struct perf_event *event) | ||
| 1368 | { | ||
| 1369 | if ((event->hw.config & X86_RAW_EVENT_MASK) == 0x003c) { | ||
| 1370 | /* | ||
| 1371 | * Use an alternative encoding for CPU_CLK_UNHALTED.THREAD_P | ||
| 1372 | * (0x003c) so that we can use it with PEBS. | ||
| 1373 | * | ||
| 1374 | * The regular CPU_CLK_UNHALTED.THREAD_P event (0x003c) isn't | ||
| 1375 | * PEBS capable. However we can use UOPS_RETIRED.ALL | ||
| 1376 | * (0x01c2), which is a PEBS capable event, to get the same | ||
| 1377 | * count. | ||
| 1378 | * | ||
| 1379 | * UOPS_RETIRED.ALL counts the number of cycles that retires | ||
| 1380 | * CNTMASK micro-ops. By setting CNTMASK to a value (16) | ||
| 1381 | * larger than the maximum number of micro-ops that can be | ||
| 1382 | * retired per cycle (4) and then inverting the condition, we | ||
| 1383 | * count all cycles that retire 16 or less micro-ops, which | ||
| 1384 | * is every cycle. | ||
| 1385 | * | ||
| 1386 | * Thereby we gain a PEBS capable cycle counter. | ||
| 1387 | */ | ||
| 1388 | u64 alt_config = X86_CONFIG(.event=0xc2, .umask=0x01, .inv=1, .cmask=16); | ||
| 1368 | 1389 | ||
| 1369 | alt_config |= (event->hw.config & ~X86_RAW_EVENT_MASK); | 1390 | alt_config |= (event->hw.config & ~X86_RAW_EVENT_MASK); |
| 1370 | event->hw.config = alt_config; | 1391 | event->hw.config = alt_config; |
| 1371 | } | 1392 | } |
| 1393 | } | ||
| 1394 | |||
| 1395 | static int intel_pmu_hw_config(struct perf_event *event) | ||
| 1396 | { | ||
| 1397 | int ret = x86_pmu_hw_config(event); | ||
| 1398 | |||
| 1399 | if (ret) | ||
| 1400 | return ret; | ||
| 1401 | |||
| 1402 | if (event->attr.precise_ip && x86_pmu.pebs_aliases) | ||
| 1403 | x86_pmu.pebs_aliases(event); | ||
| 1372 | 1404 | ||
| 1373 | if (intel_pmu_needs_lbr_smpl(event)) { | 1405 | if (intel_pmu_needs_lbr_smpl(event)) { |
| 1374 | ret = intel_pmu_setup_lbr_filter(event); | 1406 | ret = intel_pmu_setup_lbr_filter(event); |
| @@ -1643,6 +1675,7 @@ static __initconst const struct x86_pmu intel_pmu = { | |||
| 1643 | .max_period = (1ULL << 31) - 1, | 1675 | .max_period = (1ULL << 31) - 1, |
| 1644 | .get_event_constraints = intel_get_event_constraints, | 1676 | .get_event_constraints = intel_get_event_constraints, |
| 1645 | .put_event_constraints = intel_put_event_constraints, | 1677 | .put_event_constraints = intel_put_event_constraints, |
| 1678 | .pebs_aliases = intel_pebs_aliases_core2, | ||
| 1646 | 1679 | ||
| 1647 | .format_attrs = intel_arch3_formats_attr, | 1680 | .format_attrs = intel_arch3_formats_attr, |
| 1648 | 1681 | ||
| @@ -1885,6 +1918,7 @@ __init int intel_pmu_init(void) | |||
| 1885 | 1918 | ||
| 1886 | x86_pmu.event_constraints = intel_snb_event_constraints; | 1919 | x86_pmu.event_constraints = intel_snb_event_constraints; |
| 1887 | x86_pmu.pebs_constraints = intel_snb_pebs_event_constraints; | 1920 | x86_pmu.pebs_constraints = intel_snb_pebs_event_constraints; |
| 1921 | x86_pmu.pebs_aliases = intel_pebs_aliases_snb; | ||
| 1888 | x86_pmu.extra_regs = intel_snb_extra_regs; | 1922 | x86_pmu.extra_regs = intel_snb_extra_regs; |
| 1889 | /* all extra regs are per-cpu when HT is on */ | 1923 | /* all extra regs are per-cpu when HT is on */ |
| 1890 | x86_pmu.er_flags |= ERF_HAS_RSP_1; | 1924 | x86_pmu.er_flags |= ERF_HAS_RSP_1; |
