TRACE_EVENT: start work on type metadata declaration
authorMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Tue, 14 Dec 2010 00:46:49 +0000 (19:46 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Tue, 14 Dec 2010 00:46:49 +0000 (19:46 -0500)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
probes/Makefile
probes/lttng-events.h [new file with mode: 0644]
probes/lttng-type-list.h [new file with mode: 0644]
probes/lttng-types.c [new file with mode: 0644]
probes/lttng-types.h [new file with mode: 0644]
probes/lttng.h

index 08508a6f932f415af97c65356e8aed4d8d60f24b..cfe5e75823ee1ecf09a479f330ec8160812ba201 100644 (file)
@@ -6,7 +6,8 @@ ifneq ($(KERNELRELEASE),)
 ifneq ($(CONFIG_TRACEPOINTS),)
 
 ccflags-y += -I$(PWD)/probes
-obj-m += sched.o
+#obj-m += sched.o
+obj-m += lttng-types.o
 
 endif
 
diff --git a/probes/lttng-events.h b/probes/lttng-events.h
new file mode 100644 (file)
index 0000000..b015282
--- /dev/null
@@ -0,0 +1,808 @@
+#include <lttng.h>
+
+/*
+ * Macros mapping tp_assign() to "=", tp_memcpy() to memcpy() and tp_strcpy() to
+ * strcpy().
+ */
+#define tp_assign(dest, src)                                           \
+       lib_ring_buffer_align_ctx(config, &ctx, sizeof(src));           \
+       lib_ring_buffer_write(config, &ctx, &src, sizeof(src));
+
+#define tp_memcpy(dest, src, len)                                      \
+       lib_ring_buffer_align_ctx(config, &ctx, sizeof(*(src)));        \
+       lib_ring_buffer_write(config, &ctx, &src, len);
+
+/* TODO */
+#define tp_strcpy(dest, src)           __assign_str(dest, src)
+
+/*
+ * Stage 1 of the trace events.
+ *
+ * Create event field type metadata section.
+ */
+
+/*
+ * DECLARE_EVENT_CLASS can be used to add a generic function
+ * handlers for events. That is, if all events have the same
+ * parameters and just have distinct trace points.
+ * Each tracepoint can be defined with DEFINE_EVENT and that
+ * will map the DECLARE_EVENT_CLASS to the tracepoint.
+ *
+ * TRACE_EVENT is a one to one mapping between tracepoint and template.
+ */
+#undef TRACE_EVENT
+#define TRACE_EVENT(name, proto, args, tstruct, assign, print) \
+       DECLARE_EVENT_CLASS(name,                              \
+                            PARAMS(proto),                    \
+                            PARAMS(args),                     \
+                            PARAMS(tstruct),                  \
+                            PARAMS(assign),                   \
+                            PARAMS(print));                   \
+       DEFINE_EVENT(name, name, PARAMS(proto), PARAMS(args));
+
+/* Field types must be defined in lttng-types.h */
+
+#undef __field
+#define __field(type, item)            type    item;
+
+#undef __field_ext
+#define __field_ext(type, item, filter_type)   type    item;
+
+#undef __array
+#define __array(type, item, len)                               \
+       type { parent = array; length = len; elem_type = type; } item;
+
+/* TODO */
+
+#undef __dynamic_array
+#define __dynamic_array(type, item, len) u32 __data_loc_##item;
+
+#undef __string
+#define __string(item, src) __dynamic_array(char, item, -1)
+
+#undef TP_STRUCT__entry
+#define TP_STRUCT__entry(args...) args
+
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(name, proto, args, tstruct, assign, print) \
+       struct ftrace_raw_##name {                                      \
+               struct trace_entry      ent;                            \
+               tstruct                                                 \
+               char                    __data[0];                      \
+       };                                                              \
+                                                                       \
+       static struct ftrace_event_class event_class_##name;
+
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, name, proto, args)      \
+       static struct ftrace_event_call __used          \
+       __attribute__((__aligned__(4))) event_##name
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
+       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
+
+/* Callbacks are meaningless to ftrace. */
+#undef TRACE_EVENT_FN
+#define TRACE_EVENT_FN(name, proto, args, tstruct,                     \
+               assign, print, reg, unreg)                              \
+       TRACE_EVENT(name, PARAMS(proto), PARAMS(args),                  \
+               PARAMS(tstruct), PARAMS(assign), PARAMS(print))         \
+
+
+
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+/*
+ * Stage 2 of the trace events.
+ *
+ * Create static inline function that calculates event size.
+ */
+
+
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+/*
+ * Stage 3 of the trace events.
+ *
+ * Create the probe function : call even size calculation and write event data
+ * into the buffer.
+ */
+
+
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+
+
+
+#include <linux/ftrace_event.h>
+
+/*
+ * DECLARE_EVENT_CLASS can be used to add a generic function
+ * handlers for events. That is, if all events have the same
+ * parameters and just have distinct trace points.
+ * Each tracepoint can be defined with DEFINE_EVENT and that
+ * will map the DECLARE_EVENT_CLASS to the tracepoint.
+ *
+ * TRACE_EVENT is a one to one mapping between tracepoint and template.
+ */
+#undef TRACE_EVENT
+#define TRACE_EVENT(name, proto, args, tstruct, assign, print) \
+       DECLARE_EVENT_CLASS(name,                              \
+                            PARAMS(proto),                    \
+                            PARAMS(args),                     \
+                            PARAMS(tstruct),                  \
+                            PARAMS(assign),                   \
+                            PARAMS(print));                   \
+       DEFINE_EVENT(name, name, PARAMS(proto), PARAMS(args));
+
+
+#undef __field
+#define __field(type, item)            type    item;
+
+#undef __field_ext
+#define __field_ext(type, item, filter_type)   type    item;
+
+#undef __array
+#define __array(type, item, len)       type    item[len];
+
+#undef __dynamic_array
+#define __dynamic_array(type, item, len) u32 __data_loc_##item;
+
+#undef __string
+#define __string(item, src) __dynamic_array(char, item, -1)
+
+#undef TP_STRUCT__entry
+#define TP_STRUCT__entry(args...) args
+
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(name, proto, args, tstruct, assign, print) \
+       struct ftrace_raw_##name {                                      \
+               struct trace_entry      ent;                            \
+               tstruct                                                 \
+               char                    __data[0];                      \
+       };                                                              \
+                                                                       \
+       static struct ftrace_event_class event_class_##name;
+
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, name, proto, args)      \
+       static struct ftrace_event_call __used          \
+       __attribute__((__aligned__(4))) event_##name
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
+       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
+
+/* Callbacks are meaningless to ftrace. */
+#undef TRACE_EVENT_FN
+#define TRACE_EVENT_FN(name, proto, args, tstruct,                     \
+               assign, print, reg, unreg)                              \
+       TRACE_EVENT(name, PARAMS(proto), PARAMS(args),                  \
+               PARAMS(tstruct), PARAMS(assign), PARAMS(print))         \
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+
+/*
+ * Stage 2 of the trace events.
+ *
+ * Create static inline function that calculates event size.
+ */
+
+#undef __field
+#define __field(type, item)
+
+#undef __field_ext
+#define __field_ext(type, item, filter_type)
+
+#undef __array
+#define __array(type, item, len)
+
+#undef __dynamic_array
+#define __dynamic_array(type, item, len)       u32 item;
+
+#undef __string
+#define __string(item, src) __dynamic_array(char, item, -1)
+
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+       struct ftrace_data_offsets_##call {                             \
+               tstruct;                                                \
+       };
+
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, name, proto, args)
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
+       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+/*
+ * Stage 3 of the trace events.
+ *
+ * Create the probe function : call even size calculation and write event data
+ * into the buffer.
+ */
+
+#undef __entry
+#define __entry field
+
+#undef TP_printk
+#define TP_printk(fmt, args...) fmt "\n", args
+
+#undef __get_dynamic_array
+#define __get_dynamic_array(field)     \
+               ((void *)__entry + (__entry->__data_loc_##field & 0xffff))
+
+#undef __get_str
+#define __get_str(field) (char *)__get_dynamic_array(field)
+
+#undef __print_flags
+#define __print_flags(flag, delim, flag_array...)                      \
+       ({                                                              \
+               static const struct trace_print_flags __flags[] =       \
+                       { flag_array, { -1, NULL }};                    \
+               ftrace_print_flags_seq(p, delim, flag, __flags);        \
+       })
+
+#undef __print_symbolic
+#define __print_symbolic(value, symbol_array...)                       \
+       ({                                                              \
+               static const struct trace_print_flags symbols[] =       \
+                       { symbol_array, { -1, NULL }};                  \
+               ftrace_print_symbols_seq(p, value, symbols);            \
+       })
+
+#undef __print_hex
+#define __print_hex(buf, buf_len) ftrace_print_hex_seq(p, buf, buf_len)
+
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+static notrace enum print_line_t                                       \
+ftrace_raw_output_##call(struct trace_iterator *iter, int flags,       \
+                        struct trace_event *trace_event)               \
+{                                                                      \
+       struct ftrace_event_call *event;                                \
+       struct trace_seq *s = &iter->seq;                               \
+       struct ftrace_raw_##call *field;                                \
+       struct trace_entry *entry;                                      \
+       struct trace_seq *p = &iter->tmp_seq;                           \
+       int ret;                                                        \
+                                                                       \
+       event = container_of(trace_event, struct ftrace_event_call,     \
+                            event);                                    \
+                                                                       \
+       entry = iter->ent;                                              \
+                                                                       \
+       if (entry->type != event->event.type) {                         \
+               WARN_ON_ONCE(1);                                        \
+               return TRACE_TYPE_UNHANDLED;                            \
+       }                                                               \
+                                                                       \
+       field = (typeof(field))entry;                                   \
+                                                                       \
+       trace_seq_init(p);                                              \
+       ret = trace_seq_printf(s, "%s: ", event->name);                 \
+       if (ret)                                                        \
+               ret = trace_seq_printf(s, print);                       \
+       if (!ret)                                                       \
+               return TRACE_TYPE_PARTIAL_LINE;                         \
+                                                                       \
+       return TRACE_TYPE_HANDLED;                                      \
+}                                                                      \
+static struct trace_event_functions ftrace_event_type_funcs_##call = { \
+       .trace                  = ftrace_raw_output_##call,             \
+};
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, call, proto, args, print)         \
+static notrace enum print_line_t                                       \
+ftrace_raw_output_##call(struct trace_iterator *iter, int flags,       \
+                        struct trace_event *event)                     \
+{                                                                      \
+       struct trace_seq *s = &iter->seq;                               \
+       struct ftrace_raw_##template *field;                            \
+       struct trace_entry *entry;                                      \
+       struct trace_seq *p = &iter->tmp_seq;                           \
+       int ret;                                                        \
+                                                                       \
+       entry = iter->ent;                                              \
+                                                                       \
+       if (entry->type != event_##call.event.type) {                   \
+               WARN_ON_ONCE(1);                                        \
+               return TRACE_TYPE_UNHANDLED;                            \
+       }                                                               \
+                                                                       \
+       field = (typeof(field))entry;                                   \
+                                                                       \
+       trace_seq_init(p);                                              \
+       ret = trace_seq_printf(s, "%s: ", #call);                       \
+       if (ret)                                                        \
+               ret = trace_seq_printf(s, print);                       \
+       if (!ret)                                                       \
+               return TRACE_TYPE_PARTIAL_LINE;                         \
+                                                                       \
+       return TRACE_TYPE_HANDLED;                                      \
+}                                                                      \
+static struct trace_event_functions ftrace_event_type_funcs_##call = { \
+       .trace                  = ftrace_raw_output_##call,             \
+};
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+#undef __field_ext
+#define __field_ext(type, item, filter_type)                           \
+       ret = trace_define_field(event_call, #type, #item,              \
+                                offsetof(typeof(field), item),         \
+                                sizeof(field.item),                    \
+                                is_signed_type(type), filter_type);    \
+       if (ret)                                                        \
+               return ret;
+
+#undef __field
+#define __field(type, item)    __field_ext(type, item, FILTER_OTHER)
+
+#undef __array
+#define __array(type, item, len)                                       \
+       BUILD_BUG_ON(len > MAX_FILTER_STR_VAL);                         \
+       ret = trace_define_field(event_call, #type "[" #len "]", #item, \
+                                offsetof(typeof(field), item),         \
+                                sizeof(field.item),                    \
+                                is_signed_type(type), FILTER_OTHER);   \
+       if (ret)                                                        \
+               return ret;
+
+#undef __dynamic_array
+#define __dynamic_array(type, item, len)                                      \
+       ret = trace_define_field(event_call, "__data_loc " #type "[]", #item,  \
+                                offsetof(typeof(field), __data_loc_##item),   \
+                                sizeof(field.__data_loc_##item),              \
+                                is_signed_type(type), FILTER_OTHER);
+
+#undef __string
+#define __string(item, src) __dynamic_array(char, item, -1)
+
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, func, print)   \
+static int notrace                                                     \
+ftrace_define_fields_##call(struct ftrace_event_call *event_call)      \
+{                                                                      \
+       struct ftrace_raw_##call field;                                 \
+       int ret;                                                        \
+                                                                       \
+       tstruct;                                                        \
+                                                                       \
+       return ret;                                                     \
+}
+
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, name, proto, args)
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
+       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+/*
+ * remember the offset of each array from the beginning of the event.
+ */
+
+#undef __entry
+#define __entry entry
+
+#undef __field
+#define __field(type, item)
+
+#undef __field_ext
+#define __field_ext(type, item, filter_type)
+
+#undef __array
+#define __array(type, item, len)
+
+#undef __dynamic_array
+#define __dynamic_array(type, item, len)                               \
+       __data_offsets->item = __data_size +                            \
+                              offsetof(typeof(*entry), __data);        \
+       __data_offsets->item |= (len * sizeof(type)) << 16;             \
+       __data_size += (len) * sizeof(type);
+
+#undef __string
+#define __string(item, src) __dynamic_array(char, item, strlen(src) + 1)
+
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+static inline notrace int ftrace_get_offsets_##call(                   \
+       struct ftrace_data_offsets_##call *__data_offsets, proto)       \
+{                                                                      \
+       int __data_size = 0;                                            \
+       struct ftrace_raw_##call __maybe_unused *entry;                 \
+                                                                       \
+       tstruct;                                                        \
+                                                                       \
+       return __data_size;                                             \
+}
+
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, name, proto, args)
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
+       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+/*
+ * Stage 4 of the trace events.
+ *
+ * Override the macros in <trace/trace_events.h> to include the following:
+ *
+ * For those macros defined with TRACE_EVENT:
+ *
+ * static struct ftrace_event_call event_<call>;
+ *
+ * static void ftrace_raw_event_<call>(void *__data, proto)
+ * {
+ *     struct ftrace_event_call *event_call = __data;
+ *     struct ftrace_data_offsets_<call> __maybe_unused __data_offsets;
+ *     struct ring_buffer_event *event;
+ *     struct ftrace_raw_<call> *entry; <-- defined in stage 1
+ *     struct ring_buffer *buffer;
+ *     unsigned long irq_flags;
+ *     int __data_size;
+ *     int pc;
+ *
+ *     local_save_flags(irq_flags);
+ *     pc = preempt_count();
+ *
+ *     __data_size = ftrace_get_offsets_<call>(&__data_offsets, args);
+ *
+ *     event = trace_current_buffer_lock_reserve(&buffer,
+ *                               event_<call>->event.type,
+ *                               sizeof(*entry) + __data_size,
+ *                               irq_flags, pc);
+ *     if (!event)
+ *             return;
+ *     entry   = ring_buffer_event_data(event);
+ *
+ *     { <assign>; }  <-- Here we assign the entries by the __field and
+ *                        __array macros.
+ *
+ *     if (!filter_current_check_discard(buffer, event_call, entry, event))
+ *             trace_current_buffer_unlock_commit(buffer,
+ *                                                event, irq_flags, pc);
+ * }
+ *
+ * static struct trace_event ftrace_event_type_<call> = {
+ *     .trace                  = ftrace_raw_output_<call>, <-- stage 2
+ * };
+ *
+ * static const char print_fmt_<call>[] = <TP_printk>;
+ *
+ * static struct ftrace_event_class __used event_class_<template> = {
+ *     .system                 = "<system>",
+ *     .define_fields          = ftrace_define_fields_<call>,
+ *     .fields                 = LIST_HEAD_INIT(event_class_##call.fields),
+ *     .raw_init               = trace_event_raw_init,
+ *     .probe                  = ftrace_raw_event_##call,
+ *     .reg                    = ftrace_event_reg,
+ * };
+ *
+ * static struct ftrace_event_call __used
+ * __attribute__((__aligned__(4)))
+ * __attribute__((section("_ftrace_events"))) event_<call> = {
+ *     .name                   = "<call>",
+ *     .class                  = event_class_<template>,
+ *     .event                  = &ftrace_event_type_<call>,
+ *     .print_fmt              = print_fmt_<call>,
+ * };
+ *
+ */
+
+#ifdef CONFIG_PERF_EVENTS
+
+#define _TRACE_PERF_PROTO(call, proto)                                 \
+       static notrace void                                             \
+       perf_trace_##call(void *__data, proto);
+
+#define _TRACE_PERF_INIT(call)                                         \
+       .perf_probe             = perf_trace_##call,
+
+#else
+#define _TRACE_PERF_PROTO(call, proto)
+#define _TRACE_PERF_INIT(call)
+#endif /* CONFIG_PERF_EVENTS */
+
+#undef __entry
+#define __entry entry
+
+#undef __field
+#define __field(type, item)
+
+#undef __array
+#define __array(type, item, len)
+
+#undef __dynamic_array
+#define __dynamic_array(type, item, len)                               \
+       __entry->__data_loc_##item = __data_offsets.item;
+
+#undef __string
+#define __string(item, src) __dynamic_array(char, item, -1)            \
+
+#undef __assign_str
+#define __assign_str(dst, src)                                         \
+       strcpy(__get_str(dst), src);
+
+#undef TP_fast_assign
+#define TP_fast_assign(args...) args
+
+#undef TP_perf_assign
+#define TP_perf_assign(args...)
+
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+                                                                       \
+static notrace void                                                    \
+ftrace_raw_event_##call(void *__data, proto)                           \
+{                                                                      \
+       struct ftrace_event_call *event_call = __data;                  \
+       struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
+       struct ring_buffer_event *event;                                \
+       struct ftrace_raw_##call *entry;                                \
+       struct ring_buffer *buffer;                                     \
+       unsigned long irq_flags;                                        \
+       int __data_size;                                                \
+       int pc;                                                         \
+                                                                       \
+       local_save_flags(irq_flags);                                    \
+       pc = preempt_count();                                           \
+                                                                       \
+       __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \
+                                                                       \
+       event = trace_current_buffer_lock_reserve(&buffer,              \
+                                event_call->event.type,                \
+                                sizeof(*entry) + __data_size,          \
+                                irq_flags, pc);                        \
+       if (!event)                                                     \
+               return;                                                 \
+       entry   = ring_buffer_event_data(event);                        \
+                                                                       \
+       tstruct                                                         \
+                                                                       \
+       { assign; }                                                     \
+                                                                       \
+       if (!filter_current_check_discard(buffer, event_call, entry, event)) \
+               trace_nowake_buffer_unlock_commit(buffer,               \
+                                                 event, irq_flags, pc); \
+}
+/*
+ * The ftrace_test_probe is compiled out, it is only here as a build time check
+ * to make sure that if the tracepoint handling changes, the ftrace probe will
+ * fail to compile unless it too is updated.
+ */
+
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, call, proto, args)                      \
+static inline void ftrace_test_probe_##call(void)                      \
+{                                                                      \
+       check_trace_callback_type_##call(ftrace_raw_event_##template);  \
+}
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print)
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+#undef __entry
+#define __entry REC
+
+#undef __print_flags
+#undef __print_symbolic
+#undef __get_dynamic_array
+#undef __get_str
+
+#undef TP_printk
+#define TP_printk(fmt, args...) "\"" fmt "\", "  __stringify(args)
+
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+_TRACE_PERF_PROTO(call, PARAMS(proto));                                        \
+static const char print_fmt_##call[] = print;                          \
+static struct ftrace_event_class __used event_class_##call = {         \
+       .system                 = __stringify(TRACE_SYSTEM),            \
+       .define_fields          = ftrace_define_fields_##call,          \
+       .fields                 = LIST_HEAD_INIT(event_class_##call.fields),\
+       .raw_init               = trace_event_raw_init,                 \
+       .probe                  = ftrace_raw_event_##call,              \
+       .reg                    = ftrace_event_reg,                     \
+       _TRACE_PERF_INIT(call)                                          \
+};
+
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, call, proto, args)                      \
+                                                                       \
+static struct ftrace_event_call __used                                 \
+__attribute__((__aligned__(4)))                                                \
+__attribute__((section("_ftrace_events"))) event_##call = {            \
+       .name                   = #call,                                \
+       .class                  = &event_class_##template,              \
+       .event.funcs            = &ftrace_event_type_funcs_##template,  \
+       .print_fmt              = print_fmt_##template,                 \
+};
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, call, proto, args, print)         \
+                                                                       \
+static const char print_fmt_##call[] = print;                          \
+                                                                       \
+static struct ftrace_event_call __used                                 \
+__attribute__((__aligned__(4)))                                                \
+__attribute__((section("_ftrace_events"))) event_##call = {            \
+       .name                   = #call,                                \
+       .class                  = &event_class_##template,              \
+       .event.funcs            = &ftrace_event_type_funcs_##call,      \
+       .print_fmt              = print_fmt_##call,                     \
+}
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+/*
+ * Define the insertion callback to perf events
+ *
+ * The job is very similar to ftrace_raw_event_<call> except that we don't
+ * insert in the ring buffer but in a perf counter.
+ *
+ * static void ftrace_perf_<call>(proto)
+ * {
+ *     struct ftrace_data_offsets_<call> __maybe_unused __data_offsets;
+ *     struct ftrace_event_call *event_call = &event_<call>;
+ *     extern void perf_tp_event(int, u64, u64, void *, int);
+ *     struct ftrace_raw_##call *entry;
+ *     struct perf_trace_buf *trace_buf;
+ *     u64 __addr = 0, __count = 1;
+ *     unsigned long irq_flags;
+ *     struct trace_entry *ent;
+ *     int __entry_size;
+ *     int __data_size;
+ *     int __cpu
+ *     int pc;
+ *
+ *     pc = preempt_count();
+ *
+ *     __data_size = ftrace_get_offsets_<call>(&__data_offsets, args);
+ *
+ *     // Below we want to get the aligned size by taking into account
+ *     // the u32 field that will later store the buffer size
+ *     __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),
+ *                          sizeof(u64));
+ *     __entry_size -= sizeof(u32);
+ *
+ *     // Protect the non nmi buffer
+ *     // This also protects the rcu read side
+ *     local_irq_save(irq_flags);
+ *     __cpu = smp_processor_id();
+ *
+ *     if (in_nmi())
+ *             trace_buf = rcu_dereference_sched(perf_trace_buf_nmi);
+ *     else
+ *             trace_buf = rcu_dereference_sched(perf_trace_buf);
+ *
+ *     if (!trace_buf)
+ *             goto end;
+ *
+ *     trace_buf = per_cpu_ptr(trace_buf, __cpu);
+ *
+ *     // Avoid recursion from perf that could mess up the buffer
+ *     if (trace_buf->recursion++)
+ *             goto end_recursion;
+ *
+ *     raw_data = trace_buf->buf;
+ *
+ *     // Make recursion update visible before entering perf_tp_event
+ *     // so that we protect from perf recursions.
+ *
+ *     barrier();
+ *
+ *     //zero dead bytes from alignment to avoid stack leak to userspace:
+ *     *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL;
+ *     entry = (struct ftrace_raw_<call> *)raw_data;
+ *     ent = &entry->ent;
+ *     tracing_generic_entry_update(ent, irq_flags, pc);
+ *     ent->type = event_call->id;
+ *
+ *     <tstruct> <- do some jobs with dynamic arrays
+ *
+ *     <assign>  <- affect our values
+ *
+ *     perf_tp_event(event_call->id, __addr, __count, entry,
+ *                  __entry_size);  <- submit them to perf counter
+ *
+ * }
+ */
+
+#ifdef CONFIG_PERF_EVENTS
+
+#undef __entry
+#define __entry entry
+
+#undef __get_dynamic_array
+#define __get_dynamic_array(field)     \
+               ((void *)__entry + (__entry->__data_loc_##field & 0xffff))
+
+#undef __get_str
+#define __get_str(field) (char *)__get_dynamic_array(field)
+
+#undef __perf_addr
+#define __perf_addr(a) __addr = (a)
+
+#undef __perf_count
+#define __perf_count(c) __count = (c)
+
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
+static notrace void                                                    \
+perf_trace_##call(void *__data, proto)                                 \
+{                                                                      \
+       struct ftrace_event_call *event_call = __data;                  \
+       struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
+       struct ftrace_raw_##call *entry;                                \
+       struct pt_regs __regs;                                          \
+       u64 __addr = 0, __count = 1;                                    \
+       struct hlist_head *head;                                        \
+       int __entry_size;                                               \
+       int __data_size;                                                \
+       int rctx;                                                       \
+                                                                       \
+       perf_fetch_caller_regs(&__regs);                                \
+                                                                       \
+       __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \
+       __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),\
+                            sizeof(u64));                              \
+       __entry_size -= sizeof(u32);                                    \
+                                                                       \
+       if (WARN_ONCE(__entry_size > PERF_MAX_TRACE_SIZE,               \
+                     "profile buffer not large enough"))               \
+               return;                                                 \
+                                                                       \
+       entry = (struct ftrace_raw_##call *)perf_trace_buf_prepare(     \
+               __entry_size, event_call->event.type, &__regs, &rctx);  \
+       if (!entry)                                                     \
+               return;                                                 \
+                                                                       \
+       tstruct                                                         \
+                                                                       \
+       { assign; }                                                     \
+                                                                       \
+       head = this_cpu_ptr(event_call->perf_events);                   \
+       perf_trace_buf_submit(entry, __entry_size, rctx, __addr,        \
+               __count, &__regs, head);                                \
+}
+
+/*
+ * This part is compiled out, it is only here as a build time check
+ * to make sure that if the tracepoint handling changes, the
+ * perf probe will fail to compile unless it too is updated.
+ */
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(template, call, proto, args)                      \
+static inline void perf_test_probe_##call(void)                                \
+{                                                                      \
+       check_trace_callback_type_##call(perf_trace_##template);        \
+}
+
+
+#undef DEFINE_EVENT_PRINT
+#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
+       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+#endif /* CONFIG_PERF_EVENTS */
+
+#undef _TRACE_PROFILE_INIT
+
diff --git a/probes/lttng-type-list.h b/probes/lttng-type-list.h
new file mode 100644 (file)
index 0000000..38041b1
--- /dev/null
@@ -0,0 +1,61 @@
+/* Type list, used to create metadata */
+
+TRACE_EVENT_TYPE(long, integer)
+TRACE_EVENT_TYPE(unsigned long, integer)
+TRACE_EVENT_TYPE(int, integer)
+TRACE_EVENT_TYPE(unsigned int, integer)
+TRACE_EVENT_TYPE(short, integer)
+TRACE_EVENT_TYPE(unsigned short, integer)
+TRACE_EVENT_TYPE(char, integer)
+TRACE_EVENT_TYPE(signed char, integer)
+TRACE_EVENT_TYPE(unsigned char, integer)
+TRACE_EVENT_TYPE(bool, integer)
+TRACE_EVENT_TYPE(size_t, integer)
+TRACE_EVENT_TYPE(ssize_t, integer)
+TRACE_EVENT_TYPE(loff_t, integer)
+TRACE_EVENT_TYPE(u64, integer)
+TRACE_EVENT_TYPE(u32, integer)
+TRACE_EVENT_TYPE(u16, integer)
+TRACE_EVENT_TYPE(u8, integer)
+TRACE_EVENT_TYPE(s64, integer)
+TRACE_EVENT_TYPE(s32, integer)
+TRACE_EVENT_TYPE(s16, integer)
+TRACE_EVENT_TYPE(s8, integer)
+TRACE_EVENT_TYPE(void *, integer)
+
+/* Kernel-specific types */
+TRACE_EVENT_TYPE(pid_t, integer)
+TRACE_EVENT_TYPE(tid_t, integer)
+TRACE_EVENT_TYPE(uid_t, integer)
+TRACE_EVENT_TYPE(gid_t, integer)
+TRACE_EVENT_TYPE(ino_t, integer)
+TRACE_EVENT_TYPE(sector_t, integer)
+TRACE_EVENT_TYPE(blkcnt_t, integer)
+TRACE_EVENT_TYPE(pgoff_t, integer)
+TRACE_EVENT_TYPE(gfp_t, integer)
+TRACE_EVENT_TYPE(dev_t, integer)
+TRACE_EVENT_TYPE(umode_t, integer)
+TRACE_EVENT_TYPE(clockid_t, integer)
+TRACE_EVENT_TYPE(cputime_t, integer)
+
+/* Aliases needed by kernel instrumentation */
+TRACE_EVENT_TYPE(struct page *, integer)
+TRACE_EVENT_TYPE(unsigned, integer)
+TRACE_EVENT_TYPE(__u32, integer)
+TRACE_EVENT_TYPE(__u16, integer)
+
+/* Arrays */
+TRACE_EVENT_TYPE(task_comm, array, char, TASK_COMM_LEN)
+
+#include <linux/hrtimer.h>
+/* Enumerations */
+TRACE_EVENT_ENUM(hrtimer_mode,
+        V(HRTIMER_MODE_ABS),
+        V(HRTIMER_MODE_REL),
+        V(HRTIMER_MODE_PINNED),
+        V(HRTIMER_MODE_ABS_PINNED),
+        V(HRTIMER_MODE_REL_PINNED),
+       R(HRTIMER_MODE_UNDEFINED, 0x04, 0x100), /* Example (to remove) */
+)
+
+TRACE_EVENT_TYPE(hrtimer_mode, enum, unsigned char)
diff --git a/probes/lttng-types.c b/probes/lttng-types.c
new file mode 100644 (file)
index 0000000..e1a4137
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * probes/lttng-types.c
+ *
+ * Copyright 2010 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * LTTng types.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/seq_file.h>
+#include <linux/jbd.h> /* tid_t */
+#include <linux/debugfs.h>
+#include "lttng-types.h"
+
+struct dentry *lttng_types_dentry;
+
+#define ATYPE_ENTRY(name)      [atype_##name] = #name
+
+const char * const astract_types[NR_ABSTRACT_TYPES] = {
+       ATYPE_ENTRY(integer),
+       ATYPE_ENTRY(enum),
+       ATYPE_ENTRY(array),
+};
+
+#define STAGE_EXPORT_ENUMS
+#include "lttng-types.h"
+#include "lttng-type-list.h"
+#undef STAGE_EXPORT_ENUMS
+
+struct lttng_type lttng_types[] = {
+#define STAGE_EXPORT_TYPES
+#include "lttng-types.h"
+#include "lttng-type-list.h"
+#undef STAGE_EXPORT_TYPES
+};
+
+static void print_enum(struct seq_file *m, const struct lttng_enum *lttng_enum)
+{
+       int i;
+
+       for (i = 0; i < lttng_enum->len; i++) {
+               if (lttng_enum->entries[i].start == lttng_enum->entries[i].end)
+                       seq_printf(m,   "\t\t{ %llu, %s },\n",
+                                       lttng_enum->entries[i].start,
+                                       lttng_enum->entries[i].string);
+               else
+                       seq_printf(m,   "\t\t{ { %llu, %llu }, %s },\n",
+                                       lttng_enum->entries[i].start,
+                                       lttng_enum->entries[i].end,
+                                       lttng_enum->entries[i].string);
+       }
+}
+
+static void print_event_type(struct seq_file *m, const struct lttng_type *type)
+{
+       switch(type->atype) {
+       case atype_integer:
+               seq_printf(m,   "type %s {\n"
+                               "\tparent = %s;\n"
+                               "\tsize = %u;\n"
+                               "\tsigned = %u;\n"
+                               "\talign = %u;\n"
+                               "};\n", type->name,
+                               astract_types[type->atype],
+                               type->u.integer.size,
+                               type->u.integer.signedness,
+                               type->u.integer.alignment);
+               break;
+       case atype_enum:
+               seq_printf(m,   "type %s {\n"
+                               "\tparent = %s;\n"
+                               "\tparent.parent = %s;\n"
+                               "\tmap = {\n",
+                               type->name,
+                               astract_types[type->atype],
+                               type->u.enumeration.parent_type);
+               print_enum(m, &type->u.enumeration.def);
+               seq_printf(m,   "\t};\n"
+                               "};\n");
+               break;
+       case atype_array:
+               seq_printf(m,   "type %s {\n"
+                               "\tparent = %s;\n"
+                               "\telem_type = %s;\n"
+                               "\tlength = %u;\n"
+                               "};\n", type->name,
+                               astract_types[type->atype],
+                               type->u.array.elem_type,
+                               type->u.array.length);
+               break;
+       default:
+               seq_printf(m,   "<<< unknown abstract type %s for type %s >>>\n",
+                               astract_types[type->atype],
+                               type->name);
+       }
+}
+
+static void *lttng_seq_start(struct seq_file *m, loff_t *pos)
+{
+       struct lttng_type *type = &lttng_types[*pos];
+
+       if (type > &lttng_types[ARRAY_SIZE(lttng_types) - 1])
+               return NULL;
+       return type;
+}
+
+static void *lttng_seq_next(struct seq_file *m, void *v, loff_t *ppos)
+{
+       struct lttng_type *type = &lttng_types[++(*ppos)];
+
+       if (type > &lttng_types[ARRAY_SIZE(lttng_types) - 1])
+               return NULL;
+       return type;
+}
+
+static void lttng_seq_stop(struct seq_file *m, void *v)
+{
+}
+
+static int lttng_seq_show(struct seq_file *m, void *v)
+{
+       struct lttng_type *type = v;
+
+       print_event_type(m, type);
+       return 0;
+}
+
+static const struct seq_operations lttng_types_seq_ops = {
+       .start = lttng_seq_start,
+       .next = lttng_seq_next,
+       .stop = lttng_seq_stop,
+       .show = lttng_seq_show,
+};
+
+static int
+lttng_types_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &lttng_types_seq_ops);
+}
+
+static const struct file_operations lttng_types_fops = {
+       .open = lttng_types_open,
+        .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release_private,
+};
+
+static int lttng_types_init(void)
+{
+       int ret = 0;
+
+       lttng_types_dentry = debugfs_create_file("lttng-types", S_IWUSR,
+                                       NULL, NULL, &lttng_types_fops);
+       if (IS_ERR(lttng_types_dentry) || !lttng_types_dentry) {
+               printk(KERN_ERR "Error creating LTTng type export file\n");
+               ret = -ENOMEM;
+               goto error;
+       }
+error:
+       return ret;
+}
+
+module_init(lttng_types_init);
+
+static void lttng_types_exit(void)
+{
+       debugfs_remove(lttng_types_dentry);
+}
+
+module_exit(lttng_types_exit);
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@efficios.com>");
+MODULE_DESCRIPTION("LTTng types");
diff --git a/probes/lttng-types.h b/probes/lttng-types.h
new file mode 100644 (file)
index 0000000..5f55ef6
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Protect against multiple inclusion of structure declarations, but run the
+ * stages below each time.
+ */
+#ifndef _LTTNG_PROBES_LTTNG_TYPES_H
+#define _LTTNG_PROBES_LTTNG_TYPES_H
+
+#include <lttng.h>
+
+enum abstract_types {
+       atype_integer,
+       atype_enum,
+       atype_array,
+       NR_ABSTRACT_TYPES,
+};
+
+struct lttng_enum_entry {
+       unsigned long long start, end;  /* start and end are inclusive */
+       const char *string;
+};
+
+struct lttng_enum {
+       const struct lttng_enum_entry *entries;
+       unsigned int len;
+};
+
+struct lttng_type {
+       enum abstract_types atype;
+       const char *name;
+       union {
+               struct {
+                       unsigned int size;              /* in bits */
+                       unsigned short alignment;       /* in bits */
+                       unsigned int signedness:1;
+               } integer;
+               struct {
+                       const char *parent_type;
+                       const struct lttng_enum def;
+               } enumeration;
+               struct {
+                       const char *elem_type;
+                       unsigned int length;            /* num. elems. */
+               } array;
+       } u;
+} __attribute__((packed));
+
+#endif /* _LTTNG_PROBES_LTTNG_TYPES_H */
+
+
+/* Export enumerations */
+
+#ifdef STAGE_EXPORT_ENUMS
+
+#undef TRACE_EVENT_TYPE
+#define TRACE_EVENT_TYPE(_name, _abstract_type, args...)
+
+#undef TRACE_EVENT_ENUM
+#define TRACE_EVENT_ENUM(_name, _entries...)                           \
+       const struct lttng_enum_entry __trace_event_enum_##_name[] = {  \
+               PARAMS(_entries)                                        \
+       };
+
+/* Enumeration entry (single value) */
+#undef V
+#define V(_string)             { _string, _string, #_string}
+
+/* Enumeration entry (range) */
+#undef R
+#define R(_string, _range_start, _range_end)                           \
+       { _range_start, _range_end, #_string }
+
+#endif /* STAGE_EXPORT_ENUMS */
+
+
+/* Export named types */
+
+#ifdef STAGE_EXPORT_TYPES
+
+#undef TRACE_EVENT_TYPE___integer
+#define TRACE_EVENT_TYPE___integer(_name, _unused)             \
+               {                                               \
+                 .atype = atype_integer,                       \
+                 .name = #_name,                               \
+                 .u.integer.size = sizeof(_name) * 8,          \
+                 .u.integer.alignment = __alignof__(_name) * 8,\
+                 .u.integer.signedness = is_signed_type(_name),\
+               },
+
+#undef TRACE_EVENT_TYPE___enum
+#define TRACE_EVENT_TYPE___enum(_name, _parent_type)           \
+               {                                               \
+                 .atype = atype_enum,                          \
+                 .name = #_name,                               \
+                 .u.enumeration.parent_type = #_parent_type,   \
+                 .u.enumeration.def.entries = __trace_event_enum_##_name, \
+                 .u.enumeration.def.len = ARRAY_SIZE(__trace_event_enum_##_name), \
+               },
+
+#undef TRACE_EVENT_TYPE___array
+#define TRACE_EVENT_TYPE___array(_name, _elem_type, _length)   \
+               {                                               \
+                 .atype = atype_array,                         \
+                 .name = #_name,                               \
+                 .u.array.elem_type = #_elem_type,             \
+                 .u.array.length = _length,                    \
+               },
+
+/* Local declaration */
+#undef TRACE_EVENT_TYPE
+#define TRACE_EVENT_TYPE(_name, _abstract_type, args...)       \
+               TRACE_EVENT_TYPE___##_abstract_type(_name, args)
+
+#undef TRACE_EVENT_ENUM
+#define TRACE_EVENT_ENUM(_name, _entries...)
+
+#endif /* STAGE_EXPORT_TYPES */
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d09ecb115f172b09ca52dbacf3fba5451103e014 100644 (file)
@@ -0,0 +1,10 @@
+#ifndef _LTTNG_PROBES_LTTNG_H
+#define _LTTNG_PROBES_LTTNG_H
+
+#undef is_signed_type
+#define is_signed_type(type)           (((type)(-1)) < 0)
+
+#undef PARAMS
+#define PARAMS(args...)                args
+
+#endif /* _LTTNG_PROBES_LTTNG_H */
This page took 0.038508 seconds and 4 git commands to generate.