This macro allows to create an alias of an existing TRACE_EVENT. A
TRACE_EVENT_MAP connects a new probe to an existing tracepoint, so we
can use it to create another output of the same tracepoint without
changing the instrumented code.

This allows to create alternate versions of existing tracepoints to
output more/other fields only in specific use-cases and not all the time
(which could break existing tools and/or bloat the trace with too many
useless fields).

The usage is the same as the TRACE_EVENT macro with the addition of the
"map" parameter which is the name of the alias, the "name" field is the
name of the original tracepoint:
TRACE_EVENT_MAP(name, map, proto, args, tstruct, assign, print)
DEFINE_EVENT_MAP(template, name, map, proto, args)

Cc: Peter Zijlstra <pet...@infradead.org>
Cc: Steven Rostedt (Red Hat) <rost...@goodmis.org>
Cc: Thomas Gleixner <t...@linutronix.de>
Cc: Ingo Molnar <mi...@redhat.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoy...@efficios.com>
Signed-off-by: Julien Desfossez <jdesfos...@efficios.com>
---
 include/linux/trace_events.h | 14 ++++++++++++-
 include/linux/tracepoint.h   | 11 +++++++++-
 include/trace/define_trace.h |  4 ++++
 include/trace/perf.h         |  7 +++++++
 include/trace/trace_events.h | 50 ++++++++++++++++++++++++++++++++++++++++++++
 kernel/trace/trace_events.c  | 15 +++++++++----
 6 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
