Commit 4f41c013 authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar

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: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
Tested-by: default avatarIngo 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: default avatarIngo Molnar <mingo@elte.hu>
parent ef4f30f5
...@@ -132,6 +132,7 @@ struct ftrace_event_call { ...@@ -132,6 +132,7 @@ struct ftrace_event_call {
void *data; void *data;
int perf_refcount; int perf_refcount;
void *perf_data;
int (*perf_event_enable)(struct ftrace_event_call *); int (*perf_event_enable)(struct ftrace_event_call *);
void (*perf_event_disable)(struct ftrace_event_call *); void (*perf_event_disable)(struct ftrace_event_call *);
}; };
...@@ -190,7 +191,7 @@ struct perf_event; ...@@ -190,7 +191,7 @@ struct perf_event;
DECLARE_PER_CPU(struct pt_regs, perf_trace_regs); DECLARE_PER_CPU(struct pt_regs, perf_trace_regs);
extern int perf_trace_enable(int event_id); extern int perf_trace_enable(int event_id, void *data);
extern void perf_trace_disable(int event_id); extern void perf_trace_disable(int event_id);
extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, extern int ftrace_profile_set_filter(struct perf_event *event, int event_id,
char *filter_str); char *filter_str);
...@@ -201,11 +202,12 @@ perf_trace_buf_prepare(int size, unsigned short type, int *rctxp, ...@@ -201,11 +202,12 @@ perf_trace_buf_prepare(int size, unsigned short type, int *rctxp,
static inline void static inline void
perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr, perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr,
u64 count, unsigned long irq_flags, struct pt_regs *regs) u64 count, unsigned long irq_flags, struct pt_regs *regs,
void *event)
{ {
struct trace_entry *entry = raw_data; struct trace_entry *entry = raw_data;
perf_tp_event(entry->type, addr, count, raw_data, size, regs); perf_tp_event(entry->type, addr, count, raw_data, size, regs, event);
perf_swevent_put_recursion_context(rctx); perf_swevent_put_recursion_context(rctx);
local_irq_restore(irq_flags); local_irq_restore(irq_flags);
} }
......
...@@ -994,7 +994,7 @@ static inline bool perf_paranoid_kernel(void) ...@@ -994,7 +994,7 @@ static inline bool perf_paranoid_kernel(void)
extern void perf_event_init(void); extern void perf_event_init(void);
extern void perf_tp_event(int event_id, u64 addr, u64 count, void *record, extern void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
int entry_size, struct pt_regs *regs); int entry_size, struct pt_regs *regs, void *event);
extern void perf_bp_event(struct perf_event *event, void *data); extern void perf_bp_event(struct perf_event *event, void *data);
#ifndef perf_misc_flags #ifndef perf_misc_flags
......
...@@ -785,7 +785,8 @@ perf_trace_templ_##call(struct ftrace_event_call *event_call, \ ...@@ -785,7 +785,8 @@ perf_trace_templ_##call(struct ftrace_event_call *event_call, \
{ assign; } \ { assign; } \
\ \
perf_trace_buf_submit(entry, __entry_size, rctx, __addr, \ perf_trace_buf_submit(entry, __entry_size, rctx, __addr, \
__count, irq_flags, __regs); \ __count, irq_flags, __regs, \
event_call->perf_data); \
} }
#undef DEFINE_EVENT #undef DEFINE_EVENT
......
...@@ -4468,8 +4468,9 @@ static int swevent_hlist_get(struct perf_event *event) ...@@ -4468,8 +4468,9 @@ static int swevent_hlist_get(struct perf_event *event)
#ifdef CONFIG_EVENT_TRACING #ifdef CONFIG_EVENT_TRACING
void perf_tp_event(int event_id, u64 addr, u64 count, void *record, void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
int entry_size, struct pt_regs *regs) int entry_size, struct pt_regs *regs, void *event)
{ {
const int type = PERF_TYPE_TRACEPOINT;
struct perf_sample_data data; struct perf_sample_data data;
struct perf_raw_record raw = { struct perf_raw_record raw = {
.size = entry_size, .size = entry_size,
...@@ -4479,9 +4480,13 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record, ...@@ -4479,9 +4480,13 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
perf_sample_data_init(&data, addr); perf_sample_data_init(&data, addr);
data.raw = &raw; data.raw = &raw;
/* Trace events already protected against recursion */ if (!event) {
do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1, do_perf_sw_event(type, event_id, count, 1, &data, regs);
&data, regs); return;
}
if (perf_swevent_match(event, type, event_id, &data, regs))
perf_swevent_add(event, count, 1, &data, regs);
} }
EXPORT_SYMBOL_GPL(perf_tp_event); EXPORT_SYMBOL_GPL(perf_tp_event);
...@@ -4514,7 +4519,7 @@ static const struct pmu *tp_perf_event_init(struct perf_event *event) ...@@ -4514,7 +4519,7 @@ static const struct pmu *tp_perf_event_init(struct perf_event *event)
!capable(CAP_SYS_ADMIN)) !capable(CAP_SYS_ADMIN))
return ERR_PTR(-EPERM); return ERR_PTR(-EPERM);
if (perf_trace_enable(event->attr.config)) if (perf_trace_enable(event->attr.config, event))
return NULL; return NULL;
event->destroy = tp_perf_event_destroy; event->destroy = tp_perf_event_destroy;
......
...@@ -27,13 +27,15 @@ typedef typeof(unsigned long [PERF_MAX_TRACE_SIZE / sizeof(unsigned long)]) ...@@ -27,13 +27,15 @@ typedef typeof(unsigned long [PERF_MAX_TRACE_SIZE / sizeof(unsigned long)])
/* Count the events in use (per event id, not per instance) */ /* Count the events in use (per event id, not per instance) */
static int total_ref_count; static int total_ref_count;
static int perf_trace_event_enable(struct ftrace_event_call *event) static int perf_trace_event_enable(struct ftrace_event_call *event, void *data)
{ {
char *buf; char *buf;
int ret = -ENOMEM; int ret = -ENOMEM;
if (event->perf_refcount++ > 0) if (event->perf_refcount++ > 0) {
event->perf_data = NULL;
return 0; return 0;
}
if (!total_ref_count) { if (!total_ref_count) {
buf = (char *)alloc_percpu(perf_trace_t); buf = (char *)alloc_percpu(perf_trace_t);
...@@ -51,6 +53,7 @@ static int perf_trace_event_enable(struct ftrace_event_call *event) ...@@ -51,6 +53,7 @@ static int perf_trace_event_enable(struct ftrace_event_call *event)
ret = event->perf_event_enable(event); ret = event->perf_event_enable(event);
if (!ret) { if (!ret) {
event->perf_data = data;
total_ref_count++; total_ref_count++;
return 0; return 0;
} }
...@@ -68,7 +71,7 @@ static int perf_trace_event_enable(struct ftrace_event_call *event) ...@@ -68,7 +71,7 @@ static int perf_trace_event_enable(struct ftrace_event_call *event)
return ret; return ret;
} }
int perf_trace_enable(int event_id) int perf_trace_enable(int event_id, void *data)
{ {
struct ftrace_event_call *event; struct ftrace_event_call *event;
int ret = -EINVAL; int ret = -EINVAL;
...@@ -77,7 +80,7 @@ int perf_trace_enable(int event_id) ...@@ -77,7 +80,7 @@ int perf_trace_enable(int event_id)
list_for_each_entry(event, &ftrace_events, list) { list_for_each_entry(event, &ftrace_events, list) {
if (event->id == event_id && event->perf_event_enable && if (event->id == event_id && event->perf_event_enable &&
try_module_get(event->mod)) { try_module_get(event->mod)) {
ret = perf_trace_event_enable(event); ret = perf_trace_event_enable(event, data);
break; break;
} }
} }
......
...@@ -1362,7 +1362,7 @@ static __kprobes void kprobe_perf_func(struct kprobe *kp, ...@@ -1362,7 +1362,7 @@ static __kprobes void kprobe_perf_func(struct kprobe *kp,
for (i = 0; i < tp->nr_args; i++) for (i = 0; i < tp->nr_args; i++)
call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset); call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset);
perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, irq_flags, regs); perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, irq_flags, regs, call->perf_data);
} }
/* Kretprobe profile handler */ /* Kretprobe profile handler */
...@@ -1395,7 +1395,7 @@ static __kprobes void kretprobe_perf_func(struct kretprobe_instance *ri, ...@@ -1395,7 +1395,7 @@ static __kprobes void kretprobe_perf_func(struct kretprobe_instance *ri,
call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset); call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset);
perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1, perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1,
irq_flags, regs); irq_flags, regs, call->perf_data);
} }
static int probe_perf_enable(struct ftrace_event_call *call) static int probe_perf_enable(struct ftrace_event_call *call)
......
...@@ -468,7 +468,8 @@ static void perf_syscall_enter(struct pt_regs *regs, long id) ...@@ -468,7 +468,8 @@ static void perf_syscall_enter(struct pt_regs *regs, long id)
rec->nr = syscall_nr; rec->nr = syscall_nr;
syscall_get_arguments(current, regs, 0, sys_data->nb_args, syscall_get_arguments(current, regs, 0, sys_data->nb_args,
(unsigned long *)&rec->args); (unsigned long *)&rec->args);
perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs); perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs,
sys_data->enter_event->perf_data);
} }
int perf_sysenter_enable(struct ftrace_event_call *call) 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,7 +544,8 @@ static void perf_syscall_exit(struct pt_regs *regs, long ret)
rec->nr = syscall_nr; rec->nr = syscall_nr;
rec->ret = syscall_get_return_value(current, regs); rec->ret = syscall_get_return_value(current, regs);
perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs); perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs,
sys_data->exit_event->perf_data);
} }
int perf_sysexit_enable(struct ftrace_event_call *call) int perf_sysexit_enable(struct ftrace_event_call *call)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment