X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=plugins%2Ftrimmer%2Fiterator.c;h=e4213f47f7ddced5eb1bb11aca800b7b09fe1f1e;hb=ac0c6bddcdde51dcbb46fc73c61d4f2330774451;hp=44a58e43934173c800efbf4f18349b5e8ffee23b;hpb=44d3cbf0a1e9a9911cb1aa511ee2f49c270e2327;p=babeltrace.git diff --git a/plugins/trimmer/iterator.c b/plugins/trimmer/iterator.c index 44a58e43..e4213f47 100644 --- a/plugins/trimmer/iterator.c +++ b/plugins/trimmer/iterator.c @@ -37,9 +37,10 @@ #include #include #include -#include +#include #include #include +#include #include 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, + ¬ification_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);