aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/perf_event.c
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 /kernel/perf_event.c
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>
Diffstat (limited to 'kernel/perf_event.c')
-rw-r--r--kernel/perf_event.c48
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
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);