ir: add bt_ctf_clock_class object, modify bt_ctf_clock object
[babeltrace.git] / plugins / trimmer / iterator.c
index 44a58e43934173c800efbf4f18349b5e8ffee23b..e4213f47f7ddced5eb1bb11aca800b7b09fe1f1e 100644 (file)
 #include <babeltrace/ctf-ir/event.h>
 #include <babeltrace/ctf-ir/stream.h>
 #include <babeltrace/ctf-ir/stream-class.h>
-#include <babeltrace/ctf-ir/clock.h>
+#include <babeltrace/ctf-ir/clock-class.h>
 #include <babeltrace/ctf-ir/packet.h>
 #include <babeltrace/ctf-ir/trace.h>
+#include <babeltrace/ctf-ir/fields.h>
 #include <assert.h>
 
 static
@@ -54,9 +55,6 @@ void trimmer_iterator_destroy(struct bt_notification_iterator *it)
                g_ptr_array_free(it_data->input_iterator_group, TRUE);
        }
        bt_put(it_data->current_notification);
-       if (it_data->stream_to_packet_start_notification) {
-               g_hash_table_destroy(it_data->stream_to_packet_start_notification);
-       }
        g_free(it_data);
 }
 
@@ -131,123 +129,291 @@ end:
        return bt_get(trim_it->current_notification);
 }
 
-/*
- * Remove me. This is a temporary work-around due to our inhability to use
- * libbabeltrace-ctf from libbabeltrace-plugin.
- */
 static
