From 41ac640a35c8f7ec7ffdb1d069180315533e7353 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Tue, 16 Feb 2016 02:23:26 -0500 Subject: [PATCH] ir: add bt_ctf_event_get_clock_value() MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Jérémie Galarneau --- formats/ctf/ir/event.c | 59 +++++++++++++++ formats/ctf/ir/stream.c | 83 +++++++++++++++++++++ include/babeltrace/ctf-ir/event-internal.h | 4 + include/babeltrace/ctf-ir/event.h | 3 + include/babeltrace/ctf-ir/stream-internal.h | 5 ++ 5 files changed, 154 insertions(+) diff --git a/formats/ctf/ir/event.c b/formats/ctf/ir/event.c index 4202b8ff..63769c93 100644 --- a/formats/ctf/ir/event.c +++ b/formats/ctf/ir/event.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -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; +} diff --git a/formats/ctf/ir/stream.c b/formats/ctf/ir/stream.c index e9ff83e4..04bd0dfe 100644 --- a/formats/ctf/ir/stream.c +++ b/formats/ctf/ir/stream.c @@ -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); +} diff --git a/include/babeltrace/ctf-ir/event-internal.h b/include/babeltrace/ctf-ir/event-internal.h index 200e1ab2..cc10f224 100644 --- a/include/babeltrace/ctf-ir/event-internal.h +++ b/include/babeltrace/ctf-ir/event-internal.h @@ -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); diff --git a/include/babeltrace/ctf-ir/event.h b/include/babeltrace/ctf-ir/event.h index b9d813e4..840627ea 100644 --- a/include/babeltrace/ctf-ir/event.h +++ b/include/babeltrace/ctf-ir/event.h @@ -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 diff --git a/include/babeltrace/ctf-ir/stream-internal.h b/include/babeltrace/ctf-ir/stream-internal.h index a39b1529..dc392f4a 100644 --- a/include/babeltrace/ctf-ir/stream-internal.h +++ b/include/babeltrace/ctf-ir/stream-internal.h @@ -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 */ -- 2.34.1