aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2010-11-17 17:17:36 -0500
committerIngo Molnar <mingo@elte.hu>2010-12-16 05:36:43 -0500
commit2e80a82a49c4c7eca4e35734380f28298ba5db19 (patch)
treec60fe1cc6696c893a2c6c5891981bf8e81d9ab90
parent9f58a205c62d0dad1df38d076324a89b1a0f1d65 (diff)
perf: Dynamic pmu types
Extend the perf_pmu_register() interface to allow for named and dynamic pmu types. Because we need to support the existing static types we cannot use dynamic types for everything, hence provide a type argument. If we want to enumerate the PMUs they need a name, provide one. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <20101117222056.259707703@chello.nl> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/alpha/kernel/perf_event.c2
-rw-r--r--arch/arm/kernel/perf_event.c2
-rw-r--r--arch/powerpc/kernel/perf_event.c2
-rw-r--r--arch/powerpc/kernel/perf_event_fsl_emb.c2
-rw-r--r--arch/sh/kernel/perf_event.c2
-rw-r--r--arch/sparc/kernel/perf_event.c2
-rw-r--r--arch/x86/kernel/cpu/perf_event.c2
-rw-r--r--include/linux/perf_event.h5
-rw-r--r--kernel/hw_breakpoint.c2
-rw-r--r--kernel/perf_event.c48
10 files changed, 54 insertions, 15 deletions
diff --git a/arch/alpha/kernel/perf_event.c b/arch/alpha/kernel/perf_event.c
index 3283059b6e85..90561c45e7d8 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)
882 /* And set up PMU specification */ 882 /* And set up PMU specification */
883 alpha_pmu = &ev67_pmu; 883 alpha_pmu = &ev67_pmu;
884 884
885 perf_pmu_register(&pmu); 885 perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
886 886
887 return 0; 887 return 0;
888} 888}
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index d45f70e5f2ee..fdfa4976b0bf 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -3034,7 +3034,7 @@ init_hw_perf_events(void)
3034 pr_info("no hardware support available\n"); 3034 pr_info("no hardware support available\n");
3035 } 3035 }
3036 3036
3037 perf_pmu_register(&pmu); 3037 perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
3038 3038
3039 return 0; 3039 return 0;
3040} 3040}
diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/kernel/perf_event.c
index 3129c855933c..567480705789 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)
1379 freeze_events_kernel = MMCR0_FCHV; 1379 freeze_events_kernel = MMCR0_FCHV;
1380#endif /* CONFIG_PPC64 */ 1380#endif /* CONFIG_PPC64 */
1381 1381
1382 perf_pmu_register(&power_pmu); 1382 perf_pmu_register(&power_pmu, "cpu", PERF_TYPE_RAW);
1383 perf_cpu_notifier(power_pmu_notifier); 1383 perf_cpu_notifier(power_pmu_notifier);
1384 1384
1385 return 0; 1385 return 0;
diff --git a/arch/powerpc/kernel/perf_event_fsl_emb.c b/arch/powerpc/kernel/perf_event_fsl_emb.c
index 7ecca59ddf77..4dcf5f831e9d 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)
681 pr_info("%s performance monitor hardware support registered\n", 681 pr_info("%s performance monitor hardware support registered\n",
682 pmu->name); 682 pmu->name);
683 683
684 perf_pmu_register(&fsl_emb_pmu); 684 perf_pmu_register(&fsl_emb_pmu, "cpu", PERF_TYPE_RAW);
685 685
686 return 0; 686 return 0;
687} 687}
diff --git a/arch/sh/kernel/perf_event.c b/arch/sh/kernel/perf_event.c
index 5a4b33435650..2ee21a47b5af 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)
389 389
390 WARN_ON(_pmu->num_events > MAX_HWEVENTS); 390 WARN_ON(_pmu->num_events > MAX_HWEVENTS);
391 391
392 perf_pmu_register(&pmu); 392 perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
393 perf_cpu_notifier(sh_pmu_notifier); 393 perf_cpu_notifier(sh_pmu_notifier);
394 return 0; 394 return 0;
395} 395}
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c
index 39348b1cebd3..760578687e7c 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)
1318 1318
1319 pr_cont("Supported PMU type is '%s'\n", sparc_pmu_type); 1319 pr_cont("Supported PMU type is '%s'\n", sparc_pmu_type);
1320 1320
1321 perf_pmu_register(&pmu); 1321 perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
1322 register_die_notifier(&perf_event_nmi_notifier); 1322 register_die_notifier(&perf_event_nmi_notifier);
1323 1323
1324 return 0; 1324 return 0;
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index ce27c547fe78..0a360d146596 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)
1465 pr_info("... fixed-purpose events: %d\n", x86_pmu.num_counters_fixed); 1465 pr_info("... fixed-purpose events: %d\n", x86_pmu.num_counters_fixed);
1466 pr_info("... event mask: %016Lx\n", x86_pmu.intel_ctrl); 1466 pr_info("... event mask: %016Lx\n", x86_pmu.intel_ctrl);
1467 1467
1468 perf_pmu_register(&pmu); 1468 perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
1469 perf_cpu_notifier(x86_pmu_notifier); 1469 perf_cpu_notifier(x86_pmu_notifier);
1470 1470
1471 return 0; 1471 return 0;
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 30e50e2c7f30..21206d27466b 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -588,6 +588,9 @@ struct perf_event;
588struct pmu { 588struct pmu {
589 struct list_head entry; 589 struct list_head entry;
590 590
591 char *name;
592 int type;
593
591 int * __percpu pmu_disable_count; 594 int * __percpu pmu_disable_count;
592 struct perf_cpu_context * __percpu pmu_cpu_context; 595 struct perf_cpu_context * __percpu pmu_cpu_context;
593 int task_ctx_nr; 596 int task_ctx_nr;
@@ -916,7 +919,7 @@ struct perf_output_handle {
916 919
917#ifdef CONFIG_PERF_EVENTS 920#ifdef CONFIG_PERF_EVENTS
918 921
919extern int perf_pmu_register(struct pmu *pmu); 922extern int perf_pmu_register(struct pmu *pmu, char *name, int type);
920extern void perf_pmu_unregister(struct pmu *pmu); 923extern void perf_pmu_unregister(struct pmu *pmu);
921 924
922extern int perf_num_counters(void); 925extern int perf_num_counters(void);
diff --git a/kernel/hw_breakpoint.c b/kernel/hw_breakpoint.c
index e5325825aeb6..086adf25a55e 100644
--- a/kernel/hw_breakpoint.c
+++ b/kernel/hw_breakpoint.c
@@ -641,7 +641,7 @@ int __init init_hw_breakpoint(void)
641 641
642 constraints_initialized = 1; 642 constraints_initialized = 1;
643 643
644 perf_pmu_register(&perf_breakpoint); 644 perf_pmu_register(&perf_breakpoint, "breakpoint", PERF_TYPE_BREAKPOINT);
645 645
646 return register_die_notifier(&hw_breakpoint_exceptions_nb); 646 return register_die_notifier(&hw_breakpoint_exceptions_nb);
647 647
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index a3d568fbacc6..8f09bc877a30 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -13,6 +13,7 @@
13#include <linux/mm.h> 13#include <linux/mm.h>
14#include <linux/cpu.h> 14#include <linux/cpu.h>
15#include <linux/smp.h> 15#include <linux/smp.h>
16#include <linux/idr.h>
16#include <linux/file.h> 17#include <linux/file.h>
17#include <linux/poll.h> 18#include <linux/poll.h>
18#include <linux/slab.h> 19#include <linux/slab.h>
@@ -4961,7 +4962,7 @@ static struct pmu perf_tracepoint = {
4961 4962
4962static inline void perf_tp_register(void) 4963static inline void perf_tp_register(void)
4963{ 4964{
4964 perf_pmu_register(&perf_tracepoint); 4965 perf_pmu_register(&perf_tracepoint, "tracepoint", PERF_TYPE_TRACEPOINT);
4965} 4966}
4966 4967
4967static int perf_event_set_filter(struct perf_event *event, void __user *arg) 4968static int perf_event_set_filter(struct perf_event *event, void __user *arg)
@@ -5305,8 +5306,9 @@ static void free_pmu_context(struct pmu *pmu)
5305out: 5306out:
5306 mutex_unlock(&pmus_lock); 5307 mutex_unlock(&pmus_lock);
5307} 5308}
5309static struct idr pmu_idr;
5308 5310
5309int perf_pmu_register(struct pmu *pmu) 5311int perf_pmu_register(struct pmu *pmu, char *name, int type)
5310{ 5312{
5311 int cpu, ret; 5313 int cpu, ret;
5312 5314
@@ -5316,13 +5318,32 @@ int perf_pmu_register(struct pmu *pmu)
5316 if (!pmu->pmu_disable_count) 5318 if (!pmu->pmu_disable_count)
5317 goto unlock; 5319 goto unlock;
5318 5320
5321 pmu->type = -1;
5322 if (!name)
5323 goto skip_type;
5324 pmu->name = name;
5325
5326 if (type < 0) {
5327 int err = idr_pre_get(&pmu_idr, GFP_KERNEL);
5328 if (!err)
5329 goto free_pdc;
5330
5331 err = idr_get_new_above(&pmu_idr, pmu, PERF_TYPE_MAX, &type);
5332 if (err) {
5333 ret = err;
5334 goto free_pdc;
5335 }
5336 }
5337 pmu->type = type;
5338
5339skip_type:
5319 pmu->pmu_cpu_context = find_pmu_context(pmu->task_ctx_nr); 5340 pmu->pmu_cpu_context = find_pmu_context(pmu->task_ctx_nr);
5320 if (pmu->pmu_cpu_context) 5341 if (pmu->pmu_cpu_context)
5321 goto got_cpu_context; 5342 goto got_cpu_context;
5322 5343
5323 pmu->pmu_cpu_context = alloc_percpu(struct perf_cpu_context); 5344 pmu->pmu_cpu_context = alloc_percpu(struct perf_cpu_context);
5324 if (!pmu->pmu_cpu_context) 5345 if (!pmu->pmu_cpu_context)
5325 goto free_pdc; 5346 goto free_ird;
5326 5347
5327 for_each_possible_cpu(cpu) { 5348 for_each_possible_cpu(cpu) {
5328 struct perf_cpu_context *cpuctx; 5349 struct perf_cpu_context *cpuctx;
@@ -5366,6 +5387,10 @@ unlock:
5366 5387
5367 return ret; 5388 return ret;
5368 5389
5390free_idr:
5391 if (pmu->type >= PERF_TYPE_MAX)
5392 idr_remove(&pmu_idr, pmu->type);
5393
5369free_pdc: 5394free_pdc:
5370 free_percpu(pmu->pmu_disable_count); 5395 free_percpu(pmu->pmu_disable_count);
5371 goto unlock; 5396 goto unlock;
@@ -5385,6 +5410,8 @@ void perf_pmu_unregister(struct pmu *pmu)
5385 synchronize_rcu(); 5410 synchronize_rcu();
5386 5411
5387 free_percpu(pmu->pmu_disable_count); 5412 free_percpu(pmu->pmu_disable_count);
5413 if (pmu->type >= PERF_TYPE_MAX)
5414 idr_remove(&pmu_idr, pmu->type);
5388 free_pmu_context(pmu); 5415 free_pmu_context(pmu);
5389} 5416}
5390 5417
@@ -5394,6 +5421,13 @@ struct pmu *perf_init_event(struct perf_event *event)
5394 int idx; 5421 int idx;
5395 5422
5396 idx = srcu_read_lock(&pmus_srcu); 5423 idx = srcu_read_lock(&pmus_srcu);
5424
5425 rcu_read_lock();
5426 pmu = idr_find(&pmu_idr, event->attr.type);
5427 rcu_read_unlock();
5428 if (pmu)
5429 goto unlock;
5430
5397 list_for_each_entry_rcu(pmu, &pmus, entry) { 5431 list_for_each_entry_rcu(pmu, &pmus, entry) {
5398 int ret = pmu->event_init(event); 5432 int ret = pmu->event_init(event);
5399 if (!ret) 5433 if (!ret)
@@ -6555,11 +6589,13 @@ void __init perf_event_init(void)
6555{ 6589{
6556 int ret; 6590 int ret;
6557 6591
6592 idr_init(&pmu_idr);
6593
6558 perf_event_init_all_cpus(); 6594 perf_event_init_all_cpus();
6559 init_srcu_struct(&pmus_srcu); 6595 init_srcu_struct(&pmus_srcu);
6560 perf_pmu_register(&perf_swevent); 6596 perf_pmu_register(&perf_swevent, "software", PERF_TYPE_SOFTWARE);
6561 perf_pmu_register(&perf_cpu_clock); 6597 perf_pmu_register(&perf_cpu_clock, NULL, -1);
6562 perf_pmu_register(&perf_task_clock); 6598 perf_pmu_register(&perf_task_clock, NULL, -1);
6563 perf_tp_register(); 6599 perf_tp_register();
6564 perf_cpu_notifier(perf_cpu_notify); 6600 perf_cpu_notifier(perf_cpu_notify);
6565 register_reboot_notifier(&perf_reboot_notifier); 6601 register_reboot_notifier(&perf_reboot_notifier);