diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2010-11-17 17:17:36 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-12-16 05:36:43 -0500 |
commit | 2e80a82a49c4c7eca4e35734380f28298ba5db19 (patch) | |
tree | c60fe1cc6696c893a2c6c5891981bf8e81d9ab90 | |
parent | 9f58a205c62d0dad1df38d076324a89b1a0f1d65 (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.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 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; | |||
588 | struct pmu { | 588 | struct 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 | ||
919 | extern int perf_pmu_register(struct pmu *pmu); | 922 | extern int perf_pmu_register(struct pmu *pmu, char *name, int type); |
920 | extern void perf_pmu_unregister(struct pmu *pmu); | 923 | extern void perf_pmu_unregister(struct pmu *pmu); |
921 | 924 | ||
922 | extern int perf_num_counters(void); | 925 | extern 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 | ||
4962 | static inline void perf_tp_register(void) | 4963 | static 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 | ||
4967 | static int perf_event_set_filter(struct perf_event *event, void __user *arg) | 4968 | 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) | |||
5305 | out: | 5306 | out: |
5306 | mutex_unlock(&pmus_lock); | 5307 | mutex_unlock(&pmus_lock); |
5307 | } | 5308 | } |
5309 | static struct idr pmu_idr; | ||
5308 | 5310 | ||
5309 | int perf_pmu_register(struct pmu *pmu) | 5311 | int 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 | |||
5339 | skip_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 | ||
5390 | free_idr: | ||
5391 | if (pmu->type >= PERF_TYPE_MAX) | ||
5392 | idr_remove(&pmu_idr, pmu->type); | ||
5393 | |||
5369 | free_pdc: | 5394 | free_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); |