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. Struct metadata can contain nested structs. This extra metadata is added to the metadata file only if events use it.
Signed-off-by: Geneviève Bastien <[email protected]> --- lttng-events.c | 166 ++++++++++++++++++++++++++++++++++- lttng-events.h | 44 ++++++++++ probes/lttng-events-reset.h | 15 ++++ probes/lttng-events.h | 206 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 421 insertions(+), 10 deletions(-) diff --git a/lttng-events.c b/lttng-events.c index 4f30904..b332c29 100644 --- a/lttng-events.c +++ b/lttng-events.c @@ -61,6 +61,7 @@ void synchronize_trace(void) struct lttng_session *lttng_session_create(void) { struct lttng_session *session; + int i; mutex_lock(&sessions_mutex); session = kzalloc(sizeof(struct lttng_session), GFP_KERNEL); @@ -70,6 +71,11 @@ struct lttng_session *lttng_session_create(void) INIT_LIST_HEAD(&session->events); uuid_le_gen(&session->uuid); list_add(&session->list, &sessions); + /* Initialize dumped metadata */ + for (i = 0; i < NR_METADATA_TYPES; i++) { + session->dumped_metadata[i].nr_metadata = 0; + session->dumped_metadata[i].next = 0; + } mutex_unlock(&sessions_mutex); return session; } @@ -78,7 +84,8 @@ void lttng_session_destroy(struct lttng_session *session) { struct lttng_channel *chan, *tmpchan; struct lttng_event *event, *tmpevent; - int ret; + struct lttng_metadata_dumped_data *dumped; + int ret, i, j; mutex_lock(&sessions_mutex); ACCESS_ONCE(session->active) = 0; @@ -96,6 +103,15 @@ void lttng_session_destroy(struct lttng_session *session) list_for_each_entry_safe(chan, tmpchan, &session->chan, list) _lttng_channel_destroy(chan); list_del(&session->list); + /* Destroy dumped metadata */ + for (i = 0; i < NR_METADATA_TYPES; i++) { + dumped = session->dumped_metadata[i].next; + for (j = 0; j < session->dumped_metadata[i].nr_metadata; j++) { + dumped = dumped->next; + kfree(dumped); + } + + } mutex_unlock(&sessions_mutex); kfree(session); } @@ -654,6 +670,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 +685,141 @@ int _lttng_field_statedump(struct lttng_session *session, } static +int _lttng_is_type_metadata_dumped(struct lttng_session *session, + const struct lttng_metadata *metadata) +{ + /* Is the metadata dumped yet ? */ + struct lttng_metadata_dumped_data *dumped; + int is_dumped = 0, i; + + dumped = session->dumped_metadata[metadata->mtype].next; + switch (metadata->mtype) { + case mtype_struct: + for (i = 0; i < session->dumped_metadata[metadata->mtype].nr_metadata; i++) { + if (metadata->m.ctf_st.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_type_metadata_mark_dumped(struct lttng_session *session, + const struct lttng_metadata *metadata) +{ + /* mark this metadata as dumped */ + struct lttng_metadata_dumped_data *dumped; + + dumped = kzalloc(sizeof(struct lttng_metadata_dumped_data), + GFP_KERNEL); + if (!dumped) + return -ENOMEM; + + switch (metadata->mtype) { + case mtype_struct: + dumped->dumped_ptr.struct_desc = metadata->m.ctf_st.struct_desc; + break; + default: + WARN_ON_ONCE(1); + return -EINVAL; + } + + dumped->next = session->dumped_metadata[metadata->mtype].next; + session->dumped_metadata[metadata->mtype].next = dumped; + session->dumped_metadata[metadata->mtype].nr_metadata++; + return 0; +} + +static +int _lttng_type_metadata_statedump(struct lttng_session *session, + const struct lttng_metadata *metadata, unsigned int nr_metadata); + +static +int _lttng_type_metadata_do_statedump(struct lttng_session *session, + const struct lttng_metadata *meta) +{ + int i, ret = 0; + + switch (meta->mtype) { + case mtype_struct: + ret = _lttng_type_metadata_statedump(session, + meta->m.ctf_st.type_metadata, + meta->m.ctf_st.nr_metadata); + if (ret) + return ret; + + ret = lttng_metadata_printf(session, + "struct %s_%s {\n", + meta->m.ctf_st.struct_desc->provider, + meta->m.ctf_st.struct_desc->name + ); + if (ret) + return ret; + + /* Print fields */ + for (i = 0; i < meta->m.ctf_st.struct_desc->nr_fields; i++) { + const struct lttng_event_field *field; + + field = &meta->m.ctf_st.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_type_metadata_mark_dumped(session, meta); + return ret; +} + +static +int _lttng_type_metadata_statedump(struct lttng_session *session, + const struct lttng_metadata *metadata, unsigned int nr_metadata) +{ + int i, ret = 0; + + for (i = 0; i < nr_metadata; i++) { + const struct lttng_metadata *meta = &metadata[i]; + + if (_lttng_is_type_metadata_dumped(session, meta)) + continue; + + ret = _lttng_type_metadata_do_statedump(session, meta); + if (ret) + return ret; + } + return ret; +} + +static +int _lttng_event_type_metadata_statedump(struct lttng_session *session, + struct lttng_event *event) +{ + int ret = 0; + const struct lttng_event_desc *desc = event->desc; + + ret = _lttng_type_metadata_statedump(session, + desc->type_metadata, desc->nr_metadata); + return ret; +} + +static int _lttng_context_metadata_statedump(struct lttng_session *session, struct lttng_ctx *ctx) { @@ -710,6 +868,11 @@ int _lttng_event_metadata_statedump(struct lttng_session *session, if (chan == session->metadata) return 0; + /* Dump the type metadata for this event */ + ret = _lttng_event_type_metadata_statedump(session, event); + if (ret) + goto end; + ret = lttng_metadata_printf(session, "event {\n" " name = %s;\n" @@ -746,7 +909,6 @@ int _lttng_event_metadata_statedump(struct lttng_session *session, ret = _lttng_fields_metadata_statedump(session, event); if (ret) goto end; - /* * LTTng space reservation can only reserve multiples of the * byte size. diff --git a/lttng-events.h b/lttng-events.h index 37a5db7..67c49f1 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,45 @@ struct lttng_ctx { unsigned int allocated_fields; }; +struct lttng_struct_desc { + const char *provider, *name; + const struct lttng_event_field *fields; /* fields */ + unsigned int nr_fields; + struct module *owner; +}; + +struct lttng_metadata { + enum metadata_types mtype; + union { + struct { + const struct lttng_struct_desc *struct_desc; + const struct lttng_metadata *type_metadata; + unsigned int nr_metadata; + } ctf_st; + } m; +}; + +struct lttng_metadata_dumped_data { + union { + const struct lttng_struct_desc *struct_desc; + } dumped_ptr; + struct lttng_metadata_dumped_data *next; +}; + +struct lttng_metadata_dumped { + unsigned int nr_metadata; + struct lttng_metadata_dumped_data *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 */ + /* type metadata added by events */ + const struct lttng_metadata *type_metadata; unsigned int nr_fields; + unsigned int nr_metadata; struct module *owner; }; @@ -277,6 +320,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 dumped_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..dd60ca6 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(provider, name, 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, _args, _fields) diff --git a/probes/lttng-events.h b/probes/lttng-events.h index 8a3a886..93f4abc 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.provider = #_provider, \ + .u.ctf_struct.name = #_type, \ + }, \ + }, + #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, _args, _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,74 @@ static void __event_probe__##_name(void *__data); #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) /* + * Stage 3.2 of the trace events. + * + * Create type metadata description + */ + +#include "lttng-events-reset.h" /* Reset all macros within TRACE_EVENT */ + +#undef TRACEPOINT_STRUCT +#define TRACEPOINT_STRUCT(_provider, _name, _proto, _args, _fields) \ +static struct lttng_struct_desc __struct_desc___##_provider##_##_name = {\ + .fields = __struct_fields___##_provider##_##_name, \ + .nr_fields = ARRAY_SIZE(__struct_fields___##_provider##_##_name),\ + .provider = #_provider, \ + .name = #_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 or other struct + */ + +/* 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.ctf_st.struct_desc = &__struct_desc___##_provider##_##_type,\ + .m.ctf_st.type_metadata = __type_metadata_for__##_provider##_##_type,\ + .m.ctf_st.nr_metadata = ARRAY_SIZE(__type_metadata_for__##_provider##_##_type),\ + }, + + +#undef TP_STRUCT__entry +#define TP_STRUCT__entry(args...) args /* Only one used in this phase */ + +#undef TP_FIELDS +#define TP_FIELDS(args...) args + +#undef TRACEPOINT_STRUCT +#define TRACEPOINT_STRUCT(_provider, _name, _proto, _args, _fields) \ +static const struct lttng_metadata __type_metadata_for__##_provider##_##_name[] = {\ + _fields \ +}; + + + +#undef DECLARE_EVENT_CLASS_NOARGS +#define DECLARE_EVENT_CLASS_NOARGS(_name, _tstruct, _assign, _print) \ +static const struct lttng_metadata __type_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 +408,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, \ + .type_metadata = __type_metadata_for__##_template, \ .name = #_map, \ .probe_callback = (void *) TP_PROBE_CB(_template), \ .nr_fields = ARRAY_SIZE(__event_fields___##_template), \ + .nr_metadata = ARRAY_SIZE(__type_metadata_for__##_template), \ .owner = THIS_MODULE, \ }; @@ -379,9 +471,12 @@ static __used struct lttng_probe_desc TP_ID(__probe_desc___, TRACE_SYSTEM) = { #undef TP_ID /* - * Stage 6 of the trace events. + * Stage 6.0 of the trace events. * * Create static inline function that calculates event size. + * + * First stage creates function to calculate sizes of sub-metadata + * (with no effect on the dynamic length values) */ #include "lttng-events-reset.h" /* Reset all macros within TRACE_EVENT */ @@ -403,6 +498,57 @@ static __used struct lttng_probe_desc TP_ID(__probe_desc___, TRACE_SYSTEM) = { __event_len += lib_ring_buffer_align(__event_len, lttng_alignof(u32)); \ __event_len += sizeof(u32); \ __event_len += lib_ring_buffer_align(__event_len, lttng_alignof(_type)); \ + __event_len += sizeof(_type) * (_length); \ + +#undef __string +#define __string(_item, _src) \ + __event_len += strlen(_src) + 1; + +/* + * strlen_user includes \0. If returns 0, it faulted, so we set size to + * 1 (\0 only). + */ +#undef __string_from_user +#define __string_from_user(_item, _src) \ + __event_len += max_t(size_t, lttng_strlen_user_inatomic(_src), 1); + +#undef __struct +#define __struct(_provider, _type, _item, _params) \ + __event_len += __struct_get_size__##_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, _args, _fields) \ +static inline size_t __struct_get_size__##_provider##_##_name(_proto) \ + { \ + size_t __event_len = 0; \ + \ + _fields \ + return __event_len; \ +} + +#include TRACE_INCLUDE(TRACE_INCLUDE_FILE) + +/* + * Stage 6.1 of the trace events. + * + * Create static inline function that calculates event size, this time adding + * the size to the dynamic_len array + */ + +#undef __dynamic_array_enc_ext +#define __dynamic_array_enc_ext(_type, _item, _length, _order, _base, _encoding)\ + __event_len += lib_ring_buffer_align(__event_len, lttng_alignof(u32)); \ + __event_len += sizeof(u32); \ + __event_len += lib_ring_buffer_align(__event_len, lttng_alignof(_type));\ __dynamic_len[__dynamic_len_idx] = (_length); \ __event_len += sizeof(_type) * __dynamic_len[__dynamic_len_idx]; \ __dynamic_len_idx++; @@ -420,11 +566,13 @@ 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 TP_PROTO -#define TP_PROTO(args...) args +#undef __struct +#define __struct(_provider, _type, _item, _params) \ + __event_len += __dynamic_len[__dynamic_len_idx++] = \ + __struct_get_size__##_provider##_##_type(_params); -#undef TP_STRUCT__entry -#define TP_STRUCT__entry(args...) args +#undef TRACEPOINT_STRUCT +#define TRACEPOINT_STRUCT(_provider, _name, _proto, _args, _fields) #undef DECLARE_EVENT_CLASS #define DECLARE_EVENT_CLASS(_name, _proto, _args, _tstruct, _assign, _print) \ @@ -470,12 +618,36 @@ 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, \ + __instruct_get_align__##_provider##_##_type(_params)); + #undef TP_PROTO #define TP_PROTO(args...) args +#undef TP_ARGS +#define TP_ARGS(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, _args, _fields) \ +static inline size_t __struct_get_align__##_provider##_##_name(_proto) \ +{ \ + size_t __event_align = 1; \ + _fields \ + return __event_align; \ +} \ +static inline size_t __instruct_get_align__##_provider##_##_name(_proto)\ +{ \ + return __struct_get_align__##_provider##_##_name(_args); \ +} + #undef DECLARE_EVENT_CLASS #define DECLARE_EVENT_CLASS(_name, _proto, _args, _tstruct, _assign, _print) \ static inline size_t __event_get_align__##_name(_proto) \ @@ -487,7 +659,6 @@ static inline size_t __event_get_align__##_name(_proto) \ #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) - /* * Stage 8 of the trace events. * @@ -517,6 +688,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 @@ -528,7 +702,6 @@ struct __event_typemap__##_name { \ #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) - /* * Stage 9 of the trace events. * @@ -568,6 +741,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 +802,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, provider, name, dest, src) \ +__assign_##dest: \ + lib_ring_buffer_align_ctx(&__ctx, __struct_get_align__##provider##_##name(src));\ + __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(provider, name, dest, src) \ + tp_memcpy_struct_gen(event_write, provider, name, 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 _______________________________________________ lttng-dev mailing list [email protected] http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
