ir: add bt_ctf_event_get_clock_value()
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Tue, 16 Feb 2016 07:23:26 +0000 (02:23 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Mon, 22 Feb 2016 19:46:07 +0000 (14:46 -0500)
This patch adds a hash table of clocks to their current values (in
cycles) to the stream object. bt_ctf_stream_update_clock_value() can
be called to update the registered clock value of a given stream
from the current value of a given integer field, of which the type
is mapped to a clock. The function handles the case where the size of
the field is less than 64 bits and can make the current clock value
wrap once per call.

This patch also adds a similar hash table to the event object.
bt_ctf_event_register_stream_clock_values() is to be called by
internal code to take a snapshot of all the registered clock values
of the event's stream. The copied clock values can be retrieved by
the user later using bt_ctf_event_get_clock_value(), which should
return the value that a given clock had when the event was emitted.

This is intended to be used by sink components since the value
of a clock changes as events are created, whereas it is common
situation to hold an event and later need the clock values when
this event was emitted.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
formats/ctf/ir/event.c
formats/ctf/ir/stream.c
include/babeltrace/ctf-ir/event-internal.h
include/babeltrace/ctf-ir/event.h
include/babeltrace/ctf-ir/stream-internal.h

index 4202b8ff975dbb893ea733891cdcd8fa62697c6d..63769c935b4895279383a5ba236a95beef4c6620 100644 (file)
@@ -33,6 +33,7 @@
 #include <babeltrace/ctf-ir/event-class-internal.h>
 #include <babeltrace/ctf-ir/stream-class.h>
 #include <babeltrace/ctf-ir/stream-class-internal.h>
+#include <babeltrace/ctf-ir/stream-internal.h>
 #include <babeltrace/ctf-ir/packet.h>
 #include <babeltrace/ctf-ir/packet-internal.h>
 #include <babeltrace/ctf-ir/trace-internal.h>
@@ -154,6 +155,8 @@ struct bt_ctf_event *bt_ctf_event_create(struct bt_ctf_event_class *event_class)
         * lifetime.
         */
        event->event_class = bt_get(event_class);
+       event->clock_values = g_hash_table_new_full(g_direct_hash,
+               g_direct_equal, NULL, g_free);
        event_header =
                bt_ctf_field_create(validation_output.event_header_type);
        if (!event_header) {
@@ -568,6 +571,7 @@ void bt_ctf_event_destroy(struct bt_object *obj)
                 */
                bt_put(event->event_class);
        }
+       g_hash_table_destroy(event->clock_values);
        bt_put(event->event_header);
        bt_put(event->stream_event_context);
        bt_put(event->context_payload);
@@ -784,3 +788,58 @@ void bt_ctf_event_freeze(struct bt_ctf_event *event)
        bt_ctf_field_freeze(event->fields_payload);
        event->frozen = 1;
 }
+
+static
+void insert_stream_clock_value_into_event_clock_values(gpointer key,
+               gpointer value,
+               gpointer data)
+{
+       struct bt_ctf_event *event = data;
+       uint64_t *clock_value;
+
+       assert(event);
+
+       /* Copy clock value because it belongs to the hash table */
+       clock_value = g_new0(uint64_t, 1);
+       *clock_value = *((uint64_t *) value);
+
+       /* Insert copy into event clock values */
+       g_hash_table_insert(event->clock_values, key, clock_value);
+}
+
+BT_HIDDEN
+int bt_ctf_event_register_stream_clock_values(struct bt_ctf_event *event)
+{
+       int ret = 0;
+       struct bt_ctf_stream *stream;
+
+       stream = bt_ctf_event_get_stream(event);
+       assert(stream);
+       g_hash_table_remove_all(event->clock_values);
+       g_hash_table_foreach(stream->clock_values,
+               insert_stream_clock_value_into_event_clock_values, event);
+       BT_PUT(stream);
+
+       return ret;
+}
+
+uint64_t bt_ctf_event_get_clock_value(struct bt_ctf_event *event,
+               struct bt_ctf_clock *clock)
+{
+       uint64_t ret = -1ULL;
+       uint64_t *clock_value;
+
+       if (!event || !clock) {
+               goto end;
+       }
+
+       clock_value = g_hash_table_lookup(event->clock_values, clock);
+       if (!clock_value) {
+               goto end;
+       }
+
+       ret = *clock_value;
+
+end:
+       return ret;
+}
index e9ff83e4982e2521b41c4de40b982ab1715cd810..04bd0dfeba207fff347d0b765cc06eab6cf270c7 100644 (file)
@@ -403,6 +403,9 @@ struct bt_ctf_stream *bt_ctf_stream_create(
                if (ret) {
                        goto error;
                }
+
+               stream->clock_values = g_hash_table_new_full(g_direct_hash,
+                       g_direct_equal, NULL, g_free);
        }
 
        /* Add this stream to the trace's streams */
@@ -930,6 +933,11 @@ void bt_ctf_stream_destroy(struct bt_object *obj)
        if (stream->name) {
                g_string_free(stream->name, TRUE);
        }
