src.ctf.fs: add stream port name to trace-info query, use it for stream intersection
authorSimon Marchi <simon.marchi@efficios.com>
Tue, 28 May 2019 16:01:36 +0000 (12:01 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Wed, 5 Jun 2019 17:47:34 +0000 (13:47 -0400)
For creating stream intersection trimmers, we currently rely on the fact
that the CLI and the Python bindings know that src.ctf.fs component port
names are the path to the data stream files (or the first data stream
file for the corresponding stream, if there are multiple files).  Using
this information, they can deduce which trace (from the trace-info
query) this port is from, by checking for a trace whose path is a prefix
of the port name.

This patch changes how this works to avoid the CLI and Python bindings
having internal knowledge of how the src.ctf.fs component class names
the ports.  The trace-info query now include a "port-name" property for
each stream.  This property contains the name that a src.ctf.fs
component would give the port associated to this stream.  This allows
the CLI and the Python bindings to match a port with a trace (and
therefore an intersection range) just by comparing the port name in the
actual component instance with the port name in the trace-info query
result.

Here's an excerpt (just two streams) from a trace-info result with this patch
applied:

    -
      range-ns:
        begin: 1556911621056878212
        end: 1556911631077588247
      class-id: 0
      paths:
        - /home/smarchi/src/lttng-envs/augmented-metadata/home/lttng-traces/perpid-20190503-152658/archives/20190503T152700-0400-20190503T152703-0400-1/ust/pid/hello-ust-2335-20190503-152701/chan_2
        - /home/smarchi/src/lttng-envs/augmented-metadata/home/lttng-traces/perpid-20190503-152658/20190503T152705-0400-3/ust/pid/hello-ust-2335-20190503-152701/chan_2
      port-name: 1838b922-0089-497c-96e7-2c7ad63e901e | 0 | 2
      id: 2
    -
      range-ns:
        begin: 1556911621053751789
        end: 1556911631077569864
      class-id: 0
      paths:
        - /home/smarchi/src/lttng-envs/augmented-metadata/home/lttng-traces/perpid-20190503-152658/archives/20190503T152700-0400-20190503T152703-0400-1/ust/pid/hello-ust-2335-20190503-152701/chan_1
        - /home/smarchi/src/lttng-envs/augmented-metadata/home/lttng-traces/perpid-20190503-152658/20190503T152705-0400-3/ust/pid/hello-ust-2335-20190503-152701/chan_1
      port-name: 1838b922-0089-497c-96e7-2c7ad63e901e | 0 | 1
      id: 1

I added some simple tests, although they don't cover all the cases.  We
currently don't have a trace without uuid, or a trace with
stream_instance_id fields, to test the remaining possibilities.  I plan
on adding some soon, when adding tests for the trace merging feature, at
which point we can also enhance
test_query_trace_info.QueryTraceInfoPortNameTestCase.

Change-Id: Ib3afc19f2c0e09a7235475b53f8023c8a2f40ebf
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Reviewed-on: https://review.lttng.org/c/babeltrace/+/1339
Tested-by: jenkins
Reviewed-by: Philippe Proulx <eeppeliteloop@gmail.com>
bindings/python/bt2/bt2/trace_collection_message_iterator.py
cli/babeltrace.c
plugins/ctf/fs-src/fs.c
plugins/ctf/fs-src/fs.h
plugins/ctf/fs-src/query.c
tests/plugins/ctf/test_query_trace_info.py

index 269e796227586e647907cea23301b64c8416529a..2185fcd5772aa1ccbaba13ad48d68123fd21d05e 100644 (file)
@@ -140,14 +140,15 @@ class TraceCollectionMessageIterator(bt2.message_iterator._MessageIterator):
         begin = None
         end = None
 
-        # find the trace info for this port's trace by name's prefix
+        # find the trace info for this port's trace
         try:
             for trace_info in trace_info_res:
-                if port.name.startswith(str(trace_info['path'])):
-                    range_ns = trace_info['intersection-range-ns']
-                    begin = range_ns['begin']
-                    end = range_ns['end']
-                    break
+                for stream in trace_info['streams']:
+                    if stream['port-name'] == port.name:
+                        range_ns = trace_info['intersection-range-ns']
+                        begin = range_ns['begin']
+                        end = range_ns['end']
+                        break
         except Exception:
             pass
 
index 814ad0f35c08e7148bd6ec5db01dbfe9327fd9ce..913a74216c2d600d15a916e2ad3ae16d6059844d 100644 (file)
@@ -2169,8 +2169,6 @@ int set_stream_intersections(struct cmd_run_ctx *ctx,
        const bt_value *intersection_range = NULL;
        const bt_value *intersection_begin = NULL;
        const bt_value *intersection_end = NULL;
-       const bt_value *stream_path_value = NULL;
-       const bt_value *stream_paths = NULL;
        const bt_value *stream_infos = NULL;
        const bt_value *stream_info = NULL;
        struct port_id *port_id = NULL;
@@ -2269,20 +2267,8 @@ int set_stream_intersections(struct cmd_run_ctx *ctx,
                        goto error;
                }
 
-               /*
-                * FIXME
-                *
-                * The first path of a stream's "paths" is currently used to
-                * associate streams/ports to a given trace intersection.
-                *
-                * This is a fragile hack as it relies on the port names
-                * being set to the various streams path.
-                *
-                * A stream name should be introduced as part of the trace-info
-                * query result.
-                */
                for (stream_idx = 0; stream_idx < stream_count; stream_idx++) {
-                       const char *stream_path;
+                       const bt_value *port_name;
 
                        port_id = g_new0(struct port_id, 1);
                        if (!port_id) {
@@ -2314,26 +2300,14 @@ int set_stream_intersections(struct cmd_run_ctx *ctx,
                                goto error;
                        }
 
-                       stream_paths = bt_value_map_borrow_entry_value_const(stream_info,
-                                                                            "paths");
-                       if (!stream_paths || !bt_value_is_array(stream_paths)) {
-                               ret = -1;
-                               BT_LOGD_STR("Cannot retrieve stream paths from trace in query result.");
-                               goto error;
-                       }
-
-                       stream_path_value =
-                               bt_value_array_borrow_element_by_index_const(
-                                       stream_paths, 0);
-                       if (!stream_path_value ||
-                               !bt_value_is_string(stream_path_value)) {
+                       port_name = bt_value_map_borrow_entry_value_const(stream_info, "port-name");
+                       if (!port_name || !bt_value_is_string(port_name)) {
                                ret = -1;
-                               BT_LOGD_STR("Cannot retrieve stream path value from trace in query result.");
+                               BT_LOGD_STR("Cannot retrieve port name in query result.");
                                goto error;
                        }
 
-                       stream_path = bt_value_string_get(stream_path_value);
-                       port_id->port_name = strdup(stream_path);
+                       port_id->port_name = g_strdup(bt_value_string_get(port_name));
                        if (!port_id->port_name) {
                                ret = -1;
                                BT_LOGE_STR("Cannot allocate memory for port_id port_name.");
index 6f02c8de4570a40738c6886173338e4acb64073a..f1583ae439b3448386e8e6db089d02232eaaac97 100644 (file)
@@ -399,29 +399,48 @@ void ctf_fs_finalize(bt_self_component_source *component)
                bt_self_component_source_as_self_component(component)));
 }
 
-static
-GString *get_stream_instance_unique_name(
-               struct ctf_fs_ds_file_group *ds_file_group)
+gchar *ctf_fs_make_port_name(struct ctf_fs_ds_file_group *ds_file_group)
 {
-       GString *name;
-       struct ctf_fs_ds_file_info *ds_file_info;
+       GString *name = g_string_new(NULL);
 
-       name = g_string_new(NULL);
-       if (!name) {
-               goto end;
+       /*
+        * The unique port name is generated by concatenating unique identifiers
+        * for:
+        *
+        *   - the trace
+        *   - the stream class
+        *   - the stream
+        */
+
+       /* For the trace, use the uuid if present, else the path. */
+       if (ds_file_group->ctf_fs_trace->metadata->tc->is_uuid_set) {
+               char uuid_str[BABELTRACE_UUID_STR_LEN];
+
+               bt_uuid_unparse(ds_file_group->ctf_fs_trace->metadata->tc->uuid, uuid_str);
+               g_string_assign(name, uuid_str);
+       } else {
+               g_string_assign(name, ds_file_group->ctf_fs_trace->path->str);
        }
 
        /*
-        * If there's more than one stream file in the stream file
-        * group, the first (earliest) stream file's path is used as
-        * the stream's unique name.
+        * For the stream class, use the id if present.  We can omit this field
+        * otherwise, as there will only be a single stream class.
         */
-       BT_ASSERT(ds_file_group->ds_file_infos->len > 0);
-       ds_file_info = g_ptr_array_index(ds_file_group->ds_file_infos, 0);
-       g_string_assign(name, ds_file_info->path->str);
+       if (ds_file_group->sc->id != UINT64_C(-1)) {
+               g_string_append_printf(name, " | %" PRIu64, ds_file_group->sc->id);
+       }
 
-end:
-       return name;
+       /* For the stream, use the id if present, else, use the path. */
+       if (ds_file_group->stream_id != UINT64_C(-1)) {
+               g_string_append_printf(name, " | %" PRIu64, ds_file_group->stream_id);
+       } else {
+               BT_ASSERT(ds_file_group->ds_file_infos->len == 1);
+               struct ctf_fs_ds_file_info *ds_file_info =
+                       g_ptr_array_index(ds_file_group->ds_file_infos, 0);
+               g_string_append_printf(name, " | %s", ds_file_info->path->str);
+       }
+
+       return g_string_free(name, FALSE);
 }
 
 static
@@ -431,14 +450,14 @@ int create_one_port_for_trace(struct ctf_fs_component *ctf_fs,
 {
        int ret = 0;
        struct ctf_fs_port_data *port_data = NULL;
-       GString *port_name = NULL;
+       gchar *port_name;
 
-       port_name = get_stream_instance_unique_name(ds_file_group);
+       port_name = ctf_fs_make_port_name(ds_file_group);
        if (!port_name) {
                goto error;
        }
 
-       BT_LOGD("Creating one port named `%s`", port_name->str);
+       BT_LOGD("Creating one port named `%s`", port_name);
 
        /* Create output port for this file */
        port_data = g_new0(struct ctf_fs_port_data, 1);
@@ -449,7 +468,7 @@ int create_one_port_for_trace(struct ctf_fs_component *ctf_fs,
        port_data->ctf_fs = ctf_fs;
        port_data->ds_file_group = ds_file_group;
        ret = bt_self_component_source_add_output_port(
-               ctf_fs->self_comp, port_name->str, port_data, NULL);
+               ctf_fs->self_comp, port_name, port_data, NULL);
        if (ret) {
                goto error;
        }
@@ -463,7 +482,7 @@ error:
 
 end:
        if (port_name) {
-               g_string_free(port_name, TRUE);
+               g_free(port_name);
        }
 
        port_data_destroy(port_data);
@@ -1587,6 +1606,31 @@ end:
        return ret;
 }
 
+static
+GString *get_stream_instance_unique_name(
+               struct ctf_fs_ds_file_group *ds_file_group)
+{
+       GString *name;
+       struct ctf_fs_ds_file_info *ds_file_info;
+
+       name = g_string_new(NULL);
+       if (!name) {
+               goto end;
+       }
+
+       /*
+        * If there's more than one stream file in the stream file
+        * group, the first (earliest) stream file's path is used as
+        * the stream's unique name.
+        */
+       BT_ASSERT(ds_file_group->ds_file_infos->len > 0);
+       ds_file_info = g_ptr_array_index(ds_file_group->ds_file_infos, 0);
+       g_string_assign(name, ds_file_info->path->str);
+
+end:
+       return name;
+}
+
 /* Create the IR stream objects for ctf_fs_trace. */
 
 static
index 6594b61153c8334fd8119affb2dfe818d948829d..ed65aa3c446fe21864f9e73e0fcd2ec36a61872c 100644 (file)
@@ -218,4 +218,13 @@ BT_HIDDEN
 bool read_src_fs_parameters(const bt_value *params,
                const bt_value **paths, struct ctf_fs_component *ctf_fs);
 
+/*
+ * Generate the port name to be used for a given data stream file group.
+ *
+ * The result must be freed using g_free by the caller.
+ */
+
+BT_HIDDEN
+gchar *ctf_fs_make_port_name(struct ctf_fs_ds_file_group *ds_file_group);
+
 #endif /* BABELTRACE_PLUGIN_CTF_FS_H */
index 31d710814b92812578d2ab7582fb85e89609e502..d666e1c4f6f9baab495027975ac29dacfc5a6a08 100644 (file)
@@ -273,6 +273,7 @@ int populate_stream_info(struct ctf_fs_ds_file_group *group,
        bt_value *file_paths;
        struct ctf_fs_ds_file_info *first_file_info, *last_file_info;
        struct ctf_fs_ds_index_entry *first_ds_index_entry, *last_ds_index_entry;
+       gchar *port_name = NULL;
 
        file_paths = bt_value_array_create();
        if (!file_paths) {
@@ -344,6 +345,20 @@ int populate_stream_info(struct ctf_fs_ds_file_group *group,
        if (ret) {
                goto end;
        }
+
+       port_name = ctf_fs_make_port_name(group);
+       if (!port_name) {
+               ret = -1;
+               goto end;
+       }
+
+       status = bt_value_map_insert_string_entry(group_info, "port-name",
+               port_name);
+       if (status != BT_VALUE_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
 end:
        bt_value_put_ref(file_paths);
        return ret;
index c8b5923cd9e8aec34cf7565b63c697f53a7700c7..053c0e1e43c20b4a7f8892d96100bb09c8903ccd 100644 (file)
@@ -17,6 +17,7 @@
 import unittest
 import bt2
 import os
+import re
 
 
 test_ctf_traces_path = os.environ['TEST_CTF_TRACES_PATH']
@@ -121,5 +122,54 @@ class QueryTraceInfoClockOffsetTestCase(unittest.TestCase):
                 'clock-class-offset-ns': None,
             })
 
+
+class QueryTraceInfoPortNameTestCase(unittest.TestCase):
+    def setUp(self):
+        ctf = bt2.find_plugin("ctf")
+        self._fs = ctf.source_component_classes["fs"]
+
+        self._executor = bt2.QueryExecutor()
+
+    def test_trace_uuid_stream_class_id_no_stream_id(self):
+        res = self._executor.query(
+            self._fs,
+            "trace-info",
+            {
+                "paths": [
+                    os.path.join(
+                        test_ctf_traces_path, "intersection", "3eventsintersect"
+                    )
+                ]
+            },
+        )
+        self.assertEqual(len(res), 1)
+        trace = res[0]
+        streams = sorted(trace["streams"], key=sort_by_begin)
+        self.assertEqual(len(streams), 2)
+        self.assertRegexpMatches(
+            str(streams[0]["port-name"]),
+            r"^7afe8fbe-79b8-4f6a-bbc7-d0c782e7ddaf \| 0 \| .*/tests/ctf-traces/intersection/3eventsintersect/test_stream_0$",
+        )
+        self.assertRegexpMatches(
+            str(streams[1]["port-name"]),
+            r"^7afe8fbe-79b8-4f6a-bbc7-d0c782e7ddaf \| 0 \| .*/tests/ctf-traces/intersection/3eventsintersect/test_stream_1$",
+        )
+
+    def test_trace_uuid_no_stream_class_id_no_stream_id(self):
+        res = self._executor.query(
+            self._fs,
+            "trace-info",
+            {"paths": [os.path.join(test_ctf_traces_path, "succeed", "succeed1")]},
+        )
+        self.assertEqual(len(res), 1)
+        trace = res[0]
+        streams = sorted(trace["streams"], key=sort_by_begin)
+        self.assertEqual(len(streams), 1)
+        self.assertRegexpMatches(
+            str(streams[0]["port-name"]),
+            r"^2a6422d0-6cee-11e0-8c08-cb07d7b3a564 \| .*/tests/ctf-traces/succeed/succeed1/dummystream$",
+        )
+
+
 if __name__ == '__main__':
     unittest.main()
This page took 0.031105 seconds and 4 git commands to generate.