trimmer: Update the bounds of the trimmed packets
authorJulien Desfossez <jdesfossez@efficios.com>
Wed, 22 Feb 2017 21:49:29 +0000 (16:49 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Sun, 28 May 2017 16:57:39 +0000 (12:57 -0400)
Update the timestamp_begin field of the first packet of each stream and
the timestamp_end field of the last packet to reflect the fact that the
packet content got truncated by the user. This is important for the
packet intersection feature afterwards. This requires that we create new
packets and copy the events to assign them to the new packets.

Signed-off-by: Julien Desfossez <jdesfossez@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
plugins/utils/trimmer/Makefile.am
plugins/utils/trimmer/copy.c [new file with mode: 0644]
plugins/utils/trimmer/copy.h [new file with mode: 0644]
plugins/utils/trimmer/iterator.c
plugins/utils/trimmer/iterator.h

index f229fc6875b4b2914c701cf8fd638603f36e70f2..a8de1c14f4fd4b88765efc639c897560f63eca93 100644 (file)
@@ -1,8 +1,11 @@
-AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include -I$(top_srcdir)/plugins
+AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include -I$(top_srcdir)/plugins \
+           -I$(top_srcdir)/plugins/libctfcopytrace
 
 noinst_LTLIBRARIES = libbabeltrace-plugin-trimmer.la
 libbabeltrace_plugin_trimmer_la_SOURCES = \
        trimmer.c \
        iterator.c \
+       copy.c \
        trimmer.h \
-       iterator.h
+       iterator.h \
+       copy.h
diff --git a/plugins/utils/trimmer/copy.c b/plugins/utils/trimmer/copy.c
new file mode 100644 (file)
index 0000000..a8c5d5c
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * copy.c
+ *
+ * Babeltrace Copy Trace Structure
+ *
+ * Copyright 2017 Julien Desfossez <jdesfossez@efficios.com>
+ *
+ * Author: Julien Desfossez <jdesfossez@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/ctf-ir/event.h>
+#include <babeltrace/ctf-ir/packet.h>
+#include <babeltrace/ctf-ir/event-class.h>
+#include <babeltrace/ctf-ir/stream.h>
+#include <babeltrace/ctf-ir/stream-class.h>
+#include <babeltrace/ctf-ir/clock-class.h>
+#include <babeltrace/ctf-ir/fields.h>
+#include <babeltrace/ctf-writer/stream-class.h>
+#include <babeltrace/ctf-writer/stream.h>
+
+#include <ctfcopytrace.h>
+#include "iterator.h"
+
+static
+struct bt_ctf_packet *lookup_packet(struct trimmer_iterator *trim_it,
+               struct bt_ctf_packet *packet)
+{
+       return (struct bt_ctf_packet *) g_hash_table_lookup(
+                       trim_it->packet_map,
+                       (gpointer) packet);
+}
+
+static
+struct bt_ctf_packet *insert_new_packet(struct trimmer_iterator *trim_it,
+               struct bt_ctf_packet *packet,
+               struct bt_ctf_stream *stream)
+{
+       struct bt_ctf_packet *writer_packet;
+
+       writer_packet = bt_ctf_packet_create(stream);
+       if (!writer_packet) {
+               fprintf(trim_it->err, "[error] %s in %s:%d\n", __func__,
+                               __FILE__, __LINE__);
+               goto end;
+       }
+       g_hash_table_insert(trim_it->packet_map, (gpointer) packet, writer_packet);
+
+end:
+       return writer_packet;
+}
+
+BT_HIDDEN
+enum bt_component_status update_packet_context_field(FILE *err,
+               struct bt_ctf_packet *writer_packet,
+               const char *name, int64_t value)
+{
+       enum bt_component_status ret;
+       struct bt_ctf_field *packet_context, *writer_packet_context;
+       struct bt_ctf_field_type *struct_type, *writer_packet_context_type;
+       struct bt_ctf_stream_class *stream_class;
+       struct bt_ctf_stream *stream;
+       int nr_fields, i, int_ret;
+
+       packet_context = bt_ctf_packet_get_context(writer_packet);
+       if (!packet_context) {
+               ret = BT_COMPONENT_STATUS_ERROR;
+               fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__,
+                               __LINE__);
+               goto end;
+       }
+
+       stream = bt_ctf_packet_get_stream(writer_packet);
+       if (!stream) {
+               ret = BT_COMPONENT_STATUS_ERROR;
+               fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__,
+                               __LINE__);
+               goto end_put_packet_context;
+       }
+
+       stream_class = bt_ctf_stream_get_class(stream);
+       if (!stream_class) {
+               ret = BT_COMPONENT_STATUS_ERROR;
+               fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__,
+                               __LINE__);
+               goto end_put_stream;
+       }
+
+       writer_packet_context_type = bt_ctf_stream_class_get_packet_context_type(
+                       stream_class);
+       if (!writer_packet_context_type) {
+               ret = BT_COMPONENT_STATUS_ERROR;
+               fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__,
+                               __LINE__);
+               goto end_put_stream_class;
+       }
+
+       struct_type = bt_ctf_field_get_type(packet_context);
+       if (!struct_type) {
+               ret = BT_COMPONENT_STATUS_ERROR;
+               fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__,
+                               __LINE__);
+               goto end_put_writer_packet_context_type;
+       }
+
+       writer_packet_context = bt_ctf_packet_get_context(writer_packet);
+       if (!writer_packet_context) {
+               ret = BT_COMPONENT_STATUS_ERROR;
+               fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__,
+                               __LINE__);
+               goto end_put_struct_type;
+       }
+
+       nr_fields = bt_ctf_field_type_structure_get_field_count(struct_type);
+       for (i = 0; i < nr_fields; i++) {
+               struct bt_ctf_field *field, *writer_field;
+               struct bt_ctf_field_type *field_type;
+               const char *field_name;
+
+               field = bt_ctf_field_structure_get_field_by_index(
+                               packet_context, i);
+               if (!field) {
+                       ret = BT_COMPONENT_STATUS_ERROR;
+                       fprintf(err, "[error] %s in %s:%d\n", __func__,
+                                       __FILE__, __LINE__);
+                       goto end_put_writer_packet_context;
+               }
+               if (bt_ctf_field_type_structure_get_field(struct_type,
+                                       &field_name, &field_type, i) < 0) {
+                       ret = BT_COMPONENT_STATUS_ERROR;
+                       bt_put(field);
+                       fprintf(err, "[error] %s in %s:%d\n", __func__,
+                                       __FILE__, __LINE__);
+                       goto end_put_writer_packet_context;
+               }
+               if (strcmp(field_name, name)) {
+                       bt_put(field_type);
+                       bt_put(field);
+                       continue;
+               }
+               if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_TYPE_ID_INTEGER) {
+                       fprintf(err, "[error] Unexpected packet context field type\n");
+                       bt_put(field);
+                       ret = BT_COMPONENT_STATUS_ERROR;
+                       goto end_put_writer_packet_context;
+               }
+               writer_field = bt_ctf_field_structure_get_field(writer_packet_context,
+                               field_name);
+               if (!writer_field) {
+                       ret = BT_COMPONENT_STATUS_ERROR;
+                       fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__,
+                                       __LINE__);
+                       goto end;
+               }
+
+               int_ret = bt_ctf_field_unsigned_integer_set_value(writer_field, value);
+               bt_put(writer_field);
+               if (int_ret < 0) {
+                       ret = BT_COMPONENT_STATUS_ERROR;
+                       fprintf(err, "[error] %s in %s:%d\n", __func__, __FILE__,
+                                       __LINE__);
+                       goto end_put_writer_packet_context;
+               }
+
+               bt_put(field_type);
+               bt_put(field);
+       }
+
+       ret = BT_COMPONENT_STATUS_OK;
+
+end_put_writer_packet_context:
+       bt_put(writer_packet_context);
+end_put_struct_type:
+       bt_put(struct_type);
+end_put_writer_packet_context_type:
+       bt_put(writer_packet_context_type);
+end_put_stream_class:
+       bt_put(stream_class);
+end_put_packet_context:
+       bt_put(packet_context);
+end_put_stream:
+       bt_put(stream);
+end:
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_ctf_packet *trimmer_new_packet(
+               struct trimmer_iterator *trim_it,
+               struct bt_ctf_packet *packet)
+{
+       struct bt_ctf_stream *stream;
+       struct bt_ctf_field *writer_packet_context;
+       struct bt_ctf_packet *writer_packet = NULL;
+       int int_ret;
+
+       stream = bt_ctf_packet_get_stream(packet);
+       if (!stream) {
+               fprintf(trim_it->err, "[error] %s in %s:%d\n",
+                               __func__, __FILE__, __LINE__);
+               goto end;
+       }
+
+       /*
+        * If a packet was already opened, close it and remove it from
+        * the HT.
+        */
+       writer_packet = lookup_packet(trim_it, packet);
+       if (writer_packet) {
+               g_hash_table_remove(trim_it->packet_map, packet);
+               bt_put(writer_packet);
+       }
+
+       writer_packet = insert_new_packet(trim_it, packet, stream);
+       if (!writer_packet) {
+               fprintf(trim_it->err, "[error] %s in %s:%d\n",
+                               __func__, __FILE__, __LINE__);
+               goto end_put_stream;
+       }
+       bt_get(writer_packet);
+
+       writer_packet_context = ctf_copy_packet_context(trim_it->err, packet,
+                       stream);
+       if (!writer_packet_context) {
+               BT_PUT(writer_packet);
+               fprintf(trim_it->err, "[error] %s in %s:%d\n",
+                               __func__, __FILE__, __LINE__);
+               goto end_put_stream;
+       }
+
+       int_ret = bt_ctf_packet_set_context(writer_packet, writer_packet_context);
+       if (int_ret) {
+               BT_PUT(writer_packet);
+               fprintf(trim_it->err, "[error] %s in %s:%d\n",
+                               __func__, __FILE__, __LINE__);
+               goto end_put_writer_packet_context;
+       }
+
+end_put_writer_packet_context:
+       bt_put(writer_packet_context);
+end_put_stream:
+       bt_put(stream);
+end:
+       return writer_packet;
+}
+
+BT_HIDDEN
+struct bt_ctf_packet *trimmer_close_packet(
+               struct trimmer_iterator *trim_it,
+               struct bt_ctf_packet *packet)
+{
+       struct bt_ctf_packet *writer_packet;
+
+       writer_packet = lookup_packet(trim_it, packet);
+       if (!writer_packet) {
+               fprintf(trim_it->err, "[error] %s in %s:%d\n", __func__,
+                               __FILE__, __LINE__);
+               goto end;
+       }
+
+       g_hash_table_remove(trim_it->packet_map, packet);
+
+end:
+       return writer_packet;
+}
+
+BT_HIDDEN
+struct bt_ctf_event *trimmer_output_event(
+               struct trimmer_iterator *trim_it,
+               struct bt_ctf_event *event)
+{
+       struct bt_ctf_event_class *event_class;
+       struct bt_ctf_stream *stream;
+       struct bt_ctf_stream_class *stream_class;
+       struct bt_ctf_event *writer_event = NULL;
+       struct bt_ctf_packet *packet, *writer_packet;
+       const char *event_name;
+       int int_ret;
+
+       event_class = bt_ctf_event_get_class(event);
+       if (!event_class) {
+               fprintf(trim_it->err, "[error] %s in %s:%d\n", __func__,
+                               __FILE__, __LINE__);
+               goto end;
+       }
+
+       event_name = bt_ctf_event_class_get_name(event_class);
+       if (!event_name) {
+               fprintf(trim_it->err, "[error] %s in %s:%d\n", __func__,
+                               __FILE__, __LINE__);
+               goto end_put_event_class;
+       }
+
+       stream = bt_ctf_event_get_stream(event);
+       if (!stream) {
+               fprintf(trim_it->err, "[error] %s in %s:%d\n", __func__,
+                               __FILE__, __LINE__);
+               goto end_put_event_class;
+       }
+
+       stream_class = bt_ctf_event_class_get_stream_class(event_class);
+       if (!stream_class) {
+               fprintf(trim_it->err, "[error] %s in %s:%d\n", __func__,
+                               __FILE__, __LINE__);
+               goto end_put_stream;
+       }
+
+       writer_event = ctf_copy_event(trim_it->err, event, event_class, false);
+       if (!writer_event) {
+               fprintf(trim_it->err, "[error] %s in %s:%d\n", __func__,
+                               __FILE__, __LINE__);
+               fprintf(trim_it->err, "[error] Failed to copy event %s\n",
+                               bt_ctf_event_class_get_name(event_class));
+               goto end_put_stream_class;
+       }
+
+       packet = bt_ctf_event_get_packet(event);
+       if (!packet) {
+               BT_PUT(writer_event);
+               fprintf(trim_it->err, "[error] %s in %s:%d\n", __func__,
+                               __FILE__, __LINE__);
+               goto end_put_stream_class;
+       }
+
+       writer_packet = lookup_packet(trim_it, packet);
+       if (!writer_packet) {
+               BT_PUT(writer_event);
+               fprintf(trim_it->err, "[error] %s in %s:%d\n", __func__,
+                               __FILE__, __LINE__);
+               goto end_put_packet;
+       }
+       bt_get(writer_packet);
+
+       int_ret = bt_ctf_event_set_packet(writer_event, writer_packet);
+       if (int_ret < 0) {
+               BT_PUT(writer_event);
+               fprintf(trim_it->err, "[error] %s in %s:%d\n", __func__,
+                               __FILE__, __LINE__);
+               fprintf(trim_it->err, "[error] Failed to append event %s\n",
+                               bt_ctf_event_class_get_name(event_class));
+               goto end_put_writer_packet;
+       }
+
+       /* We keep the reference on the writer event */
+
+end_put_writer_packet:
+       bt_put(writer_packet);
+end_put_packet:
+       bt_put(packet);
+end_put_stream_class:
+       bt_put(stream_class);
+end_put_stream:
+       bt_put(stream);
+end_put_event_class:
+       bt_put(event_class);
+end:
+       return writer_event;
+}
diff --git a/plugins/utils/trimmer/copy.h b/plugins/utils/trimmer/copy.h
new file mode 100644 (file)
index 0000000..fc66d0a
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef BABELTRACE_PLUGIN_TRIMMER_COPY_H
+#define BABELTRACE_PLUGIN_TRIMMER_COPY_H
+
+/*
+ * BabelTrace - Copy Trace Structure
+ *
+ * Copyright 2017 Julien Desfossez <jdesfossez@efficios.com>
+ *
+ * Author: Julien Desfossez <jdesfossez@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/ctf-writer/writer.h>
+#include <babeltrace/ctf-ir/packet.h>
+#include <babeltrace/graph/component.h>
+
+BT_HIDDEN
+struct bt_ctf_event *trimmer_output_event(struct trimmer_iterator *trim_it,
+               struct bt_ctf_event *event);
+BT_HIDDEN
+struct bt_ctf_packet *trimmer_new_packet(struct trimmer_iterator *trim_it,
+               struct bt_ctf_packet *packet);
+BT_HIDDEN
+struct bt_ctf_packet *trimmer_close_packet(struct trimmer_iterator *trim_it,
+               struct bt_ctf_packet *packet);
+BT_HIDDEN
+enum bt_component_status update_packet_context_field(FILE *err,
+               struct bt_ctf_packet *writer_packet,
+               const char *name, int64_t value);
+
+#endif /* BABELTRACE_PLUGIN_TRIMMER_COPY_H */
index 2d487f19ef0bc292f3f18a88fb01abcf57a29e59..8b35cf984a4d9176f604dd47f8b4743b2519004c 100644 (file)
@@ -26,8 +26,6 @@
  * SOFTWARE.
  */
 
