aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/perf_event.c
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2010-09-06 08:48:15 -0400
committerIngo Molnar <mingo@elte.hu>2010-09-09 14:46:32 -0400
commitb28ab83c595e767f2028276b7398d17f2253cec0 (patch)
treeae52b2d4c10d1317ec7a5906bea56847e95b5f43 /kernel/perf_event.c
parentc3f00c70276d8ae82578c8b773e2db657f69a478 (diff)
perf: Remove the swevent hash-table from the cpu context
Separate the swevent hash-table from the cpu_context bits in preparation for per pmu cpu contexts. This keeps the swevent hash a global entity. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: paulus <paulus@samba.org> Cc: stephane eranian <eranian@googlemail.com> Cc: Robert Richter <robert.richter@amd.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Lin Ming <ming.m.lin@intel.com> Cc: Yanmin <yanmin_zhang@linux.intel.com> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/perf_event.c')
-rw-r--r--kernel/perf_event.c104
1 files changed, 58 insertions, 46 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index a3c86a8335c..2c47ed6c4f2 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -4154,6 +4154,17 @@ int perf_event_overflow(struct perf_event *event, int nmi,
4154 * Generic software event infrastructure 4154 * Generic software event infrastructure
4155 */ 4155 */
4156 4156
4157struct swevent_htable {
4158 struct swevent_hlist *swevent_hlist;
4159 struct mutex hlist_mutex;
4160 int hlist_refcount;
4161
4162 /* Recursion avoidance in each contexts */
4163 int recursion[PERF_NR_CONTEXTS];
4164};
4165
4166static DEFINE_PER_CPU(struct swevent_htable, swevent_htable);
4167
4157/* 4168/*
4158 * We directly increment event->count and keep a second value in 4169 * We directly increment event->count and keep a second value in
4159 * event->hw.period_left to count intervals. This period event 4170 * event->hw.period_left to count intervals. This period event
@@ -4286,11 +4297,11 @@ __find_swevent_head(struct swevent_hlist *hlist, u64 type, u32 event_id)
4286 4297
4287/* For the read side: events when they trigger */ 4298/* For the read side: events when they trigger */
4288static inline struct hlist_head * 4299static inline struct hlist_head *
4289find_swevent_head_rcu(struct perf_cpu_context *ctx, u64 type, u32 event_id) 4300find_swevent_head_rcu(struct swevent_htable *swhash, u64 type, u32 event_id)
4290{ 4301{
4291 struct swevent_hlist *hlist; 4302 struct swevent_hlist *hlist;
4292 4303
4293 hlist = rcu_dereference(ctx->swevent_hlist); 4304 hlist = rcu_dereference(swhash->swevent_hlist);
4294 if (!hlist) 4305 if (!hlist)
4295 return NULL; 4306 return NULL;
4296 4307
@@ -4299,7 +4310,7 @@ find_swevent_head_rcu(struct perf_cpu_context *ctx, u64 type, u32 event_id)
4299 4310
4300/* For the event head insertion and removal in the hlist */ 4311/* For the event head insertion and removal in the hlist */
4301static inline struct hlist_head * 4312static inline struct hlist_head *
4302find_swevent_head(struct perf_cpu_context *ctx, struct perf_event *event) 4313find_swevent_head(struct swevent_htable *swhash, struct perf_event *event)
4303{ 4314{
4304 struct swevent_hlist *hlist; 4315 struct swevent_hlist *hlist;
4305 u32 event_id = event->attr.config; 4316 u32 event_id = event->attr.config;
@@ -4310,7 +4321,7 @@ find_swevent_head(struct perf_cpu_context *ctx, struct perf_event *event)
4310 * and release. Which makes the protected version suitable here. 4321 * and release. Which makes the protected version suitable here.
4311 * The context lock guarantees that. 4322 * The context lock guarantees that.
4312 */ 4323 */
4313 hlist = rcu_dereference_protected(ctx->swevent_hlist, 4324 hlist = rcu_dereference_protected(swhash->swevent_hlist,
4314 lockdep_is_held(&event->ctx->lock)); 4325 lockdep_is_held(&event->ctx->lock));
4315 if (!hlist) 4326 if (!hlist)
4316 return NULL; 4327 return NULL;
@@ -4323,17 +4334,13 @@ static void do_perf_sw_event(enum perf_type_id type, u32 event_id,
4323 struct perf_sample_data *data, 4334 struct perf_sample_data *data,
4324 struct pt_regs *regs) 4335 struct pt_regs *regs)
4325{ 4336{
4326 struct perf_cpu_context *cpuctx; 4337 struct swevent_htable *swhash = &__get_cpu_var(swevent_htable);
4327 struct perf_event *event; 4338 struct perf_event *event;
4328 struct hlist_node *node; 4339 struct hlist_node *node;
4329 struct hlist_head *head; 4340 struct hlist_head *head;
4330 4341
4331 cpuctx = &__get_cpu_var(perf_cpu_context);
4332
4333 rcu_read_lock(); 4342 rcu_read_lock();
4334 4343 head = find_swevent_head_rcu(swhash, type, event_id);
4335 head = find_swevent_head_rcu(cpuctx, type, event_id);
4336
4337 if (!head) 4344 if (!head)
4338 goto end; 4345 goto end;
4339 4346
@@ -4347,17 +4354,17 @@ end:
4347 4354
4348int perf_swevent_get_recursion_context(void) 4355int perf_swevent_get_recursion_context(void)
4349{ 4356{
4350 struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); 4357 struct swevent_htable *swhash = &__get_cpu_var(swevent_htable);
4351 4358
4352 return get_recursion_context(cpuctx->recursion); 4359 return get_recursion_context(swhash->recursion);
4353} 4360}
4354EXPORT_SYMBOL_GPL(perf_swevent_get_recursion_context); 4361EXPORT_SYMBOL_GPL(perf_swevent_get_recursion_context);
4355 4362
4356void inline perf_swevent_put_recursion_context(int rctx) 4363void inline perf_swevent_put_recursion_context(int rctx)
4357{ 4364{
4358 struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); 4365 struct swevent_htable *swhash = &__get_cpu_var(swevent_htable);
4359 4366
4360 put_recursion_context(cpuctx->recursion, rctx); 4367 put_recursion_context(swhash->recursion, rctx);
4361} 4368}
4362 4369
4363void __perf_sw_event(u32 event_id, u64 nr, int nmi, 4370void __perf_sw_event(u32 event_id, u64 nr, int nmi,
@@ -4385,12 +4392,10 @@ static void perf_swevent_read(struct perf_event *event)
4385 4392
4386static int perf_swevent_add(struct perf_event *event, int flags) 4393static int perf_swevent_add(struct perf_event *event, int flags)
4387{ 4394{
4395 struct swevent_htable *swhash = &__get_cpu_var(swevent_htable);
4388 struct hw_perf_event *hwc = &event->hw; 4396 struct hw_perf_event *hwc = &event->hw;
4389 struct perf_cpu_context *cpuctx;
4390 struct hlist_head *head; 4397 struct hlist_head *head;
4391 4398
4392 cpuctx = &__get_cpu_var(perf_cpu_context);
4393
4394 if (hwc->sample_period) { 4399 if (hwc->sample_period) {
4395 hwc->last_period = hwc->sample_period; 4400 hwc->last_period = hwc->sample_period;
4396 perf_swevent_set_period(event); 4401 perf_swevent_set_period(event);
@@ -4398,7 +4403,7 @@ static int perf_swevent_add(struct perf_event *event, int flags)
4398 4403
4399 hwc->state = !(flags & PERF_EF_START); 4404 hwc->state = !(flags & PERF_EF_START);
4400 4405
4401 head = find_swevent_head(cpuctx, event); 4406 head = find_swevent_head(swhash, event);
4402 if (WARN_ON_ONCE(!head)) 4407 if (WARN_ON_ONCE(!head))
4403 return -EINVAL; 4408 return -EINVAL;
4404 4409
@@ -4424,10 +4429,10 @@ static void perf_swevent_stop(struct perf_event *event, int flags)
4424 4429
4425/* Deref the hlist from the update side */ 4430/* Deref the hlist from the update side */
4426static inline struct swevent_hlist * 4431static inline struct swevent_hlist *
4427swevent_hlist_deref(struct perf_cpu_context *cpuctx) 4432swevent_hlist_deref(struct swevent_htable *swhash)
4428{ 4433{
4429 return rcu_dereference_protected(cpuctx->swevent_hlist, 4434 return rcu_dereference_protected(swhash->swevent_hlist,
4430 lockdep_is_held(&cpuctx->hlist_mutex)); 4435 lockdep_is_held(&swhash->hlist_mutex));
4431} 4436}
4432 4437
4433static void swevent_hlist_release_rcu(struct rcu_head *rcu_head) 4438static void swevent_hlist_release_rcu(struct rcu_head *rcu_head)
@@ -4438,27 +4443,27 @@ static void swevent_hlist_release_rcu(struct rcu_head *rcu_head)
4438 kfree(hlist); 4443 kfree(hlist);
4439} 4444}
4440 4445
4441static void swevent_hlist_release(struct perf_cpu_context *cpuctx) 4446static void swevent_hlist_release(struct swevent_htable *swhash)
4442{ 4447{
4443 struct swevent_hlist *hlist = swevent_hlist_deref(cpuctx); 4448 struct swevent_hlist *hlist = swevent_hlist_deref(swhash);
4444 4449
4445 if (!hlist) 4450 if (!hlist)
4446 return; 4451 return;
4447 4452
4448 rcu_assign_pointer(cpuctx->swevent_hlist, NULL); 4453 rcu_assign_pointer(swhash->swevent_hlist, NULL);
4449 call_rcu(&hlist->rcu_head, swevent_hlist_release_rcu); 4454 call_rcu(&hlist->rcu_head, swevent_hlist_release_rcu);
4450} 4455}
4451 4456
4452static void swevent_hlist_put_cpu(struct perf_event *event, int cpu) 4457static void swevent_hlist_put_cpu(struct perf_event *event, int cpu)
4453{ 4458{
4454 struct perf_cpu_context *cpuctx = &per_cpu(perf_cpu_context, cpu); 4459 struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
4455 4460
4456 mutex_lock(&cpuctx->hlist_mutex); 4461 mutex_lock(&swhash->hlist_mutex);
4457 4462
4458 if (!--cpuctx->hlist_refcount) 4463 if (!--swhash->hlist_refcount)
4459 swevent_hlist_release(cpuctx); 4464 swevent_hlist_release(swhash);
4460 4465
4461 mutex_unlock(&cpuctx->hlist_mutex); 4466 mutex_unlock(&swhash->hlist_mutex);
4462} 4467}
4463 4468
4464static void swevent_hlist_put(struct perf_event *event) 4469static void swevent_hlist_put(struct perf_event *event)
@@ -4476,12 +4481,12 @@ static void swevent_hlist_put(struct perf_event *event)
4476 4481
4477static int swevent_hlist_get_cpu(struct perf_event *event, int cpu) 4482static int swevent_hlist_get_cpu(struct perf_event *event, int cpu)
4478{ 4483{
4479 struct perf_cpu_context *cpuctx = &per_cpu(perf_cpu_context, cpu); 4484 struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
4480 int err = 0; 4485 int err = 0;
4481 4486
4482 mutex_lock(&cpuctx->hlist_mutex); 4487 mutex_lock(&swhash->hlist_mutex);
4483 4488
4484 if (!swevent_hlist_deref(cpuctx) && cpu_online(cpu)) { 4489 if (!swevent_hlist_deref(swhash) && cpu_online(cpu)) {
4485 struct swevent_hlist *hlist; 4490 struct swevent_hlist *hlist;
4486 4491
4487 hlist = kzalloc(sizeof(*hlist), GFP_KERNEL); 4492 hlist = kzalloc(sizeof(*hlist), GFP_KERNEL);
@@ -4489,11 +4494,11 @@ static int swevent_hlist_get_cpu(struct perf_event *event, int cpu)
4489 err = -ENOMEM; 4494 err = -ENOMEM;
4490 goto exit; 4495 goto exit;
4491 } 4496 }
4492 rcu_assign_pointer(cpuctx->swevent_hlist, hlist); 4497 rcu_assign_pointer(swhash->swevent_hlist, hlist);
4493 } 4498 }
4494 cpuctx->hlist_refcount++; 4499 swhash->hlist_refcount++;
4495exit: 4500exit:
4496 mutex_unlock(&cpuctx->hlist_mutex); 4501 mutex_unlock(&swhash->hlist_mutex);
4497 4502
4498 return err; 4503 return err;
4499} 4504}
@@ -5889,12 +5894,15 @@ int perf_event_init_task(struct task_struct *child)
5889 5894
5890static void __init perf_event_init_all_cpus(void) 5895static void __init perf_event_init_all_cpus(void)
5891{ 5896{
5892 int cpu;
5893 struct perf_cpu_context *cpuctx; 5897 struct perf_cpu_context *cpuctx;
5898 struct swevent_htable *swhash;
5899 int cpu;
5894 5900
5895 for_each_possible_cpu(cpu) { 5901 for_each_possible_cpu(cpu) {
5902 swhash = &per_cpu(swevent_htable, cpu);
5903 mutex_init(&swhash->hlist_mutex);
5904
5896 cpuctx = &per_cpu(perf_cpu_context, cpu); 5905 cpuctx = &per_cpu(perf_cpu_context, cpu);
5897 mutex_init(&cpuctx->hlist_mutex);
5898 __perf_event_init_context(&cpuctx->ctx, NULL); 5906 __perf_event_init_context(&cpuctx->ctx, NULL);
5899 } 5907 }
5900} 5908}
@@ -5902,18 +5910,21 @@ static void __init perf_event_init_all_cpus(void)
5902static void __cpuinit perf_event_init_cpu(int cpu) 5910static void __cpuinit perf_event_init_cpu(int cpu)
5903{ 5911{
5904 struct perf_cpu_context *cpuctx; 5912 struct perf_cpu_context *cpuctx;
5913 struct swevent_htable *swhash;
5905 5914
5906 cpuctx = &per_cpu(perf_cpu_context, cpu); 5915 cpuctx = &per_cpu(perf_cpu_context, cpu);
5907 5916
5908 mutex_lock(&cpuctx->hlist_mutex); 5917 swhash = &per_cpu(swevent_htable, cpu);
5909 if (cpuctx->hlist_refcount > 0) { 5918
5919 mutex_lock(&swhash->hlist_mutex);
5920 if (swhash->hlist_refcount > 0) {
5910 struct swevent_hlist *hlist; 5921 struct swevent_hlist *hlist;
5911 5922
5912 hlist = kzalloc(sizeof(*hlist), GFP_KERNEL); 5923 hlist = kzalloc_node(sizeof(*hlist), GFP_KERNEL, cpu_to_node(cpu));
5913 WARN_ON_ONCE(!hlist); 5924 WARN_ON(!hlist);
5914 rcu_assign_pointer(cpuctx->swevent_hlist, hlist); 5925 rcu_assign_pointer(swhash->swevent_hlist, hlist);
5915 } 5926 }
5916 mutex_unlock(&cpuctx->hlist_mutex); 5927 mutex_unlock(&swhash->hlist_mutex);
5917} 5928}
5918 5929
5919#ifdef CONFIG_HOTPLUG_CPU 5930#ifdef CONFIG_HOTPLUG_CPU
@@ -5931,11 +5942,12 @@ static void __perf_event_exit_cpu(void *info)
5931static void perf_event_exit_cpu(int cpu) 5942static void perf_event_exit_cpu(int cpu)
5932{ 5943{
5933 struct perf_cpu_context *cpuctx = &per_cpu(perf_cpu_context, cpu); 5944 struct perf_cpu_context *cpuctx = &per_cpu(perf_cpu_context, cpu);
5945 struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
5934 struct perf_event_context *ctx = &cpuctx->ctx; 5946 struct perf_event_context *ctx = &cpuctx->ctx;
5935 5947
5936 mutex_lock(&cpuctx->hlist_mutex); 5948 mutex_lock(&swhash->hlist_mutex);
5937 swevent_hlist_release(cpuctx); 5949 swevent_hlist_release(swhash);
5938 mutex_unlock(&cpuctx->hlist_mutex); 5950 mutex_unlock(&swhash->hlist_mutex);
5939 5951
5940 mutex_lock(&ctx->mutex); 5952 mutex_lock(&ctx->mutex);
5941 smp_call_function_single(cpu, __perf_event_exit_cpu, NULL, 1); 5953 smp_call_function_single(cpu, __perf_event_exit_cpu, NULL, 1);