[lttng-dev] [RFC-patch] Add support of struct metadata in tracepoints

Geneviève Bastien gbastien+lttng at versatic.net
Thu Apr 11 16:07:31 EDT 2013


Introduce the new macro TRACEPOINT_STRUCT to define ctf struct metadata
that can be used by tracepoints using _struct as entry and tp_memcpy_struct
to copy a struct field.
This extra metadata is added to the metadata file only if events use it.

Signed-off-by: Geneviève Bastien <gbastien+lttng at versatic.net>
---
 lttng-events.c              | 134 +++++++++++++++++++++++++++++++++++++++++-
 lttng-events.h              |  35 +++++++++++
 probes/lttng-events-reset.h |  15 +++++
 probes/lttng-events.h       | 138 +++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 320 insertions(+), 2 deletions(-)

diff --git a/lttng-events.c b/lttng-events.c
index 4f30904..431a17c 100644
--- a/lttng-events.c
+++ b/lttng-events.c
@@ -654,6 +654,13 @@ int _lttng_field_statedump(struct lttng_session *session,
 				" { encoding = ASCII; }" : "",
 			field->name);
 		break;
+	case atype_struct:
+		ret = lttng_metadata_printf(session,
+			"		struct %s%s _%s;\n",
+			field->type.u.ctf_struct.provider,
+			field->type.u.ctf_struct.name,
+			field->name);
+		break;
 	default:
 		WARN_ON_ONCE(1);
 		return -EINVAL;
@@ -662,6 +669,122 @@ int _lttng_field_statedump(struct lttng_session *session,
 }
 
 static