-#include "trimmer.h"
-#include "iterator.h"
 #include <babeltrace/graph/notification-iterator.h>
 #include <babeltrace/graph/private-notification-iterator.h>
 #include <babeltrace/graph/notification.h>
 #include <assert.h>
 #include <plugins-common.h>
 
+#include "trimmer.h"
+#include "iterator.h"
+#include "copy.h"
+
 BT_HIDDEN
 void trimmer_iterator_finalize(struct bt_private_notification_iterator *it)
 {
@@ -58,6 +60,7 @@ void trimmer_iterator_finalize(struct bt_private_notification_iterator *it)
        assert(it_data);
 
        bt_put(it_data->input_iterator);
+       g_hash_table_destroy(it_data->packet_map);
        g_free(it_data);
 }
 
@@ -94,6 +97,10 @@ enum bt_notification_iterator_status trimmer_iterator_init(
                goto end;
        }
 
+       it_data->err = stderr;
+       it_data->packet_map = g_hash_table_new_full(g_direct_hash,
+                       g_direct_equal, NULL, NULL);
+
        it_ret = bt_private_notification_iterator_set_user_data(iterator,
                it_data);
        if (it_ret) {
@@ -167,26 +174,35 @@ error:
 }
 
 static
-enum bt_notification_iterator_status
-evaluate_event_notification(struct bt_notification *notification,
+struct bt_notification *evaluate_event_notification(
+               struct bt_notification *notification,
+               struct trimmer_iterator *trim_it,
                struct trimmer_bound *begin, struct trimmer_bound *end,
                bool *_event_in_range)
 {
        int64_t ts;
        int clock_ret;
-       struct bt_ctf_event *event = NULL;
+       struct bt_ctf_event *event = NULL, *writer_event;
        bool in_range = true;
        struct bt_ctf_clock_class *clock_class = NULL;
        struct bt_ctf_trace *trace = NULL;
        struct bt_ctf_stream *stream = NULL;
        struct bt_ctf_stream_class *stream_class = NULL;
        struct bt_ctf_clock_value *clock_value = NULL;
-       enum bt_notification_iterator_status ret =
-                       BT_NOTIFICATION_ITERATOR_STATUS_OK;
        bool lazy_update = false;
+       struct bt_notification *new_notification = NULL;
+       struct bt_clock_class_priority_map *cc_prio_map;
 
        event = bt_notification_event_get_event(notification);
        assert(event);
+       cc_prio_map = bt_notification_event_get_clock_class_priority_map(
+                       notification);
+       assert(cc_prio_map);
+       writer_event = trimmer_output_event(trim_it, event);
+       assert(writer_event);
+       new_notification = bt_notification_event_create(writer_event, cc_prio_map);
+       assert(new_notification);
+       bt_put(cc_prio_map);
 
        stream = bt_ctf_event_get_stream(event);
        assert(stream);
@@ -206,30 +222,25 @@ evaluate_event_notification(struct bt_notification *notification,
        clock_value = bt_ctf_event_get_clock_value(event, clock_class);
        if (!clock_value) {
                printf_error("Failed to retrieve clock value");
-               ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
-               goto end;
+               goto error;
        }
 
        clock_ret = bt_ctf_clock_value_get_value_ns_from_epoch(
                        clock_value, &ts);
        if (clock_ret) {
                printf_error("Failed to retrieve clock value timestamp");
-               ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
-               goto end;
+               goto error;
        }
        if (update_lazy_bound(begin, "begin", ts, &lazy_update)) {
-               ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
                goto end;
        }
        if (update_lazy_bound(end, "end", ts, &lazy_update)) {
-               ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
                goto end;
        }
        if (lazy_update && begin->set && end->set) {
                if (begin->value > end->value) {
                        printf_error("Unexpected: time range begin value is above end value");
-                       ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
-                       goto end;
+                       goto error;
                }
        }
        if (begin->set && ts < begin->value) {
@@ -238,15 +249,21 @@ evaluate_event_notification(struct bt_notification *notification,
        if (end->set && ts > end->value) {
                in_range = false;
        }
+
+       goto end;
+
+error:
+       BT_PUT(new_notification);
 end:
        bt_put(event);
+       bt_put(writer_event);
        bt_put(clock_class);
        bt_put(trace);
        bt_put(stream);
        bt_put(stream_class);
        bt_put(clock_value);
        *_event_in_range = in_range;
-       return ret;
+       return new_notification;
 }
 
 static
@@ -293,58 +310,139 @@ end:
        return ret;
 }
 
+static uint64_t ns_from_value(uint64_t frequency, uint64_t value)
+{
+       uint64_t ns;
+
+       if (frequency == NSEC_PER_SEC) {
+               ns = value;
+       } else {
+               ns = (uint64_t) ((1e9 * (double) value) / (double) frequency);
+       }
+
+       return ns;
+}
+
+/*
+ * timestamp minus the offset.
+ */
 static
-enum bt_notification_iterator_status evaluate_packet_notification(
+int64_t get_raw_timestamp(struct bt_ctf_packet *writer_packet,
+               int64_t timestamp)
+{
+       struct bt_ctf_clock_class *writer_clock_class;
+       int64_t sec_offset, cycles_offset, ns;
+       struct bt_ctf_trace *writer_trace;
+       struct bt_ctf_stream *writer_stream;
+       struct bt_ctf_stream_class *writer_stream_class;
+       int ret;
+       uint64_t freq;
+
+       writer_stream = bt_ctf_packet_get_stream(writer_packet);
+       assert(writer_stream);
+
+       writer_stream_class = bt_ctf_stream_get_class(writer_stream);
+       assert(writer_stream_class);
+
+       writer_trace = bt_ctf_stream_class_get_trace(writer_stream_class);
+       assert(writer_trace);
+
+       /* FIXME multi-clock? */
+       writer_clock_class = bt_ctf_trace_get_clock_class(writer_trace, 0);
+       assert(writer_clock_class);
+
+       ret = bt_ctf_clock_class_get_offset_s(writer_clock_class, &sec_offset);
+       assert(!ret);
+       ns = sec_offset * NSEC_PER_SEC;
+
+       freq = bt_ctf_clock_class_get_frequency(writer_clock_class);
+       assert(freq != -1ULL);
+
+       ret = bt_ctf_clock_class_get_offset_cycles(writer_clock_class, &cycles_offset);
+       assert(!ret);
+
+       ns += ns_from_value(freq, cycles_offset);
+
+       bt_put(writer_clock_class);
+       bt_put(writer_trace);
+       bt_put(writer_stream_class);
+       bt_put(writer_stream);
+
+       return timestamp - ns;
+}
+
+static
+struct bt_notification *evaluate_packet_notification(
                struct bt_notification *notification,
+               struct trimmer_iterator *trim_it,
                struct trimmer_bound *begin, struct trimmer_bound *end,
                bool *_packet_in_range)
 {
-        enum bt_notification_iterator_status ret =
-                       BT_NOTIFICATION_ITERATOR_STATUS_OK;
        int64_t begin_ns, pkt_begin_ns, end_ns, pkt_end_ns;
        bool in_range = true;
-       struct bt_ctf_packet *packet = NULL;
+       struct bt_ctf_packet *packet = NULL, *writer_packet = NULL;
        struct bt_ctf_field *packet_context = NULL,
                        *timestamp_begin = NULL,
                        *timestamp_end = NULL;
+       struct bt_notification *new_notification = NULL;
+       enum bt_component_status ret;
+       bool lazy_update = false;
 
         switch (bt_notification_get_type(notification)) {
        case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
                packet = bt_notification_packet_begin_get_packet(notification);
+               assert(packet);
+               writer_packet = trimmer_new_packet(trim_it, packet);
+               assert(writer_packet);
                break;
        case BT_NOTIFICATION_TYPE_PACKET_END:
                packet = bt_notification_packet_end_get_packet(notification);
+               assert(packet);
+               writer_packet = trimmer_close_packet(trim_it, packet);
+               assert(writer_packet);
                break;
        default:
-               break;
+               goto end;
        }
-       assert(packet);
 
-       packet_context = bt_ctf_packet_get_context(packet);
+       packet_context = bt_ctf_packet_get_context(writer_packet);
        if (!packet_context) {
-               goto end;
+               goto end_no_notif;
        }
 
        if (!bt_ctf_field_is_structure(packet_context)) {
-               goto end;
+               goto end_no_notif;
        }
 
        timestamp_begin = bt_ctf_field_structure_get_field(
                        packet_context, "timestamp_begin");
        if (!timestamp_begin || !bt_ctf_field_is_integer(timestamp_begin)) {
-               goto end;
+               goto end_no_notif;
        }
        timestamp_end = bt_ctf_field_structure_get_field(
                        packet_context, "timestamp_end");
        if (!timestamp_end || !bt_ctf_field_is_integer(timestamp_end)) {
-               goto end;
+               goto end_no_notif;
        }
 
        if (ns_from_integer_field(timestamp_begin, &pkt_begin_ns)) {
-               goto end;
+               goto end_no_notif;
        }
        if (ns_from_integer_field(timestamp_end, &pkt_end_ns)) {
-               goto end;
+               goto end_no_notif;
+       }
+
+       if (update_lazy_bound(begin, "begin", pkt_begin_ns, &lazy_update)) {
+               goto end_no_notif;
+       }
+       if (update_lazy_bound(end, "end", pkt_end_ns, &lazy_update)) {
+               goto end_no_notif;
+       }
+       if (lazy_update && begin->set && end->set) {
+               if (begin->value > end->value) {
+                       printf_error("Unexpected: time range begin value is above end value");
+                       goto end_no_notif;
+               }
        }
 
        begin_ns = begin->set ? begin->value : INT64_MIN;
@@ -355,43 +453,96 @@ enum bt_notification_iterator_status evaluate_packet_notification(
         * packet.
         */
        in_range = (pkt_end_ns >= begin_ns) && (pkt_begin_ns <= end_ns);
+       if (!in_range) {
+               goto end_no_notif;
+       }
+
+       if (begin_ns > pkt_begin_ns) {
+               ret = update_packet_context_field(trim_it->err, writer_packet,
+                               "timestamp_begin",
+                               get_raw_timestamp(writer_packet, begin_ns));
+               assert(!ret);
+       }
+
+       if (end_ns < pkt_end_ns) {
+               ret = update_packet_context_field(trim_it->err, writer_packet,
+                               "timestamp_end",
+                               get_raw_timestamp(writer_packet, end_ns));
+               assert(!ret);
+       }
+
 end:
+        switch (bt_notification_get_type(notification)) {
+       case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
+               new_notification = bt_notification_packet_begin_create(writer_packet);
+               assert(new_notification);
+               break;
+       case BT_NOTIFICATION_TYPE_PACKET_END:
+               new_notification = bt_notification_packet_end_create(writer_packet);
+               assert(new_notification);
+               break;
+       default:
+               break;
+       }
+end_no_notif:
        *_packet_in_range = in_range;
        bt_put(packet);
+       bt_put(writer_packet);
        bt_put(packet_context);
        bt_put(timestamp_begin);
        bt_put(timestamp_end);
-       return ret;
+       return new_notification;
+}
+
+static
+struct bt_notification *evaluate_stream_notification(
+               struct bt_notification *notification,
+               struct trimmer_iterator *trim_it)
+{
+       struct bt_ctf_stream *stream;
+
+       stream = bt_notification_stream_end_get_stream(notification);
+       assert(stream);
+
+       /* FIXME: useless copy */
+       return bt_notification_stream_end_create(stream);
 }
 
 /* Return true if the notification should be forwarded. */
 static
 enum bt_notification_iterator_status evaluate_notification(
-               struct bt_notification *notification,
+               struct bt_notification **notification,
+               struct trimmer_iterator *trim_it,
                struct trimmer_bound *begin, struct trimmer_bound *end,
                bool *in_range)
 {
        enum bt_notification_type type;
-       enum bt_notification_iterator_status ret =
-                       BT_NOTIFICATION_ITERATOR_STATUS_OK;
+       struct bt_notification *new_notification = NULL;
 
        *in_range = true;
-       type = bt_notification_get_type(notification);
+       type = bt_notification_get_type(*notification);
        switch (type) {
        case BT_NOTIFICATION_TYPE_EVENT:
-               ret = evaluate_event_notification(notification, begin,
-                               end, in_range);
+               new_notification = evaluate_event_notification(*notification,
+                               trim_it, begin, end, in_range);
                break;
        case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
        case BT_NOTIFICATION_TYPE_PACKET_END:
-               ret = evaluate_packet_notification(notification, begin,
-                               end, in_range);
+               new_notification = evaluate_packet_notification(*notification,
+                               trim_it, begin, end, in_range);
+               break;
+       case BT_NOTIFICATION_TYPE_STREAM_END:
+               new_notification = evaluate_stream_notification(*notification,
+                               trim_it);
                break;
        default:
                /* Accept all other notifications. */
                break;
        }
-       return ret;
+       BT_PUT(*notification);
+       *notification = new_notification;
+
+       return BT_NOTIFICATION_ITERATOR_STATUS_OK;
 }
 
 BT_HIDDEN
@@ -433,11 +584,11 @@ struct bt_notification_iterator_next_return trimmer_iterator_next(
                        goto end;
                }
 
-               ret.status = evaluate_notification(ret.notification,
+               ret.status = evaluate_notification(&ret.notification, trim_it,
                                &trimmer->begin, &trimmer->end,
                                &notification_in_range);
                if (!notification_in_range) {
-                       bt_put(ret.notification);
+                       BT_PUT(ret.notification);
                }
 
                if (ret.status != BT_NOTIFICATION_ITERATOR_STATUS_OK) {
index 3fd99a729f229595ac179f1cc51b344df9592407..3b35dbd46a5bbce01a7ae30680be93bdd21badb8 100644 (file)
 struct trimmer_iterator {
        /* Input iterator associated with this output iterator. */
        struct bt_notification_iterator *input_iterator;
+       struct bt_notification *current_notification;
+       FILE *err;
+       /* Map between reader and writer packets. */
+       GHashTable *packet_map;
 };
 
 BT_HIDDEN
This page took 0.033824 seconds and 4 git commands to generate.