tracing: Remove per event trace registering

This patch removes the register functions of TRACE_EVENT() to enable
and disable tracepoints. The registering of a event is now down
directly in the trace_events.c file. The tracepoint_probe_register()
is now called directly.

The prototypes are no longer type checked, but this should not be
an issue since the tracepoints are created automatically by the
macros. If a prototype is incorrect in the TRACE_EVENT() macro, then
other macros will catch it.

The trace_event_class structure now holds the probes to be called
by the callbacks. This removes needing to have each event have
a separate pointer for the probe.

To handle kprobes and syscalls, since they register probes in a
different manner, a "reg" field is added to the ftrace_event_class
structure. If the "reg" field is assigned, then it will be called for
enabling and disabling of the probe for either ftrace or perf. To let
the reg function know what is happening, a new enum (trace_reg) is
created that has the type of control that is needed.

With this new rework, the 82 kernel events and 618 syscall events
has their footprint dramatically lowered:

   text	   data	    bss	    dec	    hex	filename
4913961	1088356	 861512	6863829	 68bbd5	vmlinux.orig
4914025	1088868	 861512	6864405	 68be15	vmlinux.class
4918492	1084612	 861512	6864616	 68bee8	vmlinux.tracepoint
4900252	1057412	 861512	6819176	 680d68	vmlinux.regs

The size went from 6863829 to 6819176, that's a total of 44K
in savings. With tracepoints being continuously added, this is
critical that the footprint becomes minimal.

v5: Added #ifdef CONFIG_PERF_EVENTS around a reference to perf
    specific structure in trace_events.c.

v4: Fixed trace self tests to check probe because regfunc no longer
    exists.

v3: Updated to handle void *data in beginning of probe parameters.
    Also added the tracepoint: check_trace_callback_type_##call().

v2: Changed the callback probes to pass void * and typecast the
    value within the function.