index be00761..1f7e0ec 100644
--- a/include/linux/trace_events.h
+++ b/include/linux/trace_events.h
@@ -217,6 +217,7 @@ enum {
        TRACE_EVENT_FL_TRACEPOINT_BIT,
        TRACE_EVENT_FL_KPROBE_BIT,
        TRACE_EVENT_FL_UPROBE_BIT,
+       TRACE_EVENT_FL_MAP_BIT,
 };
 
 /*
@@ -231,6 +232,7 @@ enum {
  *  TRACEPOINT    - Event is a tracepoint
  *  KPROBE        - Event is a kprobe
  *  UPROBE        - Event is a uprobe
+ *  MAP           - Event maps to a tracepoint as an alias
  */
 enum {
        TRACE_EVENT_FL_FILTERED         = (1 << TRACE_EVENT_FL_FILTERED_BIT),
@@ -241,10 +243,16 @@ enum {
        TRACE_EVENT_FL_TRACEPOINT       = (1 << TRACE_EVENT_FL_TRACEPOINT_BIT),
        TRACE_EVENT_FL_KPROBE           = (1 << TRACE_EVENT_FL_KPROBE_BIT),
        TRACE_EVENT_FL_UPROBE           = (1 << TRACE_EVENT_FL_UPROBE_BIT),
+       TRACE_EVENT_FL_MAP              = (1 << TRACE_EVENT_FL_MAP_BIT),
 };
 
 #define TRACE_EVENT_FL_UKPROBE (TRACE_EVENT_FL_KPROBE | TRACE_EVENT_FL_UPROBE)
 
+struct trace_event_map {
+       struct tracepoint       *tp;
+       char                    *name;
+};
+
 struct trace_event_call {
        struct list_head        list;
        struct trace_event_class *class;
@@ -252,6 +260,8 @@ struct trace_event_call {
                char                    *name;
                /* Set TRACE_EVENT_FL_TRACEPOINT flag when using "tp" */
                struct tracepoint       *tp;
+               /* Set TRACE_EVENT_FL_MAP flag when using "map" instead */
+               struct trace_event_map  *map;
        };
        struct trace_event      event;
        char                    *print_fmt;
@@ -282,7 +292,9 @@ struct trace_event_call {
 static inline const char *
 trace_event_name(struct trace_event_call *call)
 {
-       if (call->flags & TRACE_EVENT_FL_TRACEPOINT)
+       if (call->flags & TRACE_EVENT_FL_MAP)
+               return call->map->name;
+       else if (call->flags & TRACE_EVENT_FL_TRACEPOINT)
                return call->tp ? call->tp->name : NULL;
        else
                return call->name;
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index be586c6..b8ab12a 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -276,6 +276,7 @@ static inline void tracepoint_synchronize_unregister(void)
 
 #define DEFINE_TRACE_FN(name, reg, unreg)
 #define DEFINE_TRACE(name)
+#define DEFINE_TRACE_MAP(name, map)
 #define EXPORT_TRACEPOINT_SYMBOL_GPL(name)
 #define EXPORT_TRACEPOINT_SYMBOL(name)
 
@@ -466,6 +467,13 @@ static inline void tracepoint_synchronize_unregister(void)
  *
  * A set of (un)registration functions can be passed to the variant
  * TRACE_EVENT_FN to perform any (un)registration work.
+ *
+ * TRACE_EVENT_MAP can be used to create alternate versions of a
+ * TRACE_EVENT without modifying the instrumented code. It connects
+ * a different probe to an existing tracepoint, so other fields can be
+ * extracted. The "name" field is the name of the original TRACE_EVENT,
+ * the "map" field is the name of the alias. They can be enabled
+ * independently.
  */
 
 #define DECLARE_EVENT_CLASS(name, proto, args, tstruct, assign, print)
@@ -493,9 +501,10 @@ static inline void tracepoint_synchronize_unregister(void)
                              struct, assign, print)            \
        DECLARE_TRACE_CONDITION(name, PARAMS(proto),            \
                                PARAMS(args), PARAMS(cond))
-
 #define TRACE_EVENT_FLAGS(event, flag)
 
 #define TRACE_EVENT_PERF_PERM(event, expr...)
 
+#define TRACE_EVENT_MAP(name, map, proto, args, struct, assign, print)
+
 #endif /* ifdef TRACE_EVENT (see note above) */
diff --git a/include/trace/define_trace.h b/include/trace/define_trace.h
index 6e3945f..fdd8845 100644
--- a/include/trace/define_trace.h
+++ b/include/trace/define_trace.h
@@ -26,6 +26,9 @@
 #define TRACE_EVENT(name, proto, args, tstruct, assign, print) \
        DEFINE_TRACE(name)
 
+#undef TRACE_EVENT_MAP
+#define TRACE_EVENT_MAP(name, map, proto, args, tstruct, assign, print)
+
 #undef TRACE_EVENT_CONDITION
 #define TRACE_EVENT_CONDITION(name, proto, args, cond, tstruct, assign, print) 
\
        TRACE_EVENT(name,                                               \
@@ -100,6 +103,7 @@
 #undef TRACE_EVENT_FN
 #undef TRACE_EVENT_FN_COND
 #undef TRACE_EVENT_CONDITION
+#undef TRACE_EVENT_MAP
 #undef DECLARE_EVENT_CLASS
 #undef DEFINE_EVENT
 #undef DEFINE_EVENT_FN
diff --git a/include/trace/perf.h b/include/trace/perf.h
index 04fe68bb..563d441 100644
--- a/include/trace/perf.h
+++ b/include/trace/perf.h
@@ -86,5 +86,12 @@
 #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
        DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
 
+#undef DEFINE_EVENT_MAP
+#define DEFINE_EVENT_MAP(template, call, map, proto, args)             \
+static inline void perf_test_probe_##map(void)                         \
+{                                                                      \
+       check_trace_callback_type_##call(perf_trace_##template);        \
+}
+
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 #endif /* CONFIG_PERF_EVENTS */
diff --git a/include/trace/trace_events.h b/include/trace/trace_events.h
index 467e12f..deb5bc6 100644
--- a/include/trace/trace_events.h
+++ b/include/trace/trace_events.h
@@ -65,6 +65,15 @@
                             PARAMS(print));                   \
        DEFINE_EVENT(name, name, PARAMS(proto), PARAMS(args));
 
+#undef TRACE_EVENT_MAP
+#define TRACE_EVENT_MAP(name, map, proto, args, tstruct, assign, print) \
+       DECLARE_EVENT_CLASS(map,                               \
+                            PARAMS(proto),                    \
+                            PARAMS(args),                     \
+                            PARAMS(tstruct),                  \
+                            PARAMS(assign),                   \
+                            PARAMS(print));                   \
+       DEFINE_EVENT_MAP(map, name, map, PARAMS(proto), PARAMS(args));
 
 #undef __field
 #define __field(type, item)            type    item;
@@ -108,6 +117,11 @@
        static struct trace_event_call  __used          \
        __attribute__((__aligned__(4))) event_##name
 
+#undef DEFINE_EVENT_MAP
+#define DEFINE_EVENT_MAP(template, name, map, proto, args)     \
+       static struct trace_event_call  __used          \
+       __attribute__((__aligned__(4))) event_##map
+
 #undef DEFINE_EVENT_FN
 #define DEFINE_EVENT_FN(template, name, proto, args, reg, unreg)       \
        DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
@@ -191,6 +205,9 @@
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, name, proto, args)
 
+#undef DEFINE_EVENT_MAP
+#define DEFINE_EVENT_MAP(template, name, map, proto, args)
+
 #undef DEFINE_EVENT_PRINT
 #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
        DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
@@ -426,6 +443,9 @@
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, name, proto, args)
 
+#undef DEFINE_EVENT_MAP
+#define DEFINE_EVENT_MAP(template, name, map, proto, args)
+
 #undef DEFINE_EVENT_PRINT
 #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
        DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
@@ -506,6 +526,9 @@
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, name, proto, args)
 
