sink.ctf.fs: write option field classes and fields
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Tue, 13 Aug 2019 00:16:09 +0000 (20:16 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Thu, 15 Aug 2019 15:41:44 +0000 (11:41 -0400)
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 <eeppeliteloop@gmail.com>
Change-Id: Ib83e011f73795d70cd8545f55ea87e0bf10b68bc
Reviewed-on: https://review.lttng.org/c/babeltrace/+/1901
Tested-by: jenkins <jenkins@lttng.org>
Reviewed-by: Francis Deslauriers <francis.deslauriers@efficios.com>
src/plugins/ctf/fs-sink/fs-sink-ctf-meta.h
src/plugins/ctf/fs-sink/fs-sink-stream.c
src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c
src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.c

index a96cbad8e5c30bedf4e53106be4394e8c1f9aaeb..9fcd3636c8aae13b563169791c632af63ca9423c 100644 (file)
@@ -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;
index 28f70e4f99d36a5c7a6b2b091afebc11d4fb4541..ed516b1cb32c8e4bb8707831062604a5b10b9b8e 100644 (file)
@@ -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;
index b21917ac3584c2b850dcf57f4a86eca45c5ba5b1..2fa7c0fdadfb84ed8eeea5eb47cc983d767b3dfa 100644 (file)
@@ -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;
index ce4ec6f09646657e37dbdbd1d317ba7ffcc01735..96455e7014ba7a4e76fd37b30f5f71ef08edbde8 100644 (file)
@@ -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:
        {
This page took 0.031648 seconds and 4 git commands to generate.