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 /kernel/perf_event.c | |
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>
Diffstat (limited to 'kernel/perf_event.c')
-rw-r--r-- | kernel/perf_event.c | 48 |
1 files changed, 42 insertions, 6 deletions
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); |