aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2011-12-06 08:07:15 -0500
committerIngo Molnar <mingo@elte.hu>2011-12-06 14:41:06 -0500
commitc1d6f42f1a42c721513e2f388c208e5348004f64 (patch)
treec30bac2feecd91ceb012eb5523568360f40ce9a3 /arch
parentffb871bc9156ee2e5cf442f61250c5bd6aad17e3 (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.c5
-rw-r--r--arch/x86/kernel/cpu/perf_event.h16
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel.c80
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
1249static int __init init_hw_perf_events(void) 1249static 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
264struct 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_) \
349do { \
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
1522static void intel_clovertown_quirks(void) 1522static __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
1548static void intel_sandybridge_quirks(void) 1548static __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
1555static const int intel_event_id_to_hw_id[] __initconst = { 1555static 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
1565static __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
1577static __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}