+
+       if (stream->clock_values) {
+               g_hash_table_destroy(stream->clock_values);
+       }
+
        bt_put(stream->packet_header);
        bt_put(stream->packet_context);
        g_free(stream);
@@ -998,3 +1006,78 @@ const char *bt_ctf_stream_get_name(struct bt_ctf_stream *stream)
 end:
        return name;
 }
+
+BT_HIDDEN
+void bt_ctf_stream_update_clock_value(struct bt_ctf_stream *stream,
+               struct bt_ctf_field *value_field)
+{
+       struct bt_ctf_field_type *value_type = NULL;
+       struct bt_ctf_clock *clock = NULL;
+       uint64_t requested_new_value;
+       uint64_t requested_new_value_mask;
+       uint64_t *cur_value;
+       uint64_t cur_value_masked;
+       int requested_new_value_size;
+       int ret;
+
+       assert(stream);
+       assert(clock);
+       assert(value_field);
+       value_type = bt_ctf_field_get_type(value_field);
+       assert(value_type);
+       clock = bt_ctf_field_type_integer_get_mapped_clock(value_type);
+       assert(clock);
+       requested_new_value_size =
+               bt_ctf_field_type_integer_get_size(value_type);
+       assert(requested_new_value_size > 0);
+       ret = bt_ctf_field_unsigned_integer_get_value(value_field,
+               &requested_new_value);
+       assert(!ret);
+       cur_value = g_hash_table_lookup(stream->clock_values, clock);
+
+       if (!cur_value) {
+               /*
+                * Updating the value of a clock which is not registered
+                * yet, so register it with the new value as its initial
+                * value.
+                */
+               uint64_t *requested_new_value_ptr = g_new0(uint64_t, 1);
+
+               *requested_new_value_ptr = requested_new_value;
+               g_hash_table_insert(stream->clock_values, clock,
+                       requested_new_value_ptr);
+               goto end;
+       }
+
+       /*
+        * Special case for a 64-bit new value, which is the limit
+        * of a clock value as of this version: overwrite the
+        * current value directly.
+        */
+       if (requested_new_value_size == 64) {
+               *cur_value = requested_new_value;
+               goto end;
+       }
+
+       requested_new_value_mask = (1ULL << requested_new_value_size) - 1;
+       cur_value_masked = *cur_value & requested_new_value_mask;
+
+       if (requested_new_value < cur_value_masked) {
+               /*
+                * It looks like a wrap happened on the number of bits
+                * of the requested new value. Assume that the clock
+                * value wrapped only one time.
+                */
+               *cur_value += requested_new_value_mask + 1;
+       }
+
+       /* Clear the low bits of the current clock value */
+       *cur_value &= ~requested_new_value_mask;
+
+       /* Set the low bits of the current clock value */
+       *cur_value |= requested_new_value;
+
+end:
+       bt_put(clock);
+       bt_put(value_type);
+}
index 200e1ab21f68f64275f11a25c4bb3c1ebe0e3d67..cc10f224015034a9bb9484b91f3b82dba6814608 100644 (file)
@@ -46,9 +46,13 @@ struct bt_ctf_event {
        struct bt_ctf_field *stream_event_context;
        struct bt_ctf_field *context_payload;
        struct bt_ctf_field *fields_payload;
+       GHashTable *clock_values; /* Maps clock addresses to (uint64_t *) */
        int frozen;
 };
 
+BT_HIDDEN
+int bt_ctf_event_register_stream_clock_values(struct bt_ctf_event *event);
+
 BT_HIDDEN
 int bt_ctf_event_validate(struct bt_ctf_event *event);
 
index b9d813e4b815f26f6d295d42eaf9e53b808f70a4..840627eaa1745ae02710e43fc6710ddd505b47e1 100644 (file)
@@ -245,6 +245,9 @@ extern int bt_ctf_event_set_stream_event_context(struct bt_ctf_event *event,
 extern int bt_ctf_event_set_packet(struct bt_ctf_event *event,
                struct bt_ctf_packet *packet);
 
+extern uint64_t bt_ctf_event_get_clock_value(struct bt_ctf_event *event,
+               struct bt_ctf_clock *clock);
+
 #ifdef __cplusplus
 }
 #endif
index a39b1529108bfdbd511ab8162a0815f8c9c1548a..dc392f4ad907fce01be034de6d089e7360aa1788 100644 (file)
@@ -47,9 +47,14 @@ struct bt_ctf_stream {
        GString *name;
        struct bt_ctf_field *packet_header;
        struct bt_ctf_field *packet_context;
+       GHashTable *clock_values; /* Maps clock addresses to (uint64_t *) */
 };
 
 BT_HIDDEN
 int bt_ctf_stream_set_fd(struct bt_ctf_stream *stream, int fd);
 
+BT_HIDDEN
+void bt_ctf_stream_update_clock_value(struct bt_ctf_stream *stream,
+               struct bt_ctf_field *value_field);
+
 #endif /* BABELTRACE_CTF_WRITER_STREAM_INTERNAL_H */
This page took 0.028599 seconds and 4 git commands to generate.