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>
This commit is contained in:
parent
fe4a330885
commit
0c9d42ed4c
@ -24,6 +24,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include <asm/apic.h>
|
||||
#include <asm/stacktrace.h>
|
||||
@ -1210,7 +1211,8 @@ x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
|
||||
break;
|
||||
|
||||
case CPU_STARTING:
|
||||
set_in_cr4(X86_CR4_PCE);
|
||||
if (x86_pmu.attr_rdpmc)
|
||||
set_in_cr4(X86_CR4_PCE);
|
||||
if (x86_pmu.cpu_starting)
|
||||
x86_pmu.cpu_starting(cpu);
|
||||
break;
|
||||
@ -1320,6 +1322,8 @@ static int __init init_hw_perf_events(void)
|
||||
}
|
||||
}
|
||||
|
||||
x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */
|
||||
|
||||
pr_info("... version: %d\n", x86_pmu.version);
|
||||
pr_info("... bit width: %d\n", x86_pmu.cntval_bits);
|
||||
pr_info("... generic registers: %d\n", x86_pmu.num_counters);
|
||||
@ -1555,10 +1559,59 @@ static int x86_pmu_event_idx(struct perf_event *event)
|
||||
return idx + 1;
|
||||
}
|
||||
|
||||
static ssize_t get_attr_rdpmc(struct device *cdev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return snprintf(buf, 40, "%d\n", x86_pmu.attr_rdpmc);
|
||||
}
|
||||
|
||||
static void change_rdpmc(void *info)
|
||||
{
|
||||
bool enable = !!(unsigned long)info;
|
||||
|
||||
if (enable)
|
||||
set_in_cr4(X86_CR4_PCE);
|
||||
else
|
||||
clear_in_cr4(X86_CR4_PCE);
|
||||
}
|
||||
|
||||
static ssize_t set_attr_rdpmc(struct device *cdev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned long val = simple_strtoul(buf, NULL, 0);
|
||||
|
||||
if (!!val != !!x86_pmu.attr_rdpmc) {
|
||||
x86_pmu.attr_rdpmc = !!val;
|
||||
smp_call_function(change_rdpmc, (void *)val, 1);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(rdpmc, S_IRUSR | S_IWUSR, get_attr_rdpmc, set_attr_rdpmc);
|
||||
|
||||
static struct attribute *x86_pmu_attrs[] = {
|
||||
&dev_attr_rdpmc.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group x86_pmu_attr_group = {
|
||||
.attrs = x86_pmu_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *x86_pmu_attr_groups[] = {
|
||||
&x86_pmu_attr_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct pmu pmu = {
|
||||
.pmu_enable = x86_pmu_enable,
|
||||
.pmu_disable = x86_pmu_disable,
|
||||
|
||||
.attr_groups = x86_pmu_attr_groups,
|
||||
|
||||
.event_init = x86_pmu_event_init,
|
||||
|
||||
.add = x86_pmu_add,
|
||||
|
@ -307,6 +307,14 @@ struct x86_pmu {
|
||||
struct x86_pmu_quirk *quirks;
|
||||
int perfctr_second_write;
|
||||
|
||||
/*
|
||||
* sysfs attrs
|
||||
*/
|
||||
int attr_rdpmc;
|
||||
|
||||
/*
|
||||
* CPU Hotplug hooks
|
||||
*/
|
||||
int (*cpu_prepare)(int cpu);
|
||||
void (*cpu_starting)(int cpu);
|
||||
void (*cpu_dying)(int cpu);
|
||||
|
@ -615,6 +615,7 @@ struct pmu {
|
||||
struct list_head entry;
|
||||
|
||||
struct device *dev;
|
||||
const struct attribute_group **attr_groups;
|
||||
char *name;
|
||||
int type;
|
||||
|
||||
|
@ -5505,6 +5505,7 @@ static int pmu_dev_alloc(struct pmu *pmu)
|
||||
if (!pmu->dev)
|
||||
goto out;
|
||||
|
||||
pmu->dev->groups = pmu->attr_groups;
|
||||
device_initialize(pmu->dev);
|
||||
ret = dev_set_name(pmu->dev, "%s", pmu->name);
|
||||
if (ret)
|
||||
|
Loading…
Reference in New Issue
Block a user