-struct bt_ctf_stream *internal_bt_notification_get_stream(
-               struct bt_notification *notification)
+int update_lazy_bound(struct trimmer_bound *bound, const char *name,
+               int64_t ts, bool *lazy_update)
 {
-       struct bt_ctf_stream *stream = NULL;
-
-       assert(notification);
-       switch (bt_notification_get_type(notification)) {
-       case BT_NOTIFICATION_TYPE_EVENT:
-       {
-               struct bt_ctf_event *event;
-
-               event = bt_notification_event_get_event(notification);
-               stream = bt_ctf_event_get_stream(event);
-               bt_put(event);
-               break;
-       }
-       case BT_NOTIFICATION_TYPE_PACKET_START:
-       {
-               struct bt_ctf_packet *packet;
+       struct tm tm;
+       int64_t value;
+       time_t timeval;
 
-               packet = bt_notification_packet_start_get_packet(notification);
-               stream = bt_ctf_packet_get_stream(packet);
-               bt_put(packet);
-               break;
-       }
-       case BT_NOTIFICATION_TYPE_PACKET_END:
-       {
-               struct bt_ctf_packet *packet;
+       *lazy_update = false;
 
-               packet = bt_notification_packet_end_get_packet(notification);
-               stream = bt_ctf_packet_get_stream(packet);
-               bt_put(packet);
-               break;
+       if (!bound->lazy) {
+               return 0;
        }
-       case BT_NOTIFICATION_TYPE_STREAM_END:
-               stream = bt_notification_stream_end_get_stream(notification);
-               break;
-       default:
-               goto end;
+       tm.tm_isdst = -1;
+       timeval = ts / NSEC_PER_SEC;
+
+       if (bound->lazy_values.gmt) {
+               /* Get day, month, year. */
+               if (!gmtime_r(&timeval, &tm)) {
+                       printf_error("Failure in gmtime_r()");
+                       goto error;
+               }
+               tm.tm_sec = bound->lazy_values.ss;
+               tm.tm_min = bound->lazy_values.mm;
+               tm.tm_hour = bound->lazy_values.hh;
+               timeval = timegm(&tm);
+               if (timeval < 0) {
+                       printf_error("Failure in timegm(), incorrectly formatted %s timestamp",
+                                       name);
+                       goto error;
+               }
+       } else {
+               /* Get day, month, year. */
+               if (!localtime_r(&timeval, &tm)) {
+                       printf_error("Failure in localtime_r()");
+                       goto error;
+               }
+               tm.tm_sec = bound->lazy_values.ss;
+               tm.tm_min = bound->lazy_values.mm;
+               tm.tm_hour = bound->lazy_values.hh;
+               timeval = mktime(&tm);
+               if (timeval < 0) {
+                       printf_error("Failure in mktime(), incorrectly formatted %s timestamp",
+                               name);
+                       goto error;
+               }
        }
-end:
-       return stream;
+       value = (int64_t) timeval;
+       value *= NSEC_PER_SEC;
+       value += bound->lazy_values.ns;
+       bound->value = value;
+       bound->set = true;
+       bound->lazy = false;
+       *lazy_update = true;
+       return 0;
+
+error:
+       return -1;
 }
 
-/* Return true if the notification should be forwarded. */
 static
-bool evaluate_notification(struct bt_notification *notification,
-               struct trimmer *trimmer, struct trimmer_iterator *it)
+enum bt_notification_iterator_status
+evaluate_event_notification(struct bt_notification *notification,
+               struct trimmer_bound *begin, struct trimmer_bound *end,
+               bool *_event_in_range)
 {
-       bool ret = true;
-       struct bt_ctf_clock *clock = NULL;
-       enum bt_notification_type type;
+       int64_t ts;
+       int clock_ret;
+       struct bt_ctf_event *event = NULL;
+       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;
 
-       stream = internal_bt_notification_get_stream(notification);
-       if (!stream) {
-               goto end;
-       }
+       event = bt_notification_event_get_event(notification);
+       assert(event);
+
+       stream = bt_ctf_event_get_stream(event);
+       assert(stream);
 
        stream_class = bt_ctf_stream_get_class(stream);
        assert(stream_class);
+
        trace = bt_ctf_stream_class_get_trace(stream_class);
        assert(trace);
 
-       type = bt_notification_get_type(notification);
-       switch (type) {
-       case BT_NOTIFICATION_TYPE_EVENT:
-       {
-               int64_t ts;
-               int clock_ret;
-               struct bt_ctf_event *event;
+       /* FIXME multi-clock? */
+       clock_class = bt_ctf_trace_get_clock_class(trace, 0);
+       if (!clock_class) {
+               goto end;
+       }
 
-               clock = bt_ctf_trace_get_clock(trace, 0);
-               if (!clock) {
-                       goto end;
-               }
+       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;
+       }
 
-               event = bt_notification_event_get_event(notification);
-               assert(event);
-               clock_value = bt_ctf_event_get_clock_value(event, clock);
-               if (!clock_value) {
-                       printf_error("Failed to retrieve clock value\n");
-                       bt_put(event);
+       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;
+       }
+       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;
                }
+       }
+       if (begin->set && ts < begin->value) {
+               in_range = false;
+       }
+       if (end->set && ts > end->value) {
+               in_range = false;
+       }
+end:
+       bt_put(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;
+}
+
+static
+int ns_from_integer_field(struct bt_ctf_field *integer, int64_t *ns)
+{
+       int ret = 0;
+       int is_signed;
+       uint64_t raw_clock_value;
+       struct bt_ctf_field_type *integer_type = NULL;
+       struct bt_ctf_clock_class *clock_class = NULL;
+       struct bt_ctf_clock_value *clock_value = NULL;
+
+       integer_type = bt_ctf_field_get_type(integer);
+       assert(integer_type);
+       clock_class = bt_ctf_field_type_integer_get_mapped_clock_class(
+               integer_type);
+       if (!clock_class) {
+               ret = -1;
+               goto end;
+       }
 
-               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\n");
+       is_signed = bt_ctf_field_type_integer_get_signed(integer_type);
+       if (!is_signed) {
+               ret = bt_ctf_field_unsigned_integer_get_value(integer,
+                               &raw_clock_value);
+               if (ret) {
                        goto end;
                }
+       } else {
+               /* Signed clock values are unsupported. */
+               goto end;
+       }
 
-               if (trimmer->begin.set && ts < trimmer->begin.value) {
-                       ret = false;
-               }
-               if (trimmer->end.set && ts > trimmer->end.value) {
-                       ret = false;
-               }
-               break;
+       clock_value = bt_ctf_clock_value_create(clock_class, raw_clock_value);
+        if (!clock_value) {
+               goto end;
        }
+
+       ret = bt_ctf_clock_value_get_value_ns_from_epoch(clock_value, ns);
+end:
+       bt_put(integer_type);
+       bt_put(clock_class);
+       bt_put(clock_value);
+       return ret;
+}
+
+static
+enum bt_notification_iterator_status evaluate_packet_notification(
+               struct bt_notification *notification,
+               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_field *packet_context = NULL,
+                       *timestamp_begin = NULL,
+                       *timestamp_end = NULL;
+
+        switch (bt_notification_get_type(notification)) {
+       case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
+               packet = bt_notification_packet_begin_get_packet(notification);
+               break;
+       case BT_NOTIFICATION_TYPE_PACKET_END:
+               packet = bt_notification_packet_end_get_packet(notification);
+               break;
        default:
                break;
        }
+       assert(packet);
+
+       packet_context = bt_ctf_packet_get_context(packet);
+       if (!packet_context) {
+               goto end;
+       }
+
+       if (!bt_ctf_field_is_structure(packet_context)) {
+               goto end;
+       }
+
+       timestamp_begin = bt_ctf_field_structure_get_field(
+                       packet_context, "timestamp_begin");
+       if (!timestamp_begin || !bt_ctf_field_is_integer(timestamp_begin)) {
+               goto end;
+       }
+       timestamp_end = bt_ctf_field_structure_get_field(
+                       packet_context, "timestamp_end");
+       if (!timestamp_end || !bt_ctf_field_is_integer(timestamp_end)) {
+               goto end;
+       }
+
+       if (ns_from_integer_field(timestamp_begin, &pkt_begin_ns)) {
+               goto end;
+       }
+       if (ns_from_integer_field(timestamp_end, &pkt_end_ns)) {
+               goto end;
+       }
+
+       begin_ns = begin->set ? begin->value : INT64_MIN;
+       end_ns = end->set ? end->value : INT64_MAX;
+
+       /*
+        * Accept if there is any overlap between the selected region and the
+        * packet.
+        */
+       in_range = (pkt_end_ns >= begin_ns) && (pkt_begin_ns <= end_ns);
 end:
-       bt_put(clock);
-       bt_put(trace);
-       bt_put(stream);
-       bt_put(clock_value);
+       *_packet_in_range = in_range;
+       bt_put(packet);
+       bt_put(packet_context);
+       bt_put(timestamp_begin);
+       bt_put(timestamp_end);
+       return ret;
+}
+
+/* Return true if the notification should be forwarded. */
+static
+enum bt_notification_iterator_status evaluate_notification(
+               struct bt_notification *notification,
+               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;
+
+       *in_range = true;
+       type = bt_notification_get_type(notification);
+       switch (type) {
+       case BT_NOTIFICATION_TYPE_EVENT:
+               ret = evaluate_event_notification(notification, 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);
+               break;
+       default:
+               /* Accept all other notifications. */
+               break;
+       }
        return ret;
 }
 
@@ -260,9 +426,9 @@ enum bt_notification_iterator_status trimmer_iterator_next(
        struct trimmer *trimmer = NULL;
        struct bt_notification_iterator *source_it = NULL;
        enum bt_notification_iterator_status ret =
-                       BT_NOTIFICATION_ITERATOR_STATUS_OK;;
+                       BT_NOTIFICATION_ITERATOR_STATUS_OK;
        enum bt_component_status component_ret;
-       bool event_in_range = false;
+       bool notification_in_range = false;
 
        trim_it = bt_notification_iterator_get_private_data(iterator);
        assert(trim_it);
@@ -277,7 +443,7 @@ enum bt_notification_iterator_status trimmer_iterator_next(
                        &source_it);
        assert((component_ret == BT_COMPONENT_STATUS_OK) && source_it);
 
-       while (!event_in_range) {
+       while (!notification_in_range) {
                struct bt_notification *notification;
 
                ret = bt_notification_iterator_next(source_it);
@@ -292,13 +458,18 @@ enum bt_notification_iterator_status trimmer_iterator_next(
                        goto end;
                }
 
-               event_in_range = evaluate_notification(notification, trimmer,
-                               trim_it);
-               if (event_in_range) {
+               ret = evaluate_notification(notification,
+                               &trimmer->begin, &trimmer->end,
+                               &notification_in_range);
+               if (notification_in_range) {
                        BT_MOVE(trim_it->current_notification, notification);
                } else {
                        bt_put(notification);
                }
+
+               if (ret != BT_NOTIFICATION_ITERATOR_STATUS_OK) {
+                       break;
+               }
        }
 end:
        bt_put(source_it);
This page took 0.050606 seconds and 4 git commands to generate.