Acked-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Acked-by: Masami Hiramatsu <mhiramat@redhat.com>
Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
This commit is contained in:
Steven Rostedt
2010-04-21 12:27:06 -04:00
committed by Steven Rostedt
parent 38516ab59f
commit 2239291aeb
7 changed files with 171 additions and 147 deletions
+12 -3
View File
@@ -49,7 +49,12 @@ static int perf_trace_event_enable(struct ftrace_event_call *event)
rcu_assign_pointer(perf_trace_buf_nmi, buf);
}
ret = event->perf_event_enable(event);
if (event->class->reg)
ret = event->class->reg(event, TRACE_REG_PERF_REGISTER);
else
ret = tracepoint_probe_register(event->name,
event->class->perf_probe,
event);
if (!ret) {
total_ref_count++;
return 0;
@@ -75,7 +80,8 @@ int perf_trace_enable(int event_id)
mutex_lock(&event_mutex);
list_for_each_entry(event, &ftrace_events, list) {
if (event->id == event_id && event->perf_event_enable &&
if (event->id == event_id &&
event->class && event->class->perf_probe &&
try_module_get(event->mod)) {
ret = perf_trace_event_enable(event);
break;
@@ -93,7 +99,10 @@ static void perf_trace_event_disable(struct ftrace_event_call *event)
if (--event->perf_refcount > 0)
return;
event->perf_event_disable(event);
if (event->class->reg)
event->class->reg(event, TRACE_REG_PERF_UNREGISTER);
else
tracepoint_probe_unregister(event->name, event->class->perf_probe, event);
if (!--total_ref_count) {
buf = perf_trace_buf;
+23 -9
View File
@@ -127,13 +127,23 @@ static int ftrace_event_enable_disable(struct ftrace_event_call *call,
if (call->enabled) {
call->enabled = 0;
tracing_stop_cmdline_record();
call->unregfunc(call);
if (call->class->reg)
call->class->reg(call, TRACE_REG_UNREGISTER);
else
tracepoint_probe_unregister(call->name,
call->class->probe,
call);
}
break;
case 1:
if (!call->enabled) {
tracing_start_cmdline_record();
ret = call->regfunc(call);
if (call->class->reg)
ret = call->class->reg(call, TRACE_REG_REGISTER);
else
ret = tracepoint_probe_register(call->name,
call->class->probe,
call);
if (ret) {
tracing_stop_cmdline_record();
pr_info("event trace: Could not enable event "
@@ -171,7 +181,8 @@ static int __ftrace_set_clr_event(const char *match, const char *sub,
mutex_lock(&event_mutex);
list_for_each_entry(call, &ftrace_events, list) {
if (!call->name || !call->regfunc)
if (!call->name || !call->class ||
(!call->class->probe && !call->class->reg))
continue;
if (match &&
@@ -297,7 +308,7 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
* The ftrace subsystem is for showing formats only.
* They can not be enabled or disabled via the event files.
*/
if (call->regfunc)
if (call->class && (call->class->probe || call->class->reg))
return call;
}
@@ -450,7 +461,8 @@ system_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
mutex_lock(&event_mutex);
list_for_each_entry(call, &ftrace_events, list) {
if (!call->name || !call->regfunc)
if (!call->name || !call->class ||
(!call->class->probe && !call->class->reg))
continue;
if (system && strcmp(call->class->system, system) != 0)
@@ -935,13 +947,15 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
return -1;
}
if (call->regfunc)
if (call->class->probe || call->class->reg)
trace_create_file("enable", 0644, call->dir, call,
enable);
if (call->id && call->perf_event_enable)
#ifdef CONFIG_PERF_EVENTS
if (call->id && (call->class->perf_probe || call->class->reg))
trace_create_file("id", 0444, call->dir, call,
id);
#endif
if (call->define_fields) {
ret = trace_define_common_fields(call);
@@ -1388,8 +1402,8 @@ static __init void event_trace_self_tests(void)
list_for_each_entry(call, &ftrace_events, list) {
/* Only test those that have a regfunc */
if (!call->regfunc)
/* Only test those that have a probe */
if (!call->class || !call->class->probe)
continue;
/*
+25 -9
View File
@@ -202,6 +202,7 @@ struct trace_probe {
unsigned long nhit;
unsigned int flags; /* For TP_FLAG_* */
const char *symbol; /* symbol name */
struct ftrace_event_class class;
struct ftrace_event_call call;
struct trace_event event;
unsigned int nr_args;
@@ -323,6 +324,7 @@ static struct trace_probe *alloc_trace_probe(const char *group,
goto error;
}
tp->call.class = &tp->class;
tp->call.name = kstrdup(event, GFP_KERNEL);
if (!tp->call.name)
goto error;
@@ -332,8 +334,8 @@ static struct trace_probe *alloc_trace_probe(const char *group,
goto error;
}
tp->call.class->system = kstrdup(group, GFP_KERNEL);
if (!tp->call.class->system)
tp->class.system = kstrdup(group, GFP_KERNEL);
if (!tp->class.system)
goto error;
INIT_LIST_HEAD(&tp->list);
@@ -1302,6 +1304,26 @@ static void probe_perf_disable(struct ftrace_event_call *call)
}
#endif /* CONFIG_PERF_EVENTS */
static __kprobes
int kprobe_register(struct ftrace_event_call *event, enum trace_reg type)
{
switch (type) {
case TRACE_REG_REGISTER:
return probe_event_enable(event);
case TRACE_REG_UNREGISTER:
probe_event_disable(event);
return 0;
#ifdef CONFIG_PERF_EVENTS
case TRACE_REG_PERF_REGISTER:
return probe_perf_enable(event);
case TRACE_REG_PERF_UNREGISTER:
probe_perf_disable(event);
return 0;
#endif
}
return 0;
}
static __kprobes
int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs)
@@ -1355,13 +1377,7 @@ static int register_probe_event(struct trace_probe *tp)
return -ENODEV;
}
call->enabled = 0;
call->regfunc = probe_event_enable;
call->unregfunc = probe_event_disable;
#ifdef CONFIG_PERF_EVENTS
call->perf_event_enable = probe_perf_enable;
call->perf_event_disable = probe_perf_disable;
#endif
call->class->reg = kprobe_register;
call->data = tp;
ret = trace_add_event_call(call);
if (ret) {
+54 -2
View File
@@ -15,8 +15,19 @@ static int sys_refcount_exit;
static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);
static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls);
struct ftrace_event_class event_class_syscalls = {
.system = "syscalls"
static int syscall_enter_register(struct ftrace_event_call *event,
enum trace_reg type);
static int syscall_exit_register(struct ftrace_event_call *event,
enum trace_reg type);
struct ftrace_event_class event_class_syscall_enter = {
.system = "syscalls",
.reg = syscall_enter_register
};
struct ftrace_event_class event_class_syscall_exit = {
.system = "syscalls",
.reg = syscall_exit_register
};
extern unsigned long __start_syscalls_metadata[];
@@ -587,3 +598,44 @@ void perf_sysexit_disable(struct ftrace_event_call *call)
#endif /* CONFIG_PERF_EVENTS */
static int syscall_enter_register(struct ftrace_event_call *event,
enum trace_reg type)
{
switch (type) {
case TRACE_REG_REGISTER:
return reg_event_syscall_enter(event);
case TRACE_REG_UNREGISTER:
unreg_event_syscall_enter(event);
return 0;
#ifdef CONFIG_PERF_EVENTS
case TRACE_REG_PERF_REGISTER:
return perf_sysenter_enable(event);
case TRACE_REG_PERF_UNREGISTER:
perf_sysenter_disable(event);
return 0;
#endif
}
return 0;
}
static int syscall_exit_register(struct ftrace_event_call *event,
enum trace_reg type)
{
switch (type) {
case TRACE_REG_REGISTER:
return reg_event_syscall_exit(event);
case TRACE_REG_UNREGISTER:
unreg_event_syscall_exit(event);
return 0;
#ifdef CONFIG_PERF_EVENTS
case TRACE_REG_PERF_REGISTER:
return perf_sysexit_enable(event);
case TRACE_REG_PERF_UNREGISTER:
perf_sysexit_disable(event);
return 0;
#endif
}
return 0;
}