aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Olsa <jolsa@redhat.com>2013-05-06 12:27:18 -0400
committerIngo Molnar <mingo@kernel.org>2013-05-07 07:17:29 -0400
commit52d857a8784a09576215c71cebf368d61c12a754 (patch)
tree5bb32d39139ae0a6fb4ebe38f4d20f79317d18e4
parent524eff183f51d080a83b348d0ea97c08b3607b9a (diff)
perf: Factor out auxiliary events notification
Add perf_event_aux() function to send out all types of auxiliary events - mmap, task, comm events. For each type there's match and output functions defined and used as callbacks during perf_event_aux processing. This way we can centralize the pmu/context iterating and event matching logic. Also since lot of the code was duplicated, this patch reduces the .text size about 2kB on my setup: snipped output from 'objdump -x kernel/events/core.o' before: Idx Name Size 0 .text 0000d313 after: Idx Name Size 0 .text 0000cad3 Signed-off-by: Jiri Olsa <jolsa@redhat.com> Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Stephane Eranian <eranian@google.com> Cc: Borislav Petkov <bp@alien8.de> Link: http://lkml.kernel.org/r/1367857638-27631-3-git-send-email-jolsa@redhat.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--kernel/events/core.c242
1 files changed, 89 insertions, 153 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 38b68a05c3c6..9dc297faf7c0 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4394,6 +4394,64 @@ perf_event_read_event(struct perf_event *event,
4394 perf_output_end(&handle); 4394 perf_output_end(&handle);
4395} 4395}
4396 4396
4397typedef int (perf_event_aux_match_cb)(struct perf_event *event, void *data);
4398typedef void (perf_event_aux_output_cb)(struct perf_event *event, void *data);
4399
4400static void
4401perf_event_aux_ctx(struct perf_event_context *ctx,
4402 perf_event_aux_match_cb match,
4403 perf_event_aux_output_cb output,
4404 void *data)
4405{
4406 struct perf_event *event;
4407
4408 list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
4409 if (event->state < PERF_EVENT_STATE_INACTIVE)
4410 continue;
4411 if (!event_filter_match(event))
4412 continue;
4413 if (match(event, data))
4414 output(event, data);
4415 }
4416}
4417
4418static void
4419perf_event_aux(perf_event_aux_match_cb match,
4420 perf_event_aux_output_cb output,
4421 void *data,
4422 struct perf_event_context *task_ctx)
4423{
4424 struct perf_cpu_context *cpuctx;
4425 struct perf_event_context *ctx;
4426 struct pmu *pmu;
4427 int ctxn;
4428
4429 rcu_read_lock();
4430 list_for_each_entry_rcu(pmu, &pmus, entry) {
4431 cpuctx = get_cpu_ptr(pmu->pmu_cpu_context);
4432 if (cpuctx->unique_pmu != pmu)
4433 goto next;
4434 perf_event_aux_ctx(&cpuctx->ctx, match, output, data);
4435 if (task_ctx)
4436 goto next;
4437 ctxn = pmu->task_ctx_nr;
4438 if (ctxn < 0)
4439 goto next;
4440 ctx = rcu_dereference(current->perf_event_ctxp[ctxn]);
4441 if (ctx)
4442 perf_event_aux_ctx(ctx, match, output, data);
4443next:
4444 put_cpu_ptr(pmu->pmu_cpu_context);
4445 }
4446
4447 if (task_ctx) {
4448 preempt_disable();
4449 perf_event_aux_ctx(task_ctx, match, output, data);
4450 preempt_enable();
4451 }
4452 rcu_read_unlock();
4453}
4454
4397/* 4455/*
4398 * task tracking -- fork/exit 4456 * task tracking -- fork/exit
4399 * 4457 *
@@ -4416,8 +4474,9 @@ struct perf_task_event {
4416}; 4474};
4417 4475
4418static void perf_event_task_output(struct perf_event *event, 4476static void perf_event_task_output(struct perf_event *event,
4419 struct perf_task_event *task_event) 4477 void *data)
4420{ 4478{
4479 struct perf_task_event *task_event = data;
4421 struct perf_output_handle handle; 4480 struct perf_output_handle handle;
4422 struct perf_sample_data sample; 4481 struct perf_sample_data sample;
4423 struct task_struct *task = task_event->task; 4482 struct task_struct *task = task_event->task;
@@ -4445,64 +4504,11 @@ out:
4445 task_event->event_id.header.size = size; 4504 task_event->event_id.header.size = size;
4446} 4505}
4447 4506
4448static int perf_event_task_match(struct perf_event *event) 4507static int perf_event_task_match(struct perf_event *event,
4449{ 4508 void *data __maybe_unused)
4450 if (event->state < PERF_EVENT_STATE_INACTIVE)
4451 return 0;
4452
4453 if (!event_filter_match(event))
4454 return 0;
4455
4456 if (event->attr.comm || event->attr.mmap ||
4457 event->attr.mmap_data || event->attr.task)
4458 return 1;
4459
4460 return 0;
4461}
4462
4463static void perf_event_task_ctx(struct perf_event_context *ctx,
4464 struct perf_task_event *task_event)
4465{
4466 struct perf_event *event;
4467
4468 list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
4469 if (perf_event_task_match(event))
4470 perf_event_task_output(event, task_event);
4471 }
4472}
4473
4474static void perf_event_task_event(struct perf_task_event *task_event)
4475{ 4509{
4476 struct perf_cpu_context *cpuctx; 4510 return event->attr.comm || event->attr.mmap ||
4477 struct perf_event_context *ctx, *task_ctx = task_event->task_ctx; 4511 event->attr.mmap_data || event->attr.task;
4478 struct pmu *pmu;
4479 int ctxn;
4480
4481 rcu_read_lock();
4482 list_for_each_entry_rcu(pmu, &pmus, entry) {
4483 cpuctx = get_cpu_ptr(pmu->pmu_cpu_context);
4484 if (cpuctx->unique_pmu != pmu)
4485 goto next;
4486 perf_event_task_ctx(&cpuctx->ctx, task_event);
4487
4488 if (task_ctx)
4489 goto next;
4490 ctxn = pmu->task_ctx_nr;
4491 if (ctxn < 0)
4492 goto next;
4493 ctx = rcu_dereference(current->perf_event_ctxp[ctxn]);
4494 if (ctx)
4495 perf_event_task_ctx(ctx, task_event);
4496next:
4497 put_cpu_ptr(pmu->pmu_cpu_context);
4498 }
4499 if (task_ctx) {
4500 preempt_disable();
4501 perf_event_task_ctx(task_ctx, task_event);
4502 preempt_enable();
4503 }
4504
4505 rcu_read_unlock();
4506} 4512}
4507 4513
4508static void perf_event_task(struct task_struct *task, 4514static void perf_event_task(struct task_struct *task,
@@ -4533,7 +4539,10 @@ static void perf_event_task(struct task_struct *task,
4533 }, 4539 },
4534 }; 4540 };
4535 4541
4536 perf_event_task_event(&task_event); 4542 perf_event_aux(perf_event_task_match,
4543 perf_event_task_output,
4544 &task_event,
4545 task_ctx);
4537} 4546}
4538 4547
4539void perf_event_fork(struct task_struct *task) 4548void perf_event_fork(struct task_struct *task)
@@ -4559,8 +4568,9 @@ struct perf_comm_event {
4559}; 4568};
4560 4569
4561static void perf_event_comm_output(struct perf_event *event, 4570static void perf_event_comm_output(struct perf_event *event,
4562 struct perf_comm_event *comm_event) 4571 void *data)
4563{ 4572{
4573 struct perf_comm_event *comm_event = data;
4564 struct perf_output_handle handle; 4574 struct perf_output_handle handle;
4565 struct perf_sample_data sample; 4575 struct perf_sample_data sample;
4566 int size = comm_event->event_id.header.size; 4576 int size = comm_event->event_id.header.size;
@@ -4587,39 +4597,16 @@ out:
4587 comm_event->event_id.header.size = size; 4597 comm_event->event_id.header.size = size;
4588} 4598}
4589 4599
4590static int perf_event_comm_match(struct perf_event *event) 4600static int perf_event_comm_match(struct perf_event *event,
4591{ 4601 void *data __maybe_unused)
4592 if (event->state < PERF_EVENT_STATE_INACTIVE)
4593 return 0;
4594
4595 if (!event_filter_match(event))
4596 return 0;
4597
4598 if (event->attr.comm)
4599 return 1;
4600
4601 return 0;
4602}
4603
4604static void perf_event_comm_ctx(struct perf_event_context *ctx,
4605 struct perf_comm_event *comm_event)
4606{ 4602{
4607 struct perf_event *event; 4603 return event->attr.comm;
4608
4609 list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
4610 if (perf_event_comm_match(event))
4611 perf_event_comm_output(event, comm_event);
4612 }
4613} 4604}
4614 4605
4615static void perf_event_comm_event(struct perf_comm_event *comm_event) 4606static void perf_event_comm_event(struct perf_comm_event *comm_event)
4616{ 4607{
4617 struct perf_cpu_context *cpuctx;
4618 struct perf_event_context *ctx;
4619 char comm[TASK_COMM_LEN]; 4608 char comm[TASK_COMM_LEN];
4620 unsigned int size; 4609 unsigned int size;
4621 struct pmu *pmu;
4622 int ctxn;
4623 4610
4624 memset(comm, 0, sizeof(comm)); 4611 memset(comm, 0, sizeof(comm));
4625 strlcpy(comm, comm_event->task->comm, sizeof(comm)); 4612 strlcpy(comm, comm_event->task->comm, sizeof(comm));
@@ -4629,24 +4616,11 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event)
4629 comm_event->comm_size = size; 4616 comm_event->comm_size = size;
4630 4617
4631 comm_event->event_id.header.size = sizeof(comm_event->event_id) + size; 4618 comm_event->event_id.header.size = sizeof(comm_event->event_id) + size;
4632 rcu_read_lock();
4633 list_for_each_entry_rcu(pmu, &pmus, entry) {
4634 cpuctx = get_cpu_ptr(pmu->pmu_cpu_context);
4635 if (cpuctx->unique_pmu != pmu)
4636 goto next;
4637 perf_event_comm_ctx(&cpuctx->ctx, comm_event);
4638 4619
4639 ctxn = pmu->task_ctx_nr; 4620 perf_event_aux(perf_event_comm_match,
4640 if (ctxn < 0) 4621 perf_event_comm_output,
4641 goto next; 4622 comm_event,
4642 4623 NULL);
4643 ctx = rcu_dereference(current->perf_event_ctxp[ctxn]);
4644 if (ctx)
4645 perf_event_comm_ctx(ctx, comm_event);
4646next:
4647 put_cpu_ptr(pmu->pmu_cpu_context);
4648 }
4649 rcu_read_unlock();
4650} 4624}
4651 4625
4652void perf_event_comm(struct task_struct *task) 4626void perf_event_comm(struct task_struct *task)
@@ -4708,8 +4682,9 @@ struct perf_mmap_event {
4708}; 4682};
4709 4683
4710static void perf_event_mmap_output(struct perf_event *event, 4684static void perf_event_mmap_output(struct perf_event *event,
4711 struct perf_mmap_event *mmap_event) 4685 void *data)
4712{ 4686{
4687 struct perf_mmap_event *mmap_event = data;
4713 struct perf_output_handle handle; 4688 struct perf_output_handle handle;
4714 struct perf_sample_data sample; 4689 struct perf_sample_data sample;
4715 int size = mmap_event->event_id.header.size; 4690 int size = mmap_event->event_id.header.size;
@@ -4736,46 +4711,24 @@ out:
4736} 4711}
4737 4712
4738static int perf_event_mmap_match(struct perf_event *event, 4713static int perf_event_mmap_match(struct perf_event *event,
4739 struct perf_mmap_event *mmap_event, 4714 void *data)
4740 int executable)
4741{ 4715{
4742 if (event->state < PERF_EVENT_STATE_INACTIVE) 4716 struct perf_mmap_event *mmap_event = data;
4743 return 0; 4717 struct vm_area_struct *vma = mmap_event->vma;
4744 4718 int executable = vma->vm_flags & VM_EXEC;
4745 if (!event_filter_match(event))
4746 return 0;
4747
4748 if ((!executable && event->attr.mmap_data) ||
4749 (executable && event->attr.mmap))
4750 return 1;
4751
4752 return 0;
4753}
4754
4755static void perf_event_mmap_ctx(struct perf_event_context *ctx,
4756 struct perf_mmap_event *mmap_event,
4757 int executable)
4758{
4759 struct perf_event *event;
4760 4719
4761 list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { 4720 return (!executable && event->attr.mmap_data) ||
4762 if (perf_event_mmap_match(event, mmap_event, executable)) 4721 (executable && event->attr.mmap);
4763 perf_event_mmap_output(event, mmap_event);
4764 }
4765} 4722}
4766 4723
4767static void perf_event_mmap_event(struct perf_mmap_event *mmap_event) 4724static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
4768{ 4725{
4769 struct perf_cpu_context *cpuctx;
4770 struct perf_event_context *ctx;
4771 struct vm_area_struct *vma = mmap_event->vma; 4726 struct vm_area_struct *vma = mmap_event->vma;
4772 struct file *file = vma->vm_file; 4727 struct file *file = vma->vm_file;
4773 unsigned int size; 4728 unsigned int size;
4774 char tmp[16]; 4729 char tmp[16];
4775 char *buf = NULL; 4730 char *buf = NULL;
4776 const char *name; 4731 const char *name;
4777 struct pmu *pmu;
4778 int ctxn;
4779 4732
4780 memset(tmp, 0, sizeof(tmp)); 4733 memset(tmp, 0, sizeof(tmp));
4781 4734
@@ -4831,27 +4784,10 @@ got_name:
4831 4784
4832 mmap_event->event_id.header.size = sizeof(mmap_event->event_id) + size; 4785 mmap_event->event_id.header.size = sizeof(mmap_event->event_id) + size;
4833 4786
4834 rcu_read_lock(); 4787 perf_event_aux(perf_event_mmap_match,
4835 list_for_each_entry_rcu(pmu, &pmus, entry) { 4788 perf_event_mmap_output,
4836 cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); 4789 mmap_event,
4837 if (cpuctx->unique_pmu != pmu) 4790 NULL);
4838 goto next;
4839 perf_event_mmap_ctx(&cpuctx->ctx, mmap_event,
4840 vma->vm_flags & VM_EXEC);
4841
4842 ctxn = pmu->task_ctx_nr;
4843 if (ctxn < 0)
4844 goto next;
4845
4846 ctx = rcu_dereference(current->perf_event_ctxp[ctxn]);
4847 if (ctx) {
4848 perf_event_mmap_ctx(ctx, mmap_event,
4849 vma->vm_flags & VM_EXEC);
4850 }
4851next:
4852 put_cpu_ptr(pmu->pmu_cpu_context);
4853 }
4854 rcu_read_unlock();
4855 4791
4856 kfree(buf); 4792 kfree(buf);
4857} 4793}