diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2011-12-06 08:07:15 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-12-06 14:41:06 -0500 |
commit | c1d6f42f1a42c721513e2f388c208e5348004f64 (patch) | |
tree | c30bac2feecd91ceb012eb5523568360f40ce9a3 /arch | |
parent | ffb871bc9156ee2e5cf442f61250c5bd6aad17e3 (diff) |
perf, x86: Implement arch event mask as quirk
Implement the disabling of arch events as a quirk so that we can print
a message along with it. This creates some visibility into the problem
space and could allow us to work on adding more work-around like the
AAJ80 one.
Requested-by: Ingo Molnar <mingo@elte.hu>
Cc: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/n/tip-wcja2z48wklzu1b0nkz0a5y7@git.kernel.org
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 5 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.h | 16 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel.c | 80 |
3 files changed, 68 insertions, 33 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 66f8ba9a67f9..55889e0b1452 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
@@ -1248,6 +1248,7 @@ static void __init pmu_check_apic(void) | |||
1248 | 1248 | ||
1249 | static int __init init_hw_perf_events(void) | 1249 | static int __init init_hw_perf_events(void) |
1250 | { | 1250 | { |
1251 | struct x86_pmu_quirk *quirk; | ||
1251 | struct event_constraint *c; | 1252 | struct event_constraint *c; |
1252 | int err; | 1253 | int err; |
1253 | 1254 | ||
@@ -1276,8 +1277,8 @@ static int __init init_hw_perf_events(void) | |||
1276 | 1277 | ||
1277 | pr_cont("%s PMU driver.\n", x86_pmu.name); | 1278 | pr_cont("%s PMU driver.\n", x86_pmu.name); |
1278 | 1279 | ||
1279 | if (x86_pmu.quirks) | 1280 | for (quirk = x86_pmu.quirks; quirk; quirk = quirk->next) |
1280 | x86_pmu.quirks(); | 1281 | quirk->func(); |
1281 | 1282 | ||
1282 | if (x86_pmu.num_counters > X86_PMC_MAX_GENERIC) { | 1283 | if (x86_pmu.num_counters > X86_PMC_MAX_GENERIC) { |
1283 | WARN(1, KERN_ERR "hw perf events %d > max(%d), clipping!", | 1284 | WARN(1, KERN_ERR "hw perf events %d > max(%d), clipping!", |
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index f49c5c21085c..8944062f46e2 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h | |||
@@ -261,6 +261,11 @@ union perf_capabilities { | |||
261 | u64 capabilities; | 261 | u64 capabilities; |
262 | }; | 262 | }; |
263 | 263 | ||
264 | struct x86_pmu_quirk { | ||
265 | struct x86_pmu_quirk *next; | ||
266 | void (*func)(void); | ||
267 | }; | ||
268 | |||
264 | /* | 269 | /* |
265 | * struct x86_pmu - generic x86 pmu | 270 | * struct x86_pmu - generic x86 pmu |
266 | */ | 271 | */ |
@@ -299,7 +304,7 @@ struct x86_pmu { | |||
299 | void (*put_event_constraints)(struct cpu_hw_events *cpuc, | 304 | void (*put_event_constraints)(struct cpu_hw_events *cpuc, |
300 | struct perf_event *event); | 305 | struct perf_event *event); |
301 | struct event_constraint *event_constraints; | 306 | struct event_constraint *event_constraints; |
302 | void (*quirks)(void); | 307 | struct x86_pmu_quirk *quirks; |
303 | int perfctr_second_write; | 308 | int perfctr_second_write; |
304 | 309 | ||
305 | int (*cpu_prepare)(int cpu); | 310 | int (*cpu_prepare)(int cpu); |
@@ -340,6 +345,15 @@ struct x86_pmu { | |||
340 | struct perf_guest_switch_msr *(*guest_get_msrs)(int *nr); | 345 | struct perf_guest_switch_msr *(*guest_get_msrs)(int *nr); |
341 | }; | 346 | }; |
342 | 347 | ||
348 | #define x86_add_quirk(func_) \ | ||
349 | do { \ | ||
350 | static struct x86_pmu_quirk __quirk __initdata = { \ | ||
351 | .func = func_, \ | ||
352 | }; \ | ||
353 | __quirk.next = x86_pmu.quirks; \ | ||
354 | x86_pmu.quirks = &__quirk; \ | ||
355 | } while (0) | ||
356 | |||
343 | #define ERF_NO_HT_SHARING 1 | 357 | #define ERF_NO_HT_SHARING 1 |
344 | #define ERF_HAS_RSP_1 2 | 358 | #define ERF_HAS_RSP_1 2 |
345 | 359 | ||
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 201156b80a37..2c3bf53d0302 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c | |||
@@ -1519,7 +1519,7 @@ static __initconst const struct x86_pmu intel_pmu = { | |||
1519 | .guest_get_msrs = intel_guest_get_msrs, | 1519 | .guest_get_msrs = intel_guest_get_msrs, |
1520 | }; | 1520 | }; |
1521 | 1521 | ||
1522 | static void intel_clovertown_quirks(void) | 1522 | static __init void intel_clovertown_quirk(void) |
1523 | { | 1523 | { |
1524 | /* | 1524 | /* |
1525 | * PEBS is unreliable due to: | 1525 | * PEBS is unreliable due to: |
@@ -1545,30 +1545,61 @@ static void intel_clovertown_quirks(void) | |||
1545 | x86_pmu.pebs_constraints = NULL; | 1545 | x86_pmu.pebs_constraints = NULL; |
1546 | } | 1546 | } |
1547 | 1547 | ||
1548 | static void intel_sandybridge_quirks(void) | 1548 | static __init void intel_sandybridge_quirk(void) |
1549 | { | 1549 | { |
1550 | printk(KERN_WARNING "PEBS disabled due to CPU errata.\n"); | 1550 | printk(KERN_WARNING "PEBS disabled due to CPU errata.\n"); |
1551 | x86_pmu.pebs = 0; | 1551 | x86_pmu.pebs = 0; |
1552 | x86_pmu.pebs_constraints = NULL; | 1552 | x86_pmu.pebs_constraints = NULL; |
1553 | } | 1553 | } |
1554 | 1554 | ||
1555 | static const int intel_event_id_to_hw_id[] __initconst = { | 1555 | static const struct { int id; char *name; } intel_arch_events_map[] __initconst = { |
1556 | PERF_COUNT_HW_CPU_CYCLES, | 1556 | { PERF_COUNT_HW_CPU_CYCLES, "cpu cycles" }, |
1557 | PERF_COUNT_HW_INSTRUCTIONS, | 1557 | { PERF_COUNT_HW_INSTRUCTIONS, "instructions" }, |
1558 | PERF_COUNT_HW_BUS_CYCLES, | 1558 | { PERF_COUNT_HW_BUS_CYCLES, "bus cycles" }, |
1559 | PERF_COUNT_HW_CACHE_REFERENCES, | 1559 | { PERF_COUNT_HW_CACHE_REFERENCES, "cache references" }, |
1560 | PERF_COUNT_HW_CACHE_MISSES, | 1560 | { PERF_COUNT_HW_CACHE_MISSES, "cache misses" }, |
1561 | PERF_COUNT_HW_BRANCH_INSTRUCTIONS, | 1561 | { PERF_COUNT_HW_BRANCH_INSTRUCTIONS, "branch instructions" }, |
1562 | PERF_COUNT_HW_BRANCH_MISSES, | 1562 | { PERF_COUNT_HW_BRANCH_MISSES, "branch misses" }, |
1563 | }; | 1563 | }; |
1564 | 1564 | ||
1565 | static __init void intel_arch_events_quirk(void) | ||
1566 | { | ||
1567 | int bit; | ||
1568 | |||
1569 | /* disable event that reported as not presend by cpuid */ | ||
1570 | for_each_set_bit(bit, x86_pmu.events_mask, ARRAY_SIZE(intel_arch_events_map)) { | ||
1571 | intel_perfmon_event_map[intel_arch_events_map[bit].id] = 0; | ||
1572 | printk(KERN_WARNING "CPUID marked event: \'%s\' unavailable\n", | ||
1573 | intel_arch_events_map[bit].name); | ||
1574 | } | ||
1575 | } | ||
1576 | |||
1577 | static __init void intel_nehalem_quirk(void) | ||
1578 | { | ||
1579 | union cpuid10_ebx ebx; | ||
1580 | |||
1581 | ebx.full = x86_pmu.events_maskl; | ||
1582 | if (ebx.split.no_branch_misses_retired) { | ||
1583 | /* | ||
1584 | * Erratum AAJ80 detected, we work it around by using | ||
1585 | * the BR_MISP_EXEC.ANY event. This will over-count | ||
1586 | * branch-misses, but it's still much better than the | ||
1587 | * architectural event which is often completely bogus: | ||
1588 | */ | ||
1589 | intel_perfmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x7f89; | ||
1590 | ebx.split.no_branch_misses_retired = 0; | ||
1591 | x86_pmu.events_maskl = ebx.full; | ||
1592 | printk(KERN_INFO "CPU erratum AAJ80 worked around\n"); | ||
1593 | } | ||
1594 | } | ||
1595 | |||
1565 | __init int intel_pmu_init(void) | 1596 | __init int intel_pmu_init(void) |
1566 | { | 1597 | { |
1567 | union cpuid10_edx edx; | 1598 | union cpuid10_edx edx; |
1568 | union cpuid10_eax eax; | 1599 | union cpuid10_eax eax; |
1569 | union cpuid10_ebx ebx; | 1600 | union cpuid10_ebx ebx; |
1570 | unsigned int unused; | 1601 | unsigned int unused; |
1571 | int version, bit; | 1602 | int version; |
1572 | 1603 | ||
1573 | if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) { | 1604 | if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) { |
1574 | switch (boot_cpu_data.x86) { | 1605 | switch (boot_cpu_data.x86) { |
@@ -1599,6 +1630,9 @@ __init int intel_pmu_init(void) | |||
1599 | x86_pmu.cntval_bits = eax.split.bit_width; | 1630 | x86_pmu.cntval_bits = eax.split.bit_width; |
1600 | x86_pmu.cntval_mask = (1ULL << eax.split.bit_width) - 1; | 1631 | x86_pmu.cntval_mask = (1ULL << eax.split.bit_width) - 1; |
1601 | 1632 | ||
1633 | x86_pmu.events_maskl = ebx.full; | ||
1634 | x86_pmu.events_mask_len = eax.split.mask_length; | ||
1635 | |||
1602 | /* | 1636 | /* |
1603 | * Quirk: v2 perfmon does not report fixed-purpose events, so | 1637 | * Quirk: v2 perfmon does not report fixed-purpose events, so |
1604 | * assume at least 3 events: | 1638 | * assume at least 3 events: |
@@ -1618,6 +1652,8 @@ __init int intel_pmu_init(void) | |||
1618 | 1652 | ||
1619 | intel_ds_init(); | 1653 | intel_ds_init(); |
1620 | 1654 | ||
1655 | x86_add_quirk(intel_arch_events_quirk); /* Install first, so it runs last */ | ||
1656 | |||
1621 | /* | 1657 | /* |
1622 | * Install the hw-cache-events table: | 1658 | * Install the hw-cache-events table: |
1623 | */ | 1659 | */ |
@@ -1627,7 +1663,7 @@ __init int intel_pmu_init(void) | |||
1627 | break; | 1663 | break; |
1628 | 1664 | ||
1629 | case 15: /* original 65 nm celeron/pentium/core2/xeon, "Merom"/"Conroe" */ | 1665 | case 15: /* original 65 nm celeron/pentium/core2/xeon, "Merom"/"Conroe" */ |
1630 | x86_pmu.quirks = intel_clovertown_quirks; | 1666 | x86_add_quirk(intel_clovertown_quirk); |
1631 | case 22: /* single-core 65 nm celeron/core2solo "Merom-L"/"Conroe-L" */ | 1667 | case 22: /* single-core 65 nm celeron/core2solo "Merom-L"/"Conroe-L" */ |
1632 | case 23: /* current 45 nm celeron/core2/xeon "Penryn"/"Wolfdale" */ | 1668 | case 23: /* current 45 nm celeron/core2/xeon "Penryn"/"Wolfdale" */ |
1633 | case 29: /* six-core 45 nm xeon "Dunnington" */ | 1669 | case 29: /* six-core 45 nm xeon "Dunnington" */ |
@@ -1661,18 +1697,8 @@ __init int intel_pmu_init(void) | |||
1661 | /* UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */ | 1697 | /* UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */ |
1662 | intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x1803fb1; | 1698 | intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x1803fb1; |
1663 | 1699 | ||
1664 | if (ebx.split.no_branch_misses_retired) { | 1700 | x86_add_quirk(intel_nehalem_quirk); |
1665 | /* | ||
1666 | * Erratum AAJ80 detected, we work it around by using | ||
1667 | * the BR_MISP_EXEC.ANY event. This will over-count | ||
1668 | * branch-misses, but it's still much better than the | ||
1669 | * architectural event which is often completely bogus: | ||
1670 | */ | ||
1671 | intel_perfmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x7f89; | ||
1672 | ebx.split.no_branch_misses_retired = 0; | ||
1673 | 1701 | ||
1674 | pr_cont("erratum AAJ80 worked around, "); | ||
1675 | } | ||
1676 | pr_cont("Nehalem events, "); | 1702 | pr_cont("Nehalem events, "); |
1677 | break; | 1703 | break; |
1678 | 1704 | ||
@@ -1712,7 +1738,7 @@ __init int intel_pmu_init(void) | |||
1712 | break; | 1738 | break; |
1713 | 1739 | ||
1714 | case 42: /* SandyBridge */ | 1740 | case 42: /* SandyBridge */ |
1715 | x86_pmu.quirks = intel_sandybridge_quirks; | 1741 | x86_add_quirk(intel_sandybridge_quirk); |
1716 | case 45: /* SandyBridge, "Romely-EP" */ | 1742 | case 45: /* SandyBridge, "Romely-EP" */ |
1717 | memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, | 1743 | memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, |
1718 | sizeof(hw_cache_event_ids)); | 1744 | sizeof(hw_cache_event_ids)); |
@@ -1749,12 +1775,6 @@ __init int intel_pmu_init(void) | |||
1749 | break; | 1775 | break; |
1750 | } | 1776 | } |
1751 | } | 1777 | } |
1752 | x86_pmu.events_maskl = ebx.full; | ||
1753 | x86_pmu.events_mask_len = eax.split.mask_length; | ||
1754 | |||
1755 | /* disable event that reported as not presend by cpuid */ | ||
1756 | for_each_set_bit(bit, x86_pmu.events_mask, ARRAY_SIZE(intel_event_id_to_hw_id)) | ||
1757 | intel_perfmon_event_map[intel_event_id_to_hw_id[bit]] = 0; | ||
1758 | 1778 | ||
1759 | return 0; | 1779 | return 0; |
1760 | } | 1780 | } |