aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/perf_event.c
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2010-05-19 08:02:22 -0400
committerIngo Molnar <mingo@elte.hu>2010-05-21 05:37:56 -0400
commit1c024eca51fdc965290acf342ae16a476c2189d0 (patch)
tree28dc160cc70a20eeb8b8825d6d52ea88a6188413 /kernel/perf_event.c
parentb7e2ecef92d2e7785e6d76b41e5ba8bcbc45259d (diff)
perf, trace: Optimize tracepoints by using per-tracepoint-per-cpu hlist to track events
Avoid the swevent hash-table by using per-tracepoint hlists. Also, avoid conditionals on the fast path by ordering with probe unregister so that we should never get on the callback path without the data being there. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Mike Galbraith <efault@gmx.de> Cc: Steven Rostedt <rostedt@goodmis.org> LKML-Reference: <20100521090710.473188012@chello.nl> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/perf_event.c')
-rw-r--r--kernel/perf_event.c94
1 files changed, 48 insertions, 46 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 45b7aec55458..3f2cc313ee25 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -4005,9 +4005,6 @@ static void perf_swevent_add(struct perf_event *event, u64 nr,
4005 perf_swevent_overflow(event, 0, nmi, data, regs); 4005 perf_swevent_overflow(event, 0, nmi, data, regs);
4006} 4006}
4007 4007
4008static int perf_tp_event_match(struct perf_event *event,
4009 struct perf_sample_data *data);
4010
4011static int perf_exclude_event(struct perf_event *event, 4008static int perf_exclude_event(struct perf_event *event,
4012 struct pt_regs *regs) 4009 struct pt_regs *regs)
4013{ 4010{
@@ -4037,10 +4034,6 @@ static int perf_swevent_match(struct perf_event *event,
4037 if (perf_exclude_event(event, regs)) 4034 if (perf_exclude_event(event, regs))
4038 return 0; 4035 return 0;
4039 4036
4040 if (event->attr.type == PERF_TYPE_TRACEPOINT &&
4041 !perf_tp_event_match(event, data))
4042 return 0;
4043
4044 return 1; 4037 return 1;
4045} 4038}
4046 4039
@@ -4122,7 +4115,7 @@ end:
4122 4115
4123int perf_swevent_get_recursion_context(void) 4116int perf_swevent_get_recursion_context(void)
4124{ 4117{
4125 struct perf_cpu_context *cpuctx = &get_cpu_var(perf_cpu_context); 4118 struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
4126 int rctx; 4119 int rctx;
4127 4120
4128 if (in_nmi()) 4121 if (in_nmi())
@@ -4134,10 +4127,8 @@ int perf_swevent_get_recursion_context(void)
4134 else 4127 else
4135 rctx = 0; 4128 rctx = 0;
4136 4129
4137 if (cpuctx->recursion[rctx]) { 4130 if (cpuctx->recursion[rctx])
4138 put_cpu_var(perf_cpu_context);
4139 return -1; 4131 return -1;
4140 }
4141 4132
4142 cpuctx->recursion[rctx]++; 4133 cpuctx->recursion[rctx]++;
4143 barrier(); 4134 barrier();
@@ -4151,7 +4142,6 @@ void perf_swevent_put_recursion_context(int rctx)
4151 struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context); 4142 struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
4152 barrier(); 4143 barrier();
4153 cpuctx->recursion[rctx]--; 4144 cpuctx->recursion[rctx]--;
4154 put_cpu_var(perf_cpu_context);
4155} 4145}
4156EXPORT_SYMBOL_GPL(perf_swevent_put_recursion_context); 4146EXPORT_SYMBOL_GPL(perf_swevent_put_recursion_context);
4157 4147
@@ -4162,6 +4152,7 @@ void __perf_sw_event(u32 event_id, u64 nr, int nmi,
4162 struct perf_sample_data data; 4152 struct perf_sample_data data;
4163 int rctx; 4153 int rctx;
4164 4154
4155 preempt_disable_notrace();
4165 rctx = perf_swevent_get_recursion_context(); 4156 rctx = perf_swevent_get_recursion_context();
4166 if (rctx < 0) 4157 if (rctx < 0)
4167 return; 4158 return;
@@ -4171,6 +4162,7 @@ void __perf_sw_event(u32 event_id, u64 nr, int nmi,
4171 do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, nmi, &data, regs); 4162 do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, nmi, &data, regs);
4172 4163
4173 perf_swevent_put_recursion_context(rctx); 4164 perf_swevent_put_recursion_context(rctx);
4165 preempt_enable_notrace();
4174} 4166}
4175 4167
4176static void perf_swevent_read(struct perf_event *event) 4168static void perf_swevent_read(struct perf_event *event)
@@ -4486,11 +4478,43 @@ static int swevent_hlist_get(struct perf_event *event)
4486 4478
4487#ifdef CONFIG_EVENT_TRACING 4479#ifdef CONFIG_EVENT_TRACING
4488 4480
4489void perf_tp_event(int event_id, u64 addr, u64 count, void *record, 4481static const struct pmu perf_ops_tracepoint = {
4490 int entry_size, struct pt_regs *regs, void *event) 4482 .enable = perf_trace_enable,
4483 .disable = perf_trace_disable,
4484 .read = perf_swevent_read,
4485 .unthrottle = perf_swevent_unthrottle,
4486};
4487
4488static int perf_tp_filter_match(struct perf_event *event,
4489 struct perf_sample_data *data)
4490{
4491 void *record = data->raw->data;
4492
4493 if (likely(!event->filter) || filter_match_preds(event->filter, record))
4494 return 1;
4495 return 0;
4496}
4497
4498static int perf_tp_event_match(struct perf_event *event,
4499 struct perf_sample_data *data,
4500 struct pt_regs *regs)
4501{
4502 if (perf_exclude_event(event, regs))
4503 return 0;
4504
4505 if (!perf_tp_filter_match(event, data))
4506 return 0;
4507
4508 return 1;
4509}
4510
4511void perf_tp_event(u64 addr, u64 count, void *record, int entry_size,
4512 struct pt_regs *regs, struct hlist_head *head)
4491{ 4513{
4492 const int type = PERF_TYPE_TRACEPOINT;
4493 struct perf_sample_data data; 4514 struct perf_sample_data data;
4515 struct perf_event *event;
4516 struct hlist_node *node;
4517
4494 struct perf_raw_record raw = { 4518 struct perf_raw_record raw = {
4495 .size = entry_size, 4519 .size = entry_size,
4496 .data = record, 4520 .data = record,
@@ -4499,30 +4523,18 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
4499 perf_sample_data_init(&data, addr); 4523 perf_sample_data_init(&data, addr);
4500 data.raw = &raw; 4524 data.raw = &raw;
4501 4525
4502 if (!event) { 4526 rcu_read_lock();
4503 do_perf_sw_event(type, event_id, count, 1, &data, regs); 4527 hlist_for_each_entry_rcu(event, node, head, hlist_entry) {
4504 return; 4528 if (perf_tp_event_match(event, &data, regs))
4529 perf_swevent_add(event, count, 1, &data, regs);
4505 } 4530 }
4506 4531 rcu_read_unlock();
4507 if (perf_swevent_match(event, type, event_id, &data, regs))
4508 perf_swevent_add(event, count, 1, &data, regs);
4509} 4532}
4510EXPORT_SYMBOL_GPL(perf_tp_event); 4533EXPORT_SYMBOL_GPL(perf_tp_event);
4511 4534
4512static int perf_tp_event_match(struct perf_event *event,
4513 struct perf_sample_data *data)
4514{
4515 void *record = data->raw->data;
4516
4517 if (likely(!event->filter) || filter_match_preds(event->filter, record))
4518 return 1;
4519 return 0;
4520}
4521
4522static void tp_perf_event_destroy(struct perf_event *event) 4535static void tp_perf_event_destroy(struct perf_event *event)
4523{ 4536{
4524 perf_trace_disable(event->attr.config); 4537 perf_trace_destroy(event);
4525 swevent_hlist_put(event);
4526} 4538}
4527 4539
4528static const struct pmu *tp_perf_event_init(struct perf_event *event) 4540static const struct pmu *tp_perf_event_init(struct perf_event *event)
@@ -4538,17 +4550,13 @@ static const struct pmu *tp_perf_event_init(struct perf_event *event)
4538 !capable(CAP_SYS_ADMIN)) 4550 !capable(CAP_SYS_ADMIN))
4539 return ERR_PTR(-EPERM); 4551 return ERR_PTR(-EPERM);
4540 4552
4541 if (perf_trace_enable(event->attr.config, event)) 4553 err = perf_trace_init(event);
4554 if (err)
4542 return NULL; 4555 return NULL;
4543 4556
4544 event->destroy = tp_perf_event_destroy; 4557 event->destroy = tp_perf_event_destroy;
4545 err = swevent_hlist_get(event);
4546 if (err) {
4547 perf_trace_disable(event->attr.config);
4548 return ERR_PTR(err);
4549 }
4550 4558
4551 return &perf_ops_generic; 4559 return &perf_ops_tracepoint;
4552} 4560}
4553 4561
4554static int perf_event_set_filter(struct perf_event *event, void __user *arg) 4562static int perf_event_set_filter(struct perf_event *event, void __user *arg)
@@ -4576,12 +4584,6 @@ static void perf_event_free_filter(struct perf_event *event)
4576 4584
4577#else 4585#else
4578 4586
4579static int perf_tp_event_match(struct perf_event *event,
4580 struct perf_sample_data *data)
4581{
4582 return 1;
4583}
4584
4585static const struct pmu *tp_perf_event_init(struct perf_event *event) 4587static const struct pmu *tp_perf_event_init(struct perf_event *event)
4586{ 4588{
4587 return NULL; 4589 return NULL;