ftrace: event profile hooks
authorPeter Zijlstra <a.p.zijlstra@chello.nl>
Thu, 19 Mar 2009 19:26:15 +0000 (20:26 +0100)
committerIngo Molnar <mingo@elte.hu>
Fri, 20 Mar 2009 09:17:07 +0000 (10:17 +0100)
Impact: new tracing infrastructure feature

Provide infrastructure to generate software perf counter events
from tracepoints.

Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
LKML-Reference: <20090319194233.557364871@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
kernel/trace/Makefile
kernel/trace/events.c
kernel/trace/trace.h
kernel/trace/trace_event_profile.c [new file with mode: 0644]
kernel/trace/trace_events.c
kernel/trace/trace_events_stage_3.h

index c3feea01c3e0c0738e3c00a095c9d4bc24136970..0e45c206c2f9f942f1e5119ae09827970a0025e0 100644 (file)
@@ -44,5 +44,6 @@ obj-$(CONFIG_EVENT_TRACER) += trace_events.o
 obj-$(CONFIG_EVENT_TRACER) += events.o
 obj-$(CONFIG_EVENT_TRACER) += trace_export.o
 obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o
+obj-$(CONFIG_EVENT_PROFILE) += trace_event_profile.o
 
 libftrace-y := ftrace.o
index 9fc918da404f6236a1f351877c6af65c48bf29a4..246f2aa6dc468457846cd5e1dd48e89b92d245ae 100644 (file)
@@ -12,4 +12,3 @@
 #include "trace_events_stage_2.h"
 #include "trace_events_stage_3.h"
 
-#include <trace/trace_event_types.h>
index 7c9a0cbf5dca46fbbff14c40af17db7a71d8073f..7cfb741be2001862b3ddba9df6109f422b631bbd 100644 (file)
@@ -785,12 +785,23 @@ struct ftrace_event_call {
        int             id;
        int             (*raw_init)(void);
        int             (*show_format)(struct trace_seq *s);
+
+#ifdef CONFIG_EVENT_PROFILE
+       atomic_t        profile_count;
+       int             (*profile_enable)(struct ftrace_event_call *);
+       void            (*profile_disable)(struct ftrace_event_call *);
+#endif
 };
 
 void event_trace_printk(unsigned long ip, const char *fmt, ...);
 extern struct ftrace_event_call __start_ftrace_events[];
 extern struct ftrace_event_call __stop_ftrace_events[];
 
+#define for_each_event(event)                                          \
+       for (event = __start_ftrace_events;                             \
+            (unsigned long)event < (unsigned long)__stop_ftrace_events; \
+            event++)
+
 extern const char *__start___trace_bprintk_fmt[];
 extern const char *__stop___trace_bprintk_fmt[];
 
diff --git a/kernel/trace/trace_event_profile.c b/kernel/trace/trace_event_profile.c
new file mode 100644 (file)
index 0000000..22cba99
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * trace event based perf counter profiling
+ *
+ * Copyright (C) 2009 Red Hat Inc, Peter Zijlstra <pzijlstr@redhat.com>
+ *
+ */
+
+#include "trace.h"
+
+int ftrace_profile_enable(int event_id)
+{
+       struct ftrace_event_call *event;
+
+       for_each_event(event) {
+               if (event->id == event_id)
+                       return event->profile_enable(event);
+       }
+
+       return -EINVAL;
+}
+
+void ftrace_profile_disable(int event_id)
+{
+       struct ftrace_event_call *event;
+
+       for_each_event(event) {
+               if (event->id == event_id)
+                       return event->profile_disable(event);
+       }
+}
+
index 7763db8fd0b3539d26a53dd90b3ecbdd5e059452..3047b56f663732ccb1701d6535b01546d0ab1da2 100644 (file)
 
 static DEFINE_MUTEX(event_mutex);
 
-#define events_for_each(event)                                         \
-       for (event = __start_ftrace_events;                             \
-            (unsigned long)event < (unsigned long)__stop_ftrace_events; \
-            event++)
-
 static void ftrace_clear_events(void)
 {
        struct ftrace_event_call *call = (void *)__start_ftrace_events;
@@ -90,7 +85,7 @@ static int ftrace_set_clr_event(char *buf, int set)
        }
 
        mutex_lock(&event_mutex);
