diff options
| author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2010-05-18 12:08:32 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2010-05-18 12:35:46 -0400 |
| commit | 4f41c013f553957765902fb01475972f0af3e8e7 (patch) | |
| tree | ddaa54947cc990094a4b270f2f8b3d6da195044f | |
| parent | ef4f30f54e265c2f6f9ac9eda4db158a4e16050b (diff) | |
perf/ftrace: Optimize perf/tracepoint interaction for single events
When we've got but a single event per tracepoint
there is no reason to try and multiplex it so don't.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Tested-by: Ingo Molnar <mingo@elte.hu>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
| -rw-r--r-- | include/linux/ftrace_event.h | 8 | ||||
| -rw-r--r-- | include/linux/perf_event.h | 2 | ||||
| -rw-r--r-- | include/trace/ftrace.h | 3 | ||||
| -rw-r--r-- | kernel/perf_event.c | 15 | ||||
| -rw-r--r-- | kernel/trace/trace_event_perf.c | 11 | ||||
| -rw-r--r-- | kernel/trace/trace_kprobe.c | 4 | ||||
| -rw-r--r-- | kernel/trace/trace_syscalls.c | 6 |
7 files changed, 31 insertions, 18 deletions
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index c0f4b364c711..c8091001b943 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
| @@ -132,6 +132,7 @@ struct ftrace_event_call { | |||
| 132 | void *data; | 132 | void *data; |
| 133 | 133 | ||
| 134 | int perf_refcount; | 134 | int perf_refcount; |
| 135 | void *perf_data; | ||
| 135 | int (*perf_event_enable)(struct ftrace_event_call *); | 136 | int (*perf_event_enable)(struct ftrace_event_call *); |
| 136 | void (*perf_event_disable)(struct ftrace_event_call *); | 137 | void (*perf_event_disable)(struct ftrace_event_call *); |
| 137 | }; | 138 | }; |
| @@ -190,7 +191,7 @@ struct perf_event; | |||
| 190 | 191 | ||
| 191 | DECLARE_PER_CPU(struct pt_regs, perf_trace_regs); | 192 | DECLARE_PER_CPU(struct pt_regs, perf_trace_regs); |
| 192 | 193 | ||
| 193 | extern int perf_trace_enable(int event_id); | 194 | extern int perf_trace_enable(int event_id, void *data); |
| 194 | extern void perf_trace_disable(int event_id); | 195 | extern void perf_trace_disable(int event_id); |
| 195 | extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, | 196 | extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, |
| 196 | char *filter_str); | 197 | char *filter_str); |
| @@ -201,11 +202,12 @@ perf_trace_buf_prepare(int size, unsigned short type, int *rctxp, | |||
| 201 | 202 | ||
| 202 | static inline void | 203 | static inline void |
| 203 | perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr, | 204 | perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr, |
| 204 | u64 count, unsigned long irq_flags, struct pt_regs *regs) | 205 | u64 count, unsigned long irq_flags, struct pt_regs *regs, |
| 206 | void *event) | ||
| 205 | { | 207 | { |
| 206 | struct trace_entry *entry = raw_data; | 208 | struct trace_entry *entry = raw_data; |
| 207 | 209 | ||
| 208 | perf_tp_event(entry->type, addr, count, raw_data, size, regs); | 210 | perf_tp_event(entry->type, addr, count, raw_data, size, regs, event); |
| 209 | perf_swevent_put_recursion_context(rctx); | 211 | perf_swevent_put_recursion_context(rctx); |
| 210 | local_irq_restore(irq_flags); | 212 | local_irq_restore(irq_flags); |
| 211 | } | 213 | } |
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 3fd5c82e0e18..0b521fc8f5b0 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
| @@ -994,7 +994,7 @@ static inline bool perf_paranoid_kernel(void) | |||
| 994 | 994 | ||
| 995 | extern void perf_event_init(void); | 995 | extern void perf_event_init(void); |
| 996 | extern void perf_tp_event(int event_id, u64 addr, u64 count, void *record, | 996 | extern void perf_tp_event(int event_id, u64 addr, u64 count, void *record, |
| 997 | int entry_size, struct pt_regs *regs); | 997 | int entry_size, struct pt_regs *regs, void *event); |
| 998 | extern void perf_bp_event(struct perf_event *event, void *data); | 998 | extern void perf_bp_event(struct perf_event *event, void *data); |
| 999 | 999 | ||
| 1000 | #ifndef perf_misc_flags | 1000 | #ifndef perf_misc_flags |
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 882c64832ffe..0a29df092922 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h | |||
| @@ -785,7 +785,8 @@ perf_trace_templ_##call(struct ftrace_event_call *event_call, \ | |||
| 785 | { assign; } \ | 785 | { assign; } \ |
| 786 | \ | 786 | \ |
| 787 | perf_trace_buf_submit(entry, __entry_size, rctx, __addr, \ | 787 | perf_trace_buf_submit(entry, __entry_size, rctx, __addr, \ |
| 788 | __count, irq_flags, __regs); \ | 788 | __count, irq_flags, __regs, \ |
| 789 | event_call->perf_data); \ | ||
| 789 | } | 790 | } |
| 790 | 791 | ||
| 791 | #undef DEFINE_EVENT | 792 | #undef DEFINE_EVENT |
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index a4fa381db3c2..17ac47f4bce6 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
| @@ -4468,8 +4468,9 @@ static int swevent_hlist_get(struct perf_event *event) | |||
| 4468 | #ifdef CONFIG_EVENT_TRACING | 4468 | #ifdef CONFIG_EVENT_TRACING |
| 4469 | 4469 | ||
| 4470 | void perf_tp_event(int event_id, u64 addr, u64 count, void *record, | 4470 | void perf_tp_event(int event_id, u64 addr, u64 count, void *record, |
| 4471 | int entry_size, struct pt_regs *regs) | 4471 | int entry_size, struct pt_regs *regs, void *event) |
| 4472 | { | 4472 | { |
| 4473 | const int type = PERF_TYPE_TRACEPOINT; | ||
| 4473 | struct perf_sample_data data; | 4474 | struct perf_sample_data data; |
| 4474 | struct perf_raw_record raw = { | 4475 | struct perf_raw_record raw = { |
| 4475 | .size = entry_size, | 4476 | .size = entry_size, |
| @@ -4479,9 +4480,13 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record, | |||
| 4479 | perf_sample_data_init(&data, addr); | 4480 | perf_sample_data_init(&data, addr); |
| 4480 | data.raw = &raw; | 4481 | data.raw = &raw; |
| 4481 | 4482 | ||
| 4482 | /* Trace events already protected against recursion */ | 4483 | if (!event) { |
| 4483 | do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1, | 4484 | do_perf_sw_event(type, event_id, count, 1, &data, regs); |
| 4484 | &data, regs); | 4485 | return; |
| 4486 | } | ||
| 4487 | |||
| 4488 | if (perf_swevent_match(event, type, event_id, &data, regs)) | ||
| 4489 | perf_swevent_add(event, count, 1, &data, regs); | ||
| 4485 | } | 4490 | } |
| 4486 | EXPORT_SYMBOL_GPL(perf_tp_event); | 4491 | EXPORT_SYMBOL_GPL(perf_tp_event); |
| 4487 | 4492 | ||
| @@ -4514,7 +4519,7 @@ static const struct pmu *tp_perf_event_init(struct perf_event *event) | |||
| 4514 | !capable(CAP_SYS_ADMIN)) | 4519 | !capable(CAP_SYS_ADMIN)) |
| 4515 | return ERR_PTR(-EPERM); | 4520 | return ERR_PTR(-EPERM); |
| 4516 | 4521 | ||
| 4517 | if (perf_trace_enable(event->attr.config)) | 4522 | if (perf_trace_enable(event->attr.config, event)) |
| 4518 | return NULL; | 4523 | return NULL; |
| 4519 | 4524 | ||
| 4520 | event->destroy = tp_perf_event_destroy; | 4525 | event->destroy = tp_perf_event_destroy; |
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index 0565bb42566f..89b780a7c522 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c | |||
| @@ -27,13 +27,15 @@ typedef typeof(unsigned long [PERF_MAX_TRACE_SIZE / sizeof(unsigned long)]) | |||
| 27 | /* Count the events in use (per event id, not per instance) */ | 27 | /* Count the events in use (per event id, not per instance) */ |
| 28 | static int total_ref_count; | 28 | static int total_ref_count; |
| 29 | 29 | ||
| 30 | static int perf_trace_event_enable(struct ftrace_event_call *event) | 30 | static int perf_trace_event_enable(struct ftrace_event_call *event, void *data) |
| 31 | { | 31 | { |
| 32 | char *buf; | 32 | char *buf; |
| 33 | int ret = -ENOMEM; | 33 | int ret = -ENOMEM; |
| 34 | 34 | ||
| 35 | if (event->perf_refcount++ > 0) | 35 | if (event->perf_refcount++ > 0) { |
| 36 | event->perf_data = NULL; | ||
| 36 | return 0; | 37 | return 0; |
| 38 | } | ||
| 37 | 39 | ||
| 38 | if (!total_ref_count) { | 40 | if (!total_ref_count) { |
| 39 | buf = (char *)alloc_percpu(perf_trace_t); | 41 | buf = (char *)alloc_percpu(perf_trace_t); |
| @@ -51,6 +53,7 @@ static int perf_trace_event_enable(struct ftrace_event_call *event) | |||
| 51 | 53 | ||
| 52 | ret = event->perf_event_enable(event); | 54 | ret = event->perf_event_enable(event); |
| 53 | if (!ret) { | 55 | if (!ret) { |
| 56 | event->perf_data = data; | ||
| 54 | total_ref_count++; | 57 | total_ref_count++; |
| 55 | return 0; | 58 | return 0; |
| 56 | } | 59 | } |
| @@ -68,7 +71,7 @@ fail_buf: | |||
| 68 | return ret; | 71 | return ret; |
| 69 | } | 72 | } |
| 70 | 73 | ||
| 71 | int perf_trace_enable(int event_id) | 74 | int perf_trace_enable(int event_id, void *data) |
| 72 | { | 75 | { |
| 73 | struct ftrace_event_call *event; | 76 | struct ftrace_event_call *event; |
| 74 | int ret = -EINVAL; | 77 | int ret = -EINVAL; |
| @@ -77,7 +80,7 @@ int perf_trace_enable(int event_id) | |||
| 77 | list_for_each_entry(event, &ftrace_events, list) { | 80 | list_for_each_entry(event, &ftrace_events, list) { |
| 78 | if (event->id == event_id && event->perf_event_enable && | 81 | if (event->id == event_id && event->perf_event_enable && |
| 79 | try_module_get(event->mod)) { | 82 | try_module_get(event->mod)) { |
| 80 | ret = perf_trace_event_enable(event); | 83 | ret = perf_trace_event_enable(event, data); |
| 81 | break; | 84 | break; |
| 82 | } | 85 | } |
| 83 | } | 86 | } |
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index a7514326052b..2d7bf4146be8 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
| @@ -1362,7 +1362,7 @@ static __kprobes void kprobe_perf_func(struct kprobe *kp, | |||
| 1362 | for (i = 0; i < tp->nr_args; i++) | 1362 | for (i = 0; i < tp->nr_args; i++) |
| 1363 | call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset); | 1363 | call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset); |
| 1364 | 1364 | ||
| 1365 | perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, irq_flags, regs); | 1365 | perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, irq_flags, regs, call->perf_data); |
| 1366 | } | 1366 | } |
| 1367 | 1367 | ||
| 1368 | /* Kretprobe profile handler */ | 1368 | /* Kretprobe profile handler */ |
| @@ -1395,7 +1395,7 @@ static __kprobes void kretprobe_perf_func(struct kretprobe_instance *ri, | |||
| 1395 | call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset); | 1395 | call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset); |
| 1396 | 1396 | ||
| 1397 | perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1, | 1397 | perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1, |
| 1398 | irq_flags, regs); | 1398 | irq_flags, regs, call->perf_data); |
| 1399 | } | 1399 | } |
| 1400 | 1400 | ||
| 1401 | static int probe_perf_enable(struct ftrace_event_call *call) | 1401 | static int probe_perf_enable(struct ftrace_event_call *call) |
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 4d6d711717f2..9eff1a4b49b9 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
| @@ -468,7 +468,8 @@ static void perf_syscall_enter(struct pt_regs *regs, long id) | |||
| 468 | rec->nr = syscall_nr; | 468 | rec->nr = syscall_nr; |
| 469 | syscall_get_arguments(current, regs, 0, sys_data->nb_args, | 469 | syscall_get_arguments(current, regs, 0, sys_data->nb_args, |
| 470 | (unsigned long *)&rec->args); | 470 | (unsigned long *)&rec->args); |
| 471 | perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs); | 471 | perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs, |
| 472 | sys_data->enter_event->perf_data); | ||
| 472 | } | 473 | } |
| 473 | 474 | ||
| 474 | int perf_sysenter_enable(struct ftrace_event_call *call) | 475 | int perf_sysenter_enable(struct ftrace_event_call *call) |
| @@ -543,7 +544,8 @@ static void perf_syscall_exit(struct pt_regs *regs, long ret) | |||
| 543 | rec->nr = syscall_nr; | 544 | rec->nr = syscall_nr; |
| 544 | rec->ret = syscall_get_return_value(current, regs); | 545 | rec->ret = syscall_get_return_value(current, regs); |
| 545 | 546 | ||
| 546 | perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs); | 547 | perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs, |
| 548 | sys_data->exit_event->perf_data); | ||
| 547 | } | 549 | } |
| 548 | 550 | ||
| 549 | int perf_sysexit_enable(struct ftrace_event_call *call) | 551 | int perf_sysexit_enable(struct ftrace_event_call *call) |
