diff options
| author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2011-11-20 17:30:47 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2011-12-21 05:01:11 -0500 |
| commit | 0c9d42ed4cee2aa1dfc3a260b741baae8615744f (patch) | |
| tree | 393a3a3d0be5cbd57e1d03490b3f6a5a15d5367d | |
| parent | fe4a330885aee20f233de36085fb15c38094e635 (diff) | |
perf, x86: Provide means for disabling userspace RDPMC
Allow the disabling of RDPMC via a pmu specific attribute:
echo 0 > /sys/bus/event_source/devices/cpu/rdpmc
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Cc: Arun Sharma <asharma@fb.com>
Link: http://lkml.kernel.org/n/tip-pqeog465zo5hsimtkfz73f27@git.kernel.org
Signed-off-by: Ingo Molnar <mingo@elte.hu>
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 55 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event.h | 8 | ||||
| -rw-r--r-- | include/linux/perf_event.h | 1 | ||||
| -rw-r--r-- | kernel/events/core.c | 1 |
4 files changed, 64 insertions, 1 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 53b569910175..116b040a73a8 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
| 25 | #include <linux/cpu.h> | 25 | #include <linux/cpu.h> |
| 26 | #include <linux/bitops.h> | 26 | #include <linux/bitops.h> |
| 27 | #include <linux/device.h> | ||
| 27 | 28 | ||
| 28 | #include <asm/apic.h> | 29 | #include <asm/apic.h> |
| 29 | #include <asm/stacktrace.h> | 30 | #include <asm/stacktrace.h> |
| @@ -1210,7 +1211,8 @@ x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu) | |||
| 1210 | break; | 1211 | break; |
| 1211 | 1212 | ||
| 1212 | case CPU_STARTING: | 1213 | case CPU_STARTING: |
| 1213 | set_in_cr4(X86_CR4_PCE); | 1214 | if (x86_pmu.attr_rdpmc) |
| 1215 | set_in_cr4(X86_CR4_PCE); | ||
| 1214 | if (x86_pmu.cpu_starting) | 1216 | if (x86_pmu.cpu_starting) |
| 1215 | x86_pmu.cpu_starting(cpu); | 1217 | x86_pmu.cpu_starting(cpu); |
| 1216 | break; | 1218 | break; |
| @@ -1320,6 +1322,8 @@ static int __init init_hw_perf_events(void) | |||
| 1320 | } | 1322 | } |
| 1321 | } | 1323 | } |
| 1322 | 1324 | ||
| 1325 | x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */ | ||
| 1326 | |||
| 1323 | pr_info("... version: %d\n", x86_pmu.version); | 1327 | pr_info("... version: %d\n", x86_pmu.version); |
| 1324 | pr_info("... bit width: %d\n", x86_pmu.cntval_bits); | 1328 | pr_info("... bit width: %d\n", x86_pmu.cntval_bits); |
| 1325 | pr_info("... generic registers: %d\n", x86_pmu.num_counters); | 1329 | pr_info("... generic registers: %d\n", x86_pmu.num_counters); |
| @@ -1555,10 +1559,59 @@ static int x86_pmu_event_idx(struct perf_event *event) | |||
| 1555 | return idx + 1; | 1559 | return idx + 1; |
| 1556 | } | 1560 | } |
| 1557 | 1561 | ||
| 1562 | static ssize_t get_attr_rdpmc(struct device *cdev, | ||
| 1563 | struct device_attribute *attr, | ||
| 1564 | char *buf) | ||
| 1565 | { | ||
| 1566 | return snprintf(buf, 40, "%d\n", x86_pmu.attr_rdpmc); | ||
| 1567 | } | ||
| 1568 | |||
| 1569 | static void change_rdpmc(void *info) | ||
| 1570 | { | ||
| 1571 | bool enable = !!(unsigned long)info; | ||
| 1572 | |||
| 1573 | if (enable) | ||
| 1574 | set_in_cr4(X86_CR4_PCE); | ||
| 1575 | else | ||
| 1576 | clear_in_cr4(X86_CR4_PCE); | ||
| 1577 | } | ||
| 1578 | |||
| 1579 | static ssize_t set_attr_rdpmc(struct device *cdev, | ||
| 1580 | struct device_attribute *attr, | ||
| 1581 | const char *buf, size_t count) | ||
| 1582 | { | ||
| 1583 | unsigned long val = simple_strtoul(buf, NULL, 0); | ||
| 1584 | |||
| 1585 | if (!!val != !!x86_pmu.attr_rdpmc) { | ||
| 1586 | x86_pmu.attr_rdpmc = !!val; | ||
| 1587 | smp_call_function(change_rdpmc, (void *)val, 1); | ||
| 1588 | } | ||
| 1589 | |||
| 1590 | return count; | ||
| 1591 | } | ||
| 1592 | |||
| 1593 | static DEVICE_ATTR(rdpmc, S_IRUSR | S_IWUSR, get_attr_rdpmc, set_attr_rdpmc); | ||
| 1594 | |||
| 1595 | static struct attribute *x86_pmu_attrs[] = { | ||
| 1596 | &dev_attr_rdpmc.attr, | ||
| 1597 | NULL, | ||
| 1598 | }; | ||
| 1599 | |||
| 1600 | static struct attribute_group x86_pmu_attr_group = { | ||
| 1601 | .attrs = x86_pmu_attrs, | ||
| 1602 | }; | ||
| 1603 | |||
| 1604 | static const struct attribute_group *x86_pmu_attr_groups[] = { | ||
| 1605 | &x86_pmu_attr_group, | ||
| 1606 | NULL, | ||
| 1607 | }; | ||
| 1608 | |||
| 1558 | static struct pmu pmu = { | 1609 | static struct pmu pmu = { |
| 1559 | .pmu_enable = x86_pmu_enable, | 1610 | .pmu_enable = x86_pmu_enable, |
| 1560 | .pmu_disable = x86_pmu_disable, | 1611 | .pmu_disable = x86_pmu_disable, |
| 1561 | 1612 | ||
| 1613 | .attr_groups = x86_pmu_attr_groups, | ||
| 1614 | |||
| 1562 | .event_init = x86_pmu_event_init, | 1615 | .event_init = x86_pmu_event_init, |
| 1563 | 1616 | ||
| 1564 | .add = x86_pmu_add, | 1617 | .add = x86_pmu_add, |
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 8944062f46e2..513d617b93c4 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h | |||
| @@ -307,6 +307,14 @@ struct x86_pmu { | |||
| 307 | struct x86_pmu_quirk *quirks; | 307 | struct x86_pmu_quirk *quirks; |
| 308 | int perfctr_second_write; | 308 | int perfctr_second_write; |
| 309 | 309 | ||
| 310 | /* | ||
| 311 | * sysfs attrs | ||
| 312 | */ | ||
| 313 | int attr_rdpmc; | ||
| 314 | |||
| 315 | /* | ||
| 316 | * CPU Hotplug hooks | ||
| 317 | */ | ||
| 310 | int (*cpu_prepare)(int cpu); | 318 | int (*cpu_prepare)(int cpu); |
| 311 | void (*cpu_starting)(int cpu); | 319 | void (*cpu_starting)(int cpu); |
| 312 | void (*cpu_dying)(int cpu); | 320 | void (*cpu_dying)(int cpu); |
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 02545e6df95b..5311b79fe62c 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
| @@ -615,6 +615,7 @@ struct pmu { | |||
| 615 | struct list_head entry; | 615 | struct list_head entry; |
| 616 | 616 | ||
| 617 | struct device *dev; | 617 | struct device *dev; |
| 618 | const struct attribute_group **attr_groups; | ||
| 618 | char *name; | 619 | char *name; |
| 619 | int type; | 620 | int type; |
| 620 | 621 | ||
diff --git a/kernel/events/core.c b/kernel/events/core.c index 05affc3878ff..dcd4049e92fc 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
| @@ -5505,6 +5505,7 @@ static int pmu_dev_alloc(struct pmu *pmu) | |||
| 5505 | if (!pmu->dev) | 5505 | if (!pmu->dev) |
| 5506 | goto out; | 5506 | goto out; |
| 5507 | 5507 | ||
| 5508 | pmu->dev->groups = pmu->attr_groups; | ||
| 5508 | device_initialize(pmu->dev); | 5509 | device_initialize(pmu->dev); |
| 5509 | ret = dev_set_name(pmu->dev, "%s", pmu->name); | 5510 | ret = dev_set_name(pmu->dev, "%s", pmu->name); |
| 5510 | if (ret) | 5511 | if (ret) |