+int _lttng_is_extra_metadata_dumped(struct lttng_session *session,
+		const struct lttng_metadata *metadata) {
+	/* Is the metadata dumped yet ? */
+	struct lttng_metadata_dumped *dumped;
+	int is_dumped = 0;
+
+	dumped = session->extra_metadata[metadata->mtype];
+	switch (metadata->mtype) {
+	case mtype_struct:
+		while (dumped) {
+			if (metadata->m.struct_desc ==
+					dumped->dumped_ptr.struct_desc) {
+				is_dumped = 1;
+				break;
+			}
+			dumped = dumped->next;
+		}
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		return -EINVAL;
+	}
+	return is_dumped;
+}
+
+static int _lttng_extra_metadata_mark_dumped(struct lttng_session *session,
+		const struct lttng_metadata *metadata) {
+	/* mark this metadata as dumped */
+	struct lttng_metadata_dumped *dumped, *just_dumped;
+
+	just_dumped = kzalloc(sizeof(struct lttng_metadata_dumped),
+			GFP_KERNEL);
+	if (!just_dumped)
+		return -ENOMEM;
+
+	dumped = session->extra_metadata[metadata->mtype];
+
+	switch (metadata->mtype) {
+	case mtype_struct:
+		just_dumped->dumped_ptr.struct_desc = metadata->m.struct_desc;
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		return -EINVAL;
+	}
+
+	just_dumped->next = session->extra_metadata[mtype_struct];
+	session->extra_metadata[mtype_struct] = just_dumped;
+	return 0;
+}
+
+static
+int _lttng_event_extra_metadata_do_statedump(struct lttng_session *session,
+		const struct lttng_metadata *meta)
+{
+	int i, ret = 0;
+
+	switch (meta->mtype) {
+	case mtype_struct:
+
+		ret = lttng_metadata_printf(session,
+			"struct %s%s {\n",
+			meta->m.struct_desc->provider, meta->m.struct_desc->name
+		);
+		if (ret)
+			return ret;
+
+		/* Print fields */
+		for (i = 0; i < meta->m.struct_desc->nr_fields; i++) {
+			const struct lttng_event_field *field;
+			field = &meta->m.struct_desc->fields[i];
+
+			ret = _lttng_field_statedump(session, field);
+			if (ret)
+				return ret;
+		}
+
+		ret = lttng_metadata_printf(session,
+				"};\n\n");
+		if (ret)
+			return ret;
+
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		return -EINVAL;
+	}
+	if (ret)
+		return ret;
+
+	ret = _lttng_extra_metadata_mark_dumped(session, meta);
+	return ret;
+}
+
+static
+int _lttng_event_extra_metadata_statedump(struct lttng_session *session,
+			 struct lttng_event *event)
+{
+	const struct lttng_event_desc *desc = event->desc;
+	int i, ret = 0;
+
+	for (i = 0; i < desc->nr_metadata; i++) {
+		const struct lttng_metadata *meta = &desc->extra_metadata[i];
+
+		if (!_lttng_is_extra_metadata_dumped(session, meta)) {
+			ret = _lttng_event_extra_metadata_do_statedump(session,
+					meta);
+			if (ret)
+				return ret;
+		}
+	}
+	return ret;
+
+}
+
+static
 int _lttng_context_metadata_statedump(struct lttng_session *session,
 				    struct lttng_ctx *ctx)
 {
@@ -710,6 +833,11 @@ int _lttng_event_metadata_statedump(struct lttng_session *session,
 	if (chan == session->metadata)
 		return 0;
 
+	/* Dump the extra metadata for this event */
+	ret = _lttng_event_extra_metadata_statedump(session, event);
+	if (ret)
+		goto end;
+
 	ret = lttng_metadata_printf(session,
 		"event {\n"
 		"	name = %s;\n"
@@ -905,7 +1033,7 @@ int _lttng_session_metadata_statedump(struct lttng_session *session)
 	unsigned char uuid_s[37], clock_uuid_s[BOOT_ID_LEN];
 	struct lttng_channel *chan;
 	struct lttng_event *event;
-	int ret = 0;
+	int ret = 0, i;
 
 	if (!ACCESS_ONCE(session->active))
 		return 0;
@@ -1042,6 +1170,10 @@ int _lttng_session_metadata_statedump(struct lttng_session *session)
 	if (ret)
 		goto end;
 
+	/* Initialized undumped metadata */
+	for (i = 0; i < NR_METADATA_TYPES; i++)
+		session->extra_metadata[i] = 0;
+
 skip_session:
 	list_for_each_entry(chan, &session->chan, list) {
 		ret = _lttng_channel_metadata_statedump(session, chan);
diff --git a/lttng-events.h b/lttng-events.h
index 37a5db7..2cab5f3 100644
--- a/lttng-events.h
+++ b/lttng-events.h
@@ -47,9 +47,16 @@ enum abstract_types {
 	atype_array,
 	atype_sequence,
 	atype_string,
+	atype_struct,
 	NR_ABSTRACT_TYPES,
 };
 
+/* Metadata types */
+enum metadata_types {
+	mtype_struct,
+	NR_METADATA_TYPES,
+};
+
 /* Update the string_encodings name table in lttng-types.c along with this enum */
 enum lttng_string_encodings {
 	lttng_encode_none = 0,
@@ -115,6 +122,9 @@ struct lttng_type {
 			struct lttng_basic_type length_type;
 			struct lttng_basic_type elem_type;
 		} sequence;
+		struct {
+			const char *name, *provider;
+		} ctf_struct;
 	} u;
 };
 
@@ -161,12 +171,36 @@ struct lttng_ctx {
 	unsigned int allocated_fields;
 };
 
+struct lttng_struct_desc {
+	const char *name, *provider;
+	const struct lttng_event_field *fields; /* fields */
+	unsigned int nr_fields;
+	struct module *owner;
+};
+
+struct lttng_metadata {
+	enum metadata_types mtype;
+	union {
+		struct lttng_struct_desc *struct_desc;
+	} m;
+};
+
+struct lttng_metadata_dumped {
+	union {
+		struct lttng_struct_desc *struct_desc;
+	} dumped_ptr;
+	struct lttng_metadata_dumped *next;
+};
+
 struct lttng_event_desc {
 	const char *name;
 	void *probe_callback;
 	const struct lttng_event_ctx *ctx;	/* context */
 	const struct lttng_event_field *fields;	/* event payload */
+	/* Extra metadata added by events */
+	const struct lttng_metadata *extra_metadata;
 	unsigned int nr_fields;
+	unsigned int nr_metadata;
 	struct module *owner;
 };
 
@@ -277,6 +311,7 @@ struct lttng_session {
 	struct list_head list;		/* Session list */
 	unsigned int free_chan_id;	/* Next chan ID to allocate */
 	uuid_le uuid;			/* Trace session unique ID */
+	struct lttng_metadata_dumped *extra_metadata[NR_METADATA_TYPES];
 	unsigned int metadata_dumped:1;
 };
 
diff --git a/probes/lttng-events-reset.h b/probes/lttng-events-reset.h
index 44e8ba5..bf8bbf1 100644
--- a/probes/lttng-events-reset.h
+++ b/probes/lttng-events-reset.h
@@ -20,6 +20,9 @@
 
 /* Reset macros used within TRACE_EVENT to "nothing" */
 
+#undef TRACE_METADATA
+#define TRACE_METADATA 1
+
 #undef __field_full
 #define __field_full(_type, _item, _order, _base)
 
@@ -35,6 +38,9 @@
 #undef __string
 #define __string(_item, _src)
 
+#undef __struct
+#define __struct(_provider, _type, _item, _params)
+
 #undef tp_assign
 #define tp_assign(dest, src)
 
@@ -47,6 +53,9 @@
 #undef tp_strcpy
 #define tp_strcpy(dest, src)
 
+#undef tp_memcpy_struct
+#define tp_memcpy_struct(dest, src)
+
 #undef __get_str
 #define __get_str(field)
 
@@ -65,6 +74,9 @@
 #undef TP_STRUCT__entry
 #define TP_STRUCT__entry(args...)
 
+#undef TP_FIELDS
+#define TP_FIELDS(args...)
+
 #undef TP_fast_assign
 #define TP_fast_assign(args...)
 
@@ -94,3 +106,6 @@
 
 #undef TRACE_EVENT_FLAGS
 #define TRACE_EVENT_FLAGS(name, value)
+
+#undef TRACEPOINT_STRUCT
+#define TRACEPOINT_STRUCT(_provider, _name, _proto, _fields)
diff --git a/probes/lttng-events.h b/probes/lttng-events.h
index 8a3a886..8465095 100644
--- a/probes/lttng-events.h
+++ b/probes/lttng-events.h
@@ -263,9 +263,31 @@ void trace_##_name(void *__data);
 #define __string_from_user(_item, _src)				\
 	__string(_item, _src)
 
+#undef __struct
+#define __struct(_provider, _type, _item, _params)		\
+	{							\
+	  .name = #_item,					\
+	  .type =						\
+	  {							\
+		.atype = atype_struct,				\
+		.u.ctf_struct.name = #_type,			\
+		.u.ctf_struct.provider = #_provider,		\
+	  },							\
+	},
+
 #undef TP_STRUCT__entry
 #define TP_STRUCT__entry(args...) args	/* Only one used in this phase */
 
+#undef TP_FIELDS
+#define TP_FIELDS(args...) args	/* Only one used in this phase */
+
+#undef TRACEPOINT_STRUCT
+#define TRACEPOINT_STRUCT(_provider, _name, _proto, _fields)	\
+	static const struct lttng_event_field			\
+		__struct_fields___##_provider##_name[] = {	\
+			_fields					\
+	};
+
 #undef DECLARE_EVENT_CLASS_NOARGS
 #define DECLARE_EVENT_CLASS_NOARGS(_name, _tstruct, _assign, _print) \
 	static const struct lttng_event_field __event_fields___##_name[] = { \
@@ -301,6 +323,60 @@ static void __event_probe__##_name(void *__data);
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 
 /*
+ * Stage 3.2 of the trace events.
+ *
+ * Create extra metadata description
+ */
+
+#include "lttng-events-reset.h"	/* Reset all macros within TRACE_EVENT */
+
+#undef TRACEPOINT_STRUCT
+#define TRACEPOINT_STRUCT(_provider, _name, _proto, _fields)	\
+static struct lttng_struct_desc __struct_desc___##_provider##_name = {	\
+		.fields = __struct_fields___##_provider##_name,		\
+		.name = #_name,		\
+		.provider = #_provider,	\
+		.nr_fields = ARRAY_SIZE(__struct_fields___##_provider##_name),\
+		.owner = THIS_MODULE,	\
+	};
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+/*
+ * Stage 3.3 of the trace events.
+ *
+ * Associate metadata description to event or event template
+ */
+
+/* Named field types must be defined in lttng-types.h */
+
+#include "lttng-events-reset.h"	/* Reset all macros within TRACE_EVENT */
+
+#undef __struct
+#define __struct(_provider, _type, _item, _params)		\
+	{							\
+	  .mtype = mtype_struct,					\
+	  .m.struct_desc = &__struct_desc___##_provider##_type,	\
+	},
+
+#undef TP_STRUCT__entry
+#define TP_STRUCT__entry(args...) args	/* Only one used in this phase */
+
+#undef DECLARE_EVENT_CLASS_NOARGS
+#define DECLARE_EVENT_CLASS_NOARGS(_name, _tstruct, _assign, _print) \
+static const struct lttng_metadata __metadata_for__##_name[] = {	\
+	_tstruct		\
+};
+
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(_name, _proto, _args, _tstruct, _assign, _print) \
+	DECLARE_EVENT_CLASS_NOARGS(_name, PARAMS(_tstruct), PARAMS(_assign), \
+			PARAMS(_print))
+
+#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
+
+
+/*
  * Stage 3.9 of the trace events.
  *
  * Create event descriptions.
@@ -318,9 +394,11 @@ static void __event_probe__##_name(void *__data);
 #define DEFINE_EVENT_MAP_NOARGS(_template, _name, _map)			\
 static const struct lttng_event_desc __event_desc___##_map = {		\
 	.fields = __event_fields___##_template,		     		\
+	.extra_metadata = __metadata_for__##_template,			\
 	.name = #_map,					     		\
 	.probe_callback = (void *) TP_PROBE_CB(_template),   		\
 	.nr_fields = ARRAY_SIZE(__event_fields___##_template),		\
+	.nr_metadata = ARRAY_SIZE(__metadata_for__##_template),		\
 	.owner = THIS_MODULE,				     		\
 };
 
@@ -420,12 +498,33 @@ static __used struct lttng_probe_desc TP_ID(__probe_desc___, TRACE_SYSTEM) = {
 	__event_len += __dynamic_len[__dynamic_len_idx++] =		       \
 		max_t(size_t, lttng_strlen_user_inatomic(_src), 1);
 
+#undef __struct
+#define __struct(_provider, _type, _item, _params)			\
+	__event_len += __dynamic_len[__dynamic_len_idx++] =		\
+		__struct_get_size__##_provider##_type(__dynamic_len, _params);
+
 #undef TP_PROTO
 #define TP_PROTO(args...) args
 
 #undef TP_STRUCT__entry
 #define TP_STRUCT__entry(args...) args
 
+#undef TP_FIELDS
+#define TP_FIELDS(args...) args
+
+#undef TRACEPOINT_STRUCT
+#define TRACEPOINT_STRUCT(_provider, _name, _proto, _fields)	\
+static inline size_t __struct_get_size__##_provider##_name(size_t *__dynamic_len, _proto)\
+	{								\
+	size_t __event_len = 0;						\
+	unsigned int __dynamic_len_idx = 0;				\
+									\
+	if (0)								\
+		(void) __dynamic_len_idx;	/* don't warn if unused */\
+	_fields								\
+	return __event_len;						\
+}
+
 #undef DECLARE_EVENT_CLASS
 #define DECLARE_EVENT_CLASS(_name, _proto, _args, _tstruct, _assign, _print)  \
 static inline size_t __event_get_size__##_name(size_t *__dynamic_len, _proto) \
