diff options
author | Peter Zijlstra <peterz@infradead.org> | 2012-06-05 04:26:43 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2012-06-06 10:59:47 -0400 |
commit | cccb9ba9e4ee0d750265f53de9258df69655c40b (patch) | |
tree | 35d79f295087f7d94067795f0079781c060f614a /arch | |
parent | b430f7c4706aeba4270c7ab7744fc504b9315e1c (diff) |
perf/x86: Implement cycles:p for SNB/IVB
Now that there's finally a chip with working PEBS (IvyBridge), we can
enable the hardware and implement cycles:p for SNB/IVB.
Cc: Stephane Eranian <eranian@google.com>
Requested-and-tested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1338884803.28282.153.camel@twins
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch')
-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; |