From c25f8e53dc25a23d21d3e54a171b4c2dee0bd7eb Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Mon, 12 Aug 2019 20:16:09 -0400 Subject: [PATCH] sink.ctf.fs: write option field classes and fields This patch makes a `sink.ctf.fs` component handle option field classes and fields. Because CTF 1.8 has no option field class type, it makes a best effort and translates it to a variant field class with two options: * An empty structure field class (option field contains nothing). * The optional field class itself. The tag field class is always generated before the variant field class and is an 8-bit unsigned enumeration field class. For example, a `sink.ctf.fs` component would translate an optional string field class to: /* * This enumeration field class and the following variant field * class were a trace IR option field class. */ enum : integer { size = 8; align = 8; } { none = 0, content = 1, } __module_name_tag; variant <__module_name_tag> { struct { } none; string { encoding = UTF8; } content; } module_name; When a `src.ctf.fs` component reads a trace generated by `sink.ctf.fs` where the input trace IR contained option field classes, the corresponding variant field classes will stay variant field classes; the source component has no way to determine if the metadata describes an option field class or a genuine variant field class. However, the CTF 1.8 to CTF 1.8 scenario will always be unambiguous because a `src.ctf.fs` component never creates option field classes. Signed-off-by: Philippe Proulx Change-Id: Ib83e011f73795d70cd8545f55ea87e0bf10b68bc Reviewed-on: https://review.lttng.org/c/babeltrace/+/1901 Tested-by: jenkins Reviewed-by: Francis Deslauriers --- src/plugins/ctf/fs-sink/fs-sink-ctf-meta.h | 42 +++++++ src/plugins/ctf/fs-sink/fs-sink-stream.c | 37 ++++++ .../ctf/fs-sink/translate-ctf-ir-to-tsdl.c | 60 ++++++++++ .../fs-sink/translate-trace-ir-to-ctf-ir.c | 105 ++++++++++++++++++ 4 files changed, 244 insertions(+) diff --git a/src/plugins/ctf/fs-sink/fs-sink-ctf-meta.h b/src/plugins/ctf/fs-sink/fs-sink-ctf-meta.h index a96cbad8..9fcd3636 100644 --- a/src/plugins/ctf/fs-sink/fs-sink-ctf-meta.h +++ b/src/plugins/ctf/fs-sink/fs-sink-ctf-meta.h @@ -33,6 +33,7 @@ enum fs_sink_ctf_field_class_type { FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT, FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY, FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE, + FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION, FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT, }; @@ -84,6 +85,12 @@ struct fs_sink_ctf_field_class_struct { GArray *members; }; +struct fs_sink_ctf_field_class_option { + struct fs_sink_ctf_field_class base; + struct fs_sink_ctf_field_class *content_fc; + GString *tag_ref; +}; + struct fs_sink_ctf_field_class_variant { struct fs_sink_ctf_field_class base; GString *tag_ref; @@ -318,6 +325,22 @@ struct fs_sink_ctf_field_class_struct *fs_sink_ctf_field_class_struct_create_emp return fc; } +static inline +struct fs_sink_ctf_field_class_option *fs_sink_ctf_field_class_option_create_empty( + const bt_field_class *ir_fc, uint64_t index_in_parent) +{ + struct fs_sink_ctf_field_class_option *fc = + g_new0(struct fs_sink_ctf_field_class_option, 1); + + BT_ASSERT(fc); + _fs_sink_ctf_field_class_init((void *) fc, + FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION, ir_fc, + 1, index_in_parent); + fc->tag_ref = g_string_new(NULL); + BT_ASSERT(fc->tag_ref); + return fc; +} + static inline struct fs_sink_ctf_field_class_variant *fs_sink_ctf_field_class_variant_create_empty( const bt_field_class *ir_fc, uint64_t index_in_parent) @@ -485,6 +508,22 @@ void _fs_sink_ctf_field_class_sequence_destroy( g_free(fc); } +static inline +void _fs_sink_ctf_field_class_option_destroy( + struct fs_sink_ctf_field_class_option *fc) +{ + BT_ASSERT(fc); + _fs_sink_ctf_field_class_fini((void *) fc); + fs_sink_ctf_field_class_destroy(fc->content_fc); + + if (fc->tag_ref) { + g_string_free(fc->tag_ref, TRUE); + fc->tag_ref = NULL; + } + + g_free(fc); +} + static inline void _fs_sink_ctf_field_class_variant_destroy( struct fs_sink_ctf_field_class_variant *fc) @@ -544,6 +583,9 @@ void fs_sink_ctf_field_class_destroy(struct fs_sink_ctf_field_class *fc) case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE: _fs_sink_ctf_field_class_sequence_destroy((void *) fc); break; + case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION: + _fs_sink_ctf_field_class_option_destroy((void *) fc); + break; case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT: _fs_sink_ctf_field_class_variant_destroy((void *) fc); break; diff --git a/src/plugins/ctf/fs-sink/fs-sink-stream.c b/src/plugins/ctf/fs-sink/fs-sink-stream.c index 28f70e4f..ed516b1c 100644 --- a/src/plugins/ctf/fs-sink/fs-sink-stream.c +++ b/src/plugins/ctf/fs-sink/fs-sink-stream.c @@ -335,6 +335,40 @@ end: return ret; } +static inline +int write_option_field(struct fs_sink_stream *stream, + struct fs_sink_ctf_field_class_option *fc, + const bt_field *field) +{ + int ret; + const bt_field *content_field = + bt_field_option_borrow_field_const(field); + + ret = bt_ctfser_write_unsigned_int(&stream->ctfser, + content_field ? 1 : 0, 8, 8, BYTE_ORDER); + if (G_UNLIKELY(ret)) { + goto end; + } + + /* + * CTF 1.8 has no option field class type, so this component + * translates the option field class to a variant field class + * where the options are: + * + * * An empty structure field class (field occupies 0 bits). + * * The optional field class itself. + * + * If `content_field` is `NULL`, do not write anything (empty + * structure). + */ + if (content_field) { + ret = write_field(stream, fc->content_fc, content_field); + } + +end: + return ret; +} + static inline int write_variant_field(struct fs_sink_stream *stream, struct fs_sink_ctf_field_class_variant *fc, @@ -389,6 +423,9 @@ int write_field(struct fs_sink_stream *stream, case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE: ret = write_sequence_field(stream, (void *) fc, field); break; + case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION: + ret = write_option_field(stream, (void *) fc, field); + break; case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT: ret = write_variant_field(stream, (void *) fc, field); break; diff --git a/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c b/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c index b21917ac..2fa7c0fd 100644 --- a/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c +++ b/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c @@ -349,6 +349,8 @@ void append_member(struct ctx *ctx, const char *name, GString *lengths = NULL; const char *lengths_str = ""; + BT_ASSERT(fc); + while (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY || fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE) { if (!lengths) { @@ -398,6 +400,11 @@ void append_struct_field_class_members(struct ctx *ctx, struct_fc, i); struct fs_sink_ctf_field_class *fc = named_fc->fc; + /* + * For sequence, option, and variant field classes, if + * the length/tag field class is generated before, write + * it now before the dependent field class. + */ if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE) { struct fs_sink_ctf_field_class_sequence *seq_fc = (void *) fc; @@ -409,6 +416,42 @@ void append_struct_field_class_members(struct ctx *ctx, BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL, NULL, seq_fc->length_ref->str, true); } + } else if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION) { + struct fs_sink_ctf_field_class_option *opt_fc = + (void *) fc; + + /* + * CTF 1.8 does not support the option field + * class type. To write something anyway, this + * component translates this type to a variant + * field class where the options are: + * + * * An empty structure field class. + * * The optional field class itself. + * + * The "tag" is always generated/before in that + * case (an 8-bit unsigned enumeration field + * class). + */ + append_indent(ctx); + g_string_append(ctx->tsdl, + "/* The enumeration and variant field classes " + "below were a trace IR option field class. */\n"); + append_indent(ctx); + g_string_append(ctx->tsdl, "enum : "); + append_integer_field_class_from_props(ctx, + 8, 8, false, + BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL, + NULL, NULL, false); + g_string_append(ctx->tsdl, " {\n"); + ctx->indent_level++; + append_indent(ctx); + g_string_append(ctx->tsdl, "none = 0,\n"); + append_indent(ctx); + g_string_append(ctx->tsdl, "content = 1,\n"); + append_end_block(ctx); + g_string_append_printf(ctx->tsdl, " %s;\n", + opt_fc->tag_ref->str); } else if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT) { struct fs_sink_ctf_field_class_variant *var_fc = (void *) fc; @@ -461,6 +504,20 @@ void append_struct_field_class(struct ctx *ctx, fc->base.alignment); } +static +void append_option_field_class(struct ctx *ctx, + struct fs_sink_ctf_field_class_option *opt_fc) +{ + g_string_append_printf(ctx->tsdl, "variant <%s> {\n", + opt_fc->tag_ref->str); + ctx->indent_level++; + append_indent(ctx); + g_string_append(ctx->tsdl, "struct { } none;\n"); + append_indent(ctx); + append_member(ctx, "content", opt_fc->content_fc); + append_end_block(ctx); +} + static void append_variant_field_class(struct ctx *ctx, struct fs_sink_ctf_field_class_variant *var_fc) @@ -502,6 +559,9 @@ void append_field_class(struct ctx *ctx, struct fs_sink_ctf_field_class *fc) case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT: append_struct_field_class(ctx, (void *) fc); break; + case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION: + append_option_field_class(ctx, (void *) fc); + break; case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT: append_variant_field_class(ctx, (void *) fc); break; diff --git a/src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.c b/src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.c index ce4ec6f0..96455e70 100644 --- a/src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.c +++ b/src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.c @@ -319,6 +319,13 @@ int create_relative_field_ref(struct ctx *ctx, BT_ASSERT(tgt_fc); BT_ASSERT(fp_item); + if (bt_field_path_item_get_type(fp_item) == + BT_FIELD_PATH_ITEM_TYPE_CURRENT_OPTION_CONTENT) { + /* Not supported by CTF 1.8 */ + ret = -1; + goto end; + } + switch (tgt_fc->type) { case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT: BT_ASSERT(bt_field_path_item_get_type(fp_item) == @@ -599,6 +606,16 @@ void append_to_parent_field_class(struct ctx *ctx, fs_sink_ctf_field_class_struct_append_member((void *) parent_fc, cur_path_stack_top(ctx)->name->str, fc); break; + case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION: + { + struct fs_sink_ctf_field_class_option *opt_fc = + (void *) parent_fc; + + BT_ASSERT(!opt_fc->content_fc); + opt_fc->content_fc = fc; + opt_fc->base.alignment = fc->alignment; + break; + } case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT: fs_sink_ctf_field_class_variant_append_option((void *) parent_fc, cur_path_stack_top(ctx)->name->str, fc); @@ -915,6 +932,51 @@ end: return ret; } +static inline +int translate_option_field_class(struct ctx *ctx) +{ + struct fs_sink_ctf_field_class_option *fc = + fs_sink_ctf_field_class_option_create_empty( + cur_path_stack_top(ctx)->ir_fc, + cur_path_stack_top(ctx)->index_in_parent); + const bt_field_class *content_ir_fc = + bt_field_class_option_borrow_field_class_const(fc->base.ir_fc); + int ret; + + BT_ASSERT(fc); + + /* + * CTF 1.8 does not support the option field class type. To + * write something anyway, this component translates this type + * to a variant field class where the options are: + * + * * An empty structure field class. + * * The optional field class itself. + * + * The "tag" is always generated/before in that case (an 8-bit + * unsigned enumeration field class). + */ + append_to_parent_field_class(ctx, (void *) fc); + ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, false, content_ir_fc, + (void *) fc); + if (ret) { + BT_COMP_LOGE_STR("Cannot translate option field class content."); + goto end; + } + + ret = translate_field_class(ctx); + if (ret) { + BT_COMP_LOGE_STR("Cannot translate option field class content."); + goto end; + } + + cur_path_stack_pop(ctx); + update_parent_field_class_alignment(ctx, fc->base.alignment); + +end: + return ret; +} + static inline int translate_variant_field_class(struct ctx *ctx) { @@ -1255,6 +1317,9 @@ int translate_field_class(struct ctx *ctx) case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY: ret = translate_dynamic_array_field_class(ctx); break; + case BT_FIELD_CLASS_TYPE_OPTION: + ret = translate_option_field_class(ctx); + break; case BT_FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: case BT_FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: case BT_FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: @@ -1288,6 +1353,30 @@ int set_field_ref(struct fs_sink_ctf_field_class *fc, const char *fc_name, } switch (fc->type) { + case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION: + { + /* + * CTF 1.8 does not support the option field class type. + * To write something anyway, this component translates + * this type to a variant field class where the options + * are: + * + * * An empty structure field class. + * * The optional field class itself. + * + * Because the option field class becomes a CTF variant + * field class, we use the term "tag" too here. + * + * The "tag" is always generated/before in that case (an + * 8-bit unsigned enumeration field class). + */ + struct fs_sink_ctf_field_class_option *opt_fc = (void *) fc; + + field_ref = opt_fc->tag_ref; + is_before = true; + tgt_type = "tag"; + break; + } case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE: { struct fs_sink_ctf_field_class_sequence *seq_fc = (void *) fc; @@ -1375,6 +1464,22 @@ int set_field_refs(struct fs_sink_ctf_field_class * const fc, fc_type = fc->type; switch (fc_type) { + case FS_SINK_CTF_FIELD_CLASS_TYPE_OPTION: + { + struct fs_sink_ctf_field_class_option *opt_fc = (void *) fc; + + ret = set_field_ref(fc, fc_name, parent_fc); + if (ret) { + goto end; + } + + ret = set_field_refs(opt_fc->content_fc, NULL, fc); + if (ret) { + goto end; + } + + break; + } case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT: case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT: { -- 2.34.1