@@ -470,12 +569,29 @@ static inline size_t __event_get_size__##_name(size_t *__dynamic_len, _proto) \
 #undef __string_from_user
 #define __string_from_user(_item, _src)
 
+#undef __struct
+#define __struct(_provider, _type, _item, _params)			\
+	__event_align = max_t(size_t, __event_align,			\
+		__struct_get_align__##_provider##_type(_params));
+
 #undef TP_PROTO
 #define TP_PROTO(args...) args
 
 #undef TP_STRUCT__entry
 #define TP_STRUCT__entry(args...) args
 
+#undef TP_FIELDS
+#define TP_FIELDS(args...) args
+
+#undef TRACEPOINT_STRUCT
+#define TRACEPOINT_STRUCT(_provider, _name, _proto, _fields)	\
+static inline size_t __struct_get_align__##_provider##_name(_proto)	\
+{									\
+	size_t __event_align = 1;					\
+	_fields								\
+	return __event_align;						\
+}
+
 #undef DECLARE_EVENT_CLASS
 #define DECLARE_EVENT_CLASS(_name, _proto, _args, _tstruct, _assign, _print)  \
 static inline size_t __event_get_align__##_name(_proto)			      \
@@ -517,6 +633,9 @@ static inline size_t __event_get_align__##_name(_proto)			      \
 #define __string_from_user(_item, _src)		\
 	__string(_item, _src)
 
+#undef __struct
+#define __struct(_provider, _type, _item, _params)		char _item;
+
 #undef TP_STRUCT__entry
 #define TP_STRUCT__entry(args...) args
 
@@ -568,6 +687,11 @@ __end_field_##_item:
 #define __string_from_user(_item, _src)					\
 	__string(_item, _src)
 
+#undef __struct
+#define __struct(_provider, _type, _item, _params)			\
+	goto __assign_##_item;						\
+__end_field_##_item:
+
 /*
  * Macros mapping tp_assign() to "=", tp_memcpy() to memcpy() and tp_strcpy() to
  * strcpy().
@@ -624,12 +748,24 @@ __assign_##dest##_2:							\
 #define tp_memcpy_dyn_from_user(dest, src)				\
 	tp_memcpy_dyn_gen(event_write_from_user, dest, src)
 
+#undef tp_memcpy_struct_gen
+#define tp_memcpy_struct_gen(write_ops, dest, src)	\
+__assign_##dest:							\
+	lib_ring_buffer_align_ctx(&__ctx, lttng_alignof(__typemap.dest));\
+	__chan->ops->write_ops(&__ctx, src,				\
+		sizeof(__typemap.dest) * __get_dynamic_array_len(dest));\
+	goto __end_field_##dest;
+
+#undef tp_memcpy_struct
+#define tp_memcpy_struct(dest, src)	\
+		tp_memcpy_struct_gen(event_write, dest, src)
+
 /*
  * The string length including the final \0.
  */
 #undef tp_copy_string_from_user
 #define tp_copy_string_from_user(dest, src)				\
-	__assign_##dest:						\
+__assign_##dest:							\
 	{								\
 		size_t __ustrlen;					\
 									\
-- 
1.8.2.1




More information about the lttng-dev mailing list