-       events_for_each(call) {
+       for_each_event(call) {
 
                if (!call->name || !call->regfunc)
                        continue;
@@ -628,7 +623,7 @@ static __init int event_trace_init(void)
        if (!d_events)
                return 0;
 
-       events_for_each(call) {
+       for_each_event(call) {
                /* The linker may leave blanks */
                if (!call->name)
                        continue;
index 4c26d97b450836515b3978da1d2a80f9e82962e7..6b3261ca988c69676c6f890420507fa5d91ad76a 100644 (file)
 #undef TP_FMT
 #define TP_FMT(fmt, args...)   fmt "\n", ##args
 
+#ifdef CONFIG_EVENT_PROFILE
+#define _TRACE_PROFILE(call, proto, args)                              \
+static void ftrace_profile_##call(proto)                               \
+{                                                                      \
+       extern void perf_tpcounter_event(int);                          \
+       perf_tpcounter_event(event_##call.id);                          \
+}                                                                      \
+                                                                       \
+static int ftrace_profile_enable_##call(struct ftrace_event_call *call) \
+{                                                                      \
+       int ret = 0;                                                    \
+                                                                       \
+       if (!atomic_inc_return(&call->profile_count))                   \
+               ret = register_trace_##call(ftrace_profile_##call);     \
+                                                                       \
+       return ret;                                                     \
+}                                                                      \
+                                                                       \
+static void ftrace_profile_disable_##call(struct ftrace_event_call *call) \
+{                                                                      \
+       if (atomic_add_negative(-1, &call->profile_count))              \
+               unregister_trace_##call(ftrace_profile_##call);         \
+}
+
+#define _TRACE_PROFILE_INIT(call)                                      \
+       .profile_count = ATOMIC_INIT(-1),                               \
+       .profile_enable = ftrace_profile_enable_##call,                 \
+       .profile_disable = ftrace_profile_disable_##call,
+
+#else
+#define _TRACE_PROFILE(call, proto, args)
+#define _TRACE_PROFILE_INIT(call)
+#endif
+
 #define _TRACE_FORMAT(call, proto, args, fmt)                          \
 static void ftrace_event_##call(proto)                                 \
 {                                                                      \
@@ -147,6 +181,7 @@ static int ftrace_init_event_##call(void)                           \
 #undef TRACE_FORMAT
 #define TRACE_FORMAT(call, proto, args, fmt)                           \
 _TRACE_FORMAT(call, PARAMS(proto), PARAMS(args), PARAMS(fmt))          \
+_TRACE_PROFILE(call, PARAMS(proto), PARAMS(args))                      \
 static struct ftrace_event_call __used                                 \
 __attribute__((__aligned__(4)))                                                \
 __attribute__((section("_ftrace_events"))) event_##call = {            \
@@ -155,6 +190,7 @@ __attribute__((section("_ftrace_events"))) event_##call = {         \
        .raw_init               = ftrace_init_event_##call,             \
        .regfunc                = ftrace_reg_event_##call,              \
        .unregfunc              = ftrace_unreg_event_##call,            \
+       _TRACE_PROFILE_INIT(call)                                       \
 }
 
 #undef __entry
@@ -162,6 +198,7 @@ __attribute__((section("_ftrace_events"))) event_##call = {         \
 
 #undef TRACE_EVENT
 #define TRACE_EVENT(call, proto, args, tstruct, assign, print)         \
+_TRACE_PROFILE(call, PARAMS(proto), PARAMS(args))                      \
                                                                        \
 static struct ftrace_event_call event_##call;                          \
                                                                        \
@@ -227,4 +264,11 @@ __attribute__((section("_ftrace_events"))) event_##call = {                \
        .regfunc                = ftrace_raw_reg_event_##call,          \
        .unregfunc              = ftrace_raw_unreg_event_##call,        \
        .show_format            = ftrace_format_##call,                 \
+       _TRACE_PROFILE_INIT(call)                                       \
 }
+
+#include <trace/trace_event_types.h>
+
+#undef _TRACE_PROFILE
+#undef _TRACE_PROFILE_INIT
+