diff options
| -rw-r--r-- | arch/alpha/kernel/perf_event.c | 2 | ||||
| -rw-r--r-- | arch/arm/kernel/perf_event.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/kernel/perf_event.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/kernel/perf_event_fsl_emb.c | 2 | ||||
| -rw-r--r-- | arch/sh/kernel/perf_event.c | 2 | ||||
| -rw-r--r-- | arch/sparc/kernel/perf_event.c | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 2 | ||||
| -rw-r--r-- | include/linux/perf_event.h | 5 | ||||
| -rw-r--r-- | kernel/hw_breakpoint.c | 2 | ||||
| -rw-r--r-- | kernel/perf_event.c | 48 | 
10 files changed, 54 insertions, 15 deletions
diff --git a/arch/alpha/kernel/perf_event.c b/arch/alpha/kernel/perf_event.c index 3283059b6e8..90561c45e7d 100644 --- a/arch/alpha/kernel/perf_event.c +++ b/arch/alpha/kernel/perf_event.c @@ -882,7 +882,7 @@ int __init init_hw_perf_events(void)  	/* And set up PMU specification */  	alpha_pmu = &ev67_pmu; -	perf_pmu_register(&pmu); +	perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);  	return 0;  } diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index d45f70e5f2e..fdfa4976b0b 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -3034,7 +3034,7 @@ init_hw_perf_events(void)  		pr_info("no hardware support available\n");  	} -	perf_pmu_register(&pmu); +	perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);  	return 0;  } diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/kernel/perf_event.c index 3129c855933..56748070578 100644 --- a/arch/powerpc/kernel/perf_event.c +++ b/arch/powerpc/kernel/perf_event.c @@ -1379,7 +1379,7 @@ int register_power_pmu(struct power_pmu *pmu)  		freeze_events_kernel = MMCR0_FCHV;  #endif /* CONFIG_PPC64 */ -	perf_pmu_register(&power_pmu); +	perf_pmu_register(&power_pmu, "cpu", PERF_TYPE_RAW);  	perf_cpu_notifier(power_pmu_notifier);  	return 0; diff --git a/arch/powerpc/kernel/perf_event_fsl_emb.c b/arch/powerpc/kernel/perf_event_fsl_emb.c index 7ecca59ddf7..4dcf5f831e9 100644 --- a/arch/powerpc/kernel/perf_event_fsl_emb.c +++ b/arch/powerpc/kernel/perf_event_fsl_emb.c @@ -681,7 +681,7 @@ int register_fsl_emb_pmu(struct fsl_emb_pmu *pmu)  	pr_info("%s performance monitor hardware support registered\n",  		pmu->name); -	perf_pmu_register(&fsl_emb_pmu); +	perf_pmu_register(&fsl_emb_pmu, "cpu", PERF_TYPE_RAW);  	return 0;  } diff --git a/arch/sh/kernel/perf_event.c b/arch/sh/kernel/perf_event.c index 5a4b3343565..2ee21a47b5a 100644 --- a/arch/sh/kernel/perf_event.c +++ b/arch/sh/kernel/perf_event.c @@ -389,7 +389,7 @@ int __cpuinit register_sh_pmu(struct sh_pmu *_pmu)  	WARN_ON(_pmu->num_events > MAX_HWEVENTS); -	perf_pmu_register(&pmu); +	perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);  	perf_cpu_notifier(sh_pmu_notifier);  	return 0;  } diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index 39348b1cebd..760578687e7 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -1318,7 +1318,7 @@ int __init init_hw_perf_events(void)  	pr_cont("Supported PMU type is '%s'\n", sparc_pmu_type); -	perf_pmu_register(&pmu); +	perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);  	register_die_notifier(&perf_event_nmi_notifier);  	return 0; diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index ce27c547fe7..0a360d14659 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1465,7 +1465,7 @@ int __init init_hw_perf_events(void)  	pr_info("... fixed-purpose events:   %d\n",     x86_pmu.num_counters_fixed);  	pr_info("... event mask:             %016Lx\n", x86_pmu.intel_ctrl); -	perf_pmu_register(&pmu); +	perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);  	perf_cpu_notifier(x86_pmu_notifier);  	return 0; diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 30e50e2c7f3..21206d27466 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -588,6 +588,9 @@ struct perf_event;  struct pmu {  	struct list_head		entry; +	char				*name; +	int				type; +  	int * __percpu			pmu_disable_count;  	struct perf_cpu_context * __percpu pmu_cpu_context;  	int				task_ctx_nr; @@ -916,7 +919,7 @@ struct perf_output_handle {  #ifdef CONFIG_PERF_EVENTS -extern int perf_pmu_register(struct pmu *pmu); +extern int perf_pmu_register(struct pmu *pmu, char *name, int type);  extern void perf_pmu_unregister(struct pmu *pmu);  extern int perf_num_counters(void); diff --git a/kernel/hw_breakpoint.c b/kernel/hw_breakpoint.c index e5325825aeb..086adf25a55 100644 --- a/kernel/hw_breakpoint.c +++ b/kernel/hw_breakpoint.c @@ -641,7 +641,7 @@ int __init init_hw_breakpoint(void)  	constraints_initialized = 1; -	perf_pmu_register(&perf_breakpoint); +	perf_pmu_register(&perf_breakpoint, "breakpoint", PERF_TYPE_BREAKPOINT);  	return register_die_notifier(&hw_breakpoint_exceptions_nb); diff --git a/kernel/perf_event.c b/kernel/perf_event.c index a3d568fbacc..8f09bc877a3 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -13,6 +13,7 @@  #include <linux/mm.h>  #include <linux/cpu.h>  #include <linux/smp.h> +#include <linux/idr.h>  #include <linux/file.h>  #include <linux/poll.h>  #include <linux/slab.h> @@ -4961,7 +4962,7 @@ static struct pmu perf_tracepoint = {  static inline void perf_tp_register(void)  { -	perf_pmu_register(&perf_tracepoint); +	perf_pmu_register(&perf_tracepoint, "tracepoint", PERF_TYPE_TRACEPOINT);  }  static int perf_event_set_filter(struct perf_event *event, void __user *arg) @@ -5305,8 +5306,9 @@ static void free_pmu_context(struct pmu *pmu)  out:  	mutex_unlock(&pmus_lock);  } +static struct idr pmu_idr; -int perf_pmu_register(struct pmu *pmu) +int perf_pmu_register(struct pmu *pmu, char *name, int type)  {  	int cpu, ret; @@ -5316,13 +5318,32 @@ int perf_pmu_register(struct pmu *pmu)  	if (!pmu->pmu_disable_count)  		goto unlock; +	pmu->type = -1; +	if (!name) +		goto skip_type; +	pmu->name = name; + +	if (type < 0) { +		int err = idr_pre_get(&pmu_idr, GFP_KERNEL); +		if (!err) +			goto free_pdc; + +		err = idr_get_new_above(&pmu_idr, pmu, PERF_TYPE_MAX, &type); +		if (err) { +			ret = err; +			goto free_pdc; +		} +	} +	pmu->type = type; + +skip_type:  	pmu->pmu_cpu_context = find_pmu_context(pmu->task_ctx_nr);  	if (pmu->pmu_cpu_context)  		goto got_cpu_context;  	pmu->pmu_cpu_context = alloc_percpu(struct perf_cpu_context);  	if (!pmu->pmu_cpu_context) -		goto free_pdc; +		goto free_ird;  	for_each_possible_cpu(cpu) {  		struct perf_cpu_context *cpuctx; @@ -5366,6 +5387,10 @@ unlock:  	return ret; +free_idr: +	if (pmu->type >= PERF_TYPE_MAX) +		idr_remove(&pmu_idr, pmu->type); +  free_pdc:  	free_percpu(pmu->pmu_disable_count);  	goto unlock; @@ -5385,6 +5410,8 @@ void perf_pmu_unregister(struct pmu *pmu)  	synchronize_rcu();  	free_percpu(pmu->pmu_disable_count); +	if (pmu->type >= PERF_TYPE_MAX) +		idr_remove(&pmu_idr, pmu->type);  	free_pmu_context(pmu);  } @@ -5394,6 +5421,13 @@ struct pmu *perf_init_event(struct perf_event *event)  	int idx;  	idx = srcu_read_lock(&pmus_srcu); + +	rcu_read_lock(); +	pmu = idr_find(&pmu_idr, event->attr.type); +	rcu_read_unlock(); +	if (pmu) +		goto unlock; +  	list_for_each_entry_rcu(pmu, &pmus, entry) {  		int ret = pmu->event_init(event);  		if (!ret) @@ -6555,11 +6589,13 @@ void __init perf_event_init(void)  {  	int ret; +	idr_init(&pmu_idr); +  	perf_event_init_all_cpus();  	init_srcu_struct(&pmus_srcu); -	perf_pmu_register(&perf_swevent); -	perf_pmu_register(&perf_cpu_clock); -	perf_pmu_register(&perf_task_clock); +	perf_pmu_register(&perf_swevent, "software", PERF_TYPE_SOFTWARE); +	perf_pmu_register(&perf_cpu_clock, NULL, -1); +	perf_pmu_register(&perf_task_clock, NULL, -1);  	perf_tp_register();  	perf_cpu_notifier(perf_cpu_notify);  	register_reboot_notifier(&perf_reboot_notifier);  |