+#undef DEFINE_EVENT_MAP
+#define DEFINE_EVENT_MAP(template, name, map, proto, args)
+
 #undef DEFINE_EVENT_PRINT
 #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
        DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
@@ -700,6 +723,13 @@
        check_trace_callback_type_##call(trace_event_raw_event_##template); \
 }
 
+#undef DEFINE_EVENT_MAP
+#define DEFINE_EVENT_MAP(template, call, map, proto, args)             \
+static inline void ftrace_test_probe_##map(void)                       \
+{                                                                      \
+       check_trace_callback_type_##call(trace_event_raw_event_##template); \
+}
+
 #undef DEFINE_EVENT_PRINT
 #define DEFINE_EVENT_PRINT(template, name, proto, args, print)
 
@@ -749,6 +779,26 @@
 static struct trace_event_call __used                                  \
 __attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
 
+#undef DEFINE_EVENT_MAP
+#define DEFINE_EVENT_MAP(_template, _call, _map, _proto, _args)                
\
+                                                                       \
+static struct trace_event_map event_map_##_map = {                     \
+       .tp = &__tracepoint_##_call,                                    \
+       .name = #_map,                                                  \
+};                                                                     \
+                                                                       \
+static struct trace_event_call __used event_##_map = {                 \
+       .class                  = &event_class_##_template,             \
+       {                                                               \
+               .map                    = &event_map_##_map,            \
+       },                                                              \
+       .event.funcs            = &trace_event_type_funcs_##_template,  \
+       .print_fmt              = print_fmt_##_template,                \
+       .flags                  = TRACE_EVENT_FL_TRACEPOINT | 
TRACE_EVENT_FL_MAP,\
+};                                                                     \
+static struct trace_event_call __used                                  \
+__attribute__((section("_ftrace_events"))) *__event_##_map = &event_##_map
+
 #undef DEFINE_EVENT_PRINT
 #define DEFINE_EVENT_PRINT(template, call, proto, args, print)         \
                                                                        \
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 03c0a48..8b46dd8 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -327,26 +327,33 @@ int trace_event_reg(struct trace_event_call *call,
                    enum trace_reg type, void *data)
 {
        struct trace_event_file *file = data;
+       struct tracepoint *tp;
 
        WARN_ON(!(call->flags & TRACE_EVENT_FL_TRACEPOINT));
+
+       if (call->flags & TRACE_EVENT_FL_MAP)
+               tp = call->map->tp;
+       else
+               tp = call->tp;
+
        switch (type) {
        case TRACE_REG_REGISTER:
-               return tracepoint_probe_register(call->tp,
+               return tracepoint_probe_register(tp,
                                                 call->class->probe,
                                                 file);
        case TRACE_REG_UNREGISTER:
-               tracepoint_probe_unregister(call->tp,
+               tracepoint_probe_unregister(tp,
                                            call->class->probe,
                                            file);
                return 0;
 
 #ifdef CONFIG_PERF_EVENTS
        case TRACE_REG_PERF_REGISTER:
-               return tracepoint_probe_register(call->tp,
+               return tracepoint_probe_register(tp,
                                                 call->class->perf_probe,
                                                 call);
        case TRACE_REG_PERF_UNREGISTER:
-               tracepoint_probe_unregister(call->tp,
+               tracepoint_probe_unregister(tp,
                                            call->class->perf_probe,
                                            call);
                return 0;
-- 
1.9.1

Reply via email to