From 2ec84d269adb6770ff512a8943e020bd9e9f9ffb Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Thu, 22 Jun 2017 11:20:29 -0400 Subject: [PATCH] Automatically generate discarded packets/events notifications MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This patch adds discarded packets and events notifications. Those notifications are automatically generated by each notification iterator by looking at packet header (PH) field's `packet_seq_num` and packet context (PC) field's `events_discarded` fields to keep track of the current state. Automatically generating those notifications, and forbidding the user to create them, allows them to always be synchronized with the values of the PH and PC special fields, and guarantees to the user that they are generated whenever there is a change in those values. Each notification contains a count, an optional beginning clock value, and an optional ending clock value, as well as a stream in which the elements are discarded by the tracer. As of this patch, flt.utils.trimmer does not reset the value of its copied `packet_seq_num` and `events_discarded` fields to 0, and this is probably a bug because a notification iterator on an flt.utils.trimmer component can see discarded packets or events notifications before the first packet beginning notification (which should not be the case if we consider that a trimmed stream should act like a stream which originally had those time bounds). The sink.text.pretty component does not do anything specific with those new notifications yet, but they are expected to be used to replicate Babeltrace 1's behaviour (printing warnings). Signed-off-by: Philippe Proulx Signed-off-by: Jérémie Galarneau --- include/Makefile.am | 3 + include/babeltrace/babeltrace.h | 2 + ...notification-discarded-elements-internal.h | 85 +++ .../graph/notification-discarded-events.h | 59 ++ .../graph/notification-discarded-packets.h | 59 ++ .../babeltrace/graph/notification-internal.h | 4 + .../graph/notification-iterator-internal.h | 2 + include/babeltrace/graph/notification.h | 20 +- lib/graph/iterator.c | 537 +++++++++++++++++- lib/graph/notification/Makefile.am | 5 +- lib/graph/notification/discarded-elements.c | 228 ++++++++ lib/graph/notification/discarded-events.c | 56 ++ lib/graph/notification/discarded-packets.c | 56 ++ 13 files changed, 1104 insertions(+), 12 deletions(-) create mode 100644 include/babeltrace/graph/notification-discarded-elements-internal.h create mode 100644 include/babeltrace/graph/notification-discarded-events.h create mode 100644 include/babeltrace/graph/notification-discarded-packets.h create mode 100644 lib/graph/notification/discarded-elements.c create mode 100644 lib/graph/notification/discarded-events.c create mode 100644 lib/graph/notification/discarded-packets.c diff --git a/include/Makefile.am b/include/Makefile.am index aeb7cdd8..387ab5e6 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -55,6 +55,8 @@ babeltracegraphinclude_HEADERS = \ babeltrace/graph/component.h \ babeltrace/graph/connection.h \ babeltrace/graph/graph.h \ + babeltrace/graph/notification-discarded-events.h \ + babeltrace/graph/notification-discarded-packets.h \ babeltrace/graph/notification-event.h \ babeltrace/graph/notification-heap.h \ babeltrace/graph/notification-inactivity.h \ @@ -118,6 +120,7 @@ noinst_HEADERS = \ babeltrace/graph/component-source-internal.h \ babeltrace/graph/connection-internal.h \ babeltrace/graph/graph-internal.h \ + babeltrace/graph/notification-discarded-elements-internal.h \ babeltrace/graph/notification-event-internal.h \ babeltrace/graph/notification-heap-internal.h \ babeltrace/graph/notification-inactivity-internal.h \ diff --git a/include/babeltrace/babeltrace.h b/include/babeltrace/babeltrace.h index 36f1b383..7aad9b1c 100644 --- a/include/babeltrace/babeltrace.h +++ b/include/babeltrace/babeltrace.h @@ -75,6 +75,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/include/babeltrace/graph/notification-discarded-elements-internal.h b/include/babeltrace/graph/notification-discarded-elements-internal.h new file mode 100644 index 00000000..1a339ab0 --- /dev/null +++ b/include/babeltrace/graph/notification-discarded-elements-internal.h @@ -0,0 +1,85 @@ +#ifndef BABELTRACE_COMPONENT_NOTIFICATION_DISCARDED_ELEMENTS_INTERNAL_H +#define BABELTRACE_COMPONENT_NOTIFICATION_DISCARDED_ELEMENTS_INTERNAL_H + +/* + * Copyright 2017 Philippe Proulx + * + * 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 +#include +#include +#include +#include + +struct bt_clock_class_priority_map; +struct bt_ctf_stream; + +struct bt_notification_discarded_elements { + struct bt_notification parent; + struct bt_ctf_stream *stream; + struct bt_ctf_clock_value *begin_clock_value; + struct bt_ctf_clock_value *end_clock_value; + int64_t count; +}; + +BT_HIDDEN +struct bt_notification *bt_notification_discarded_elements_create( + enum bt_notification_type type, + struct bt_ctf_stream *stream, + struct bt_ctf_clock_value *begin_clock_value, + struct bt_ctf_clock_value *end_clock_value, + uint64_t count); + +BT_HIDDEN +struct bt_ctf_stream *bt_notification_discarded_elements_get_stream( + enum bt_notification_type type, + struct bt_notification *notification); + +BT_HIDDEN +struct bt_ctf_clock_value * +bt_notification_discarded_elements_get_begin_clock_value( + enum bt_notification_type type, + struct bt_notification *notification); + +BT_HIDDEN +struct bt_ctf_clock_value * +bt_notification_discarded_elements_get_end_clock_value( + enum bt_notification_type type, + struct bt_notification *notification); + +BT_HIDDEN +int64_t bt_notification_discarded_elements_get_count( + enum bt_notification_type type, + struct bt_notification *notification); + +static inline +struct bt_ctf_stream *bt_notification_discarded_elements_borrow_stream( + struct bt_notification *notification) +{ + struct bt_notification_discarded_elements *discarded_elems_notif; + + assert(notification); + discarded_elems_notif = container_of(notification, + struct bt_notification_discarded_elements, parent); + return discarded_elems_notif->stream; +} + +#endif /* BABELTRACE_COMPONENT_NOTIFICATION_DISCARDED_ELEMENTS_INTERNAL_H */ diff --git a/include/babeltrace/graph/notification-discarded-events.h b/include/babeltrace/graph/notification-discarded-events.h new file mode 100644 index 00000000..91151e4f --- /dev/null +++ b/include/babeltrace/graph/notification-discarded-events.h @@ -0,0 +1,59 @@ +#ifndef BABELTRACE_GRAPH_NOTIFICATION_DISCARDED_EVENTS_H +#define BABELTRACE_GRAPH_NOTIFICATION_DISCARDED_EVENTS_H + +/* + * Copyright 2017 Philippe Proulx + * + * 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 + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_notification; +struct bt_clock_class_priority_map; +struct bt_ctf_clock_class; +struct bt_ctf_stream; + +extern struct bt_ctf_clock_value * +bt_notification_discarded_events_get_begin_clock_value( + struct bt_notification *notification); + +extern struct bt_ctf_clock_value * +bt_notification_discarded_events_get_end_clock_value( + struct bt_notification *notification); + +extern int bt_notification_discarded_events_set_count( + struct bt_notification *notification, + uint64_t count); + +extern int64_t bt_notification_discarded_events_get_count( + struct bt_notification *notification); + +extern struct bt_ctf_stream *bt_notification_discarded_events_get_stream( + struct bt_notification *notification); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_GRAPH_NOTIFICATION_DISCARDED_EVENTS_H */ diff --git a/include/babeltrace/graph/notification-discarded-packets.h b/include/babeltrace/graph/notification-discarded-packets.h new file mode 100644 index 00000000..44600816 --- /dev/null +++ b/include/babeltrace/graph/notification-discarded-packets.h @@ -0,0 +1,59 @@ +#ifndef BABELTRACE_GRAPH_NOTIFICATION_DISCARDED_PACKETS_H +#define BABELTRACE_GRAPH_NOTIFICATION_DISCARDED_PACKETS_H + +/* + * Copyright 2017 Philippe Proulx + * + * 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 + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_notification; +struct bt_clock_class_priority_map; +struct bt_ctf_clock_class; +struct bt_ctf_stream; + +extern struct bt_ctf_clock_value * +bt_notification_discarded_packets_get_begin_clock_value( + struct bt_notification *notification); + +extern struct bt_ctf_clock_value * +bt_notification_discarded_packets_get_end_clock_value( + struct bt_notification *notification); + +extern int bt_notification_discarded_packets_set_count( + struct bt_notification *notification, + uint64_t count); + +extern int64_t bt_notification_discarded_packets_get_count( + struct bt_notification *notification); + +extern struct bt_ctf_stream *bt_notification_discarded_packets_get_stream( + struct bt_notification *notification); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_GRAPH_NOTIFICATION_DISCARDED_PACKETS_H */ diff --git a/include/babeltrace/graph/notification-internal.h b/include/babeltrace/graph/notification-internal.h index 00a8c7ee..4ffef1c5 100644 --- a/include/babeltrace/graph/notification-internal.h +++ b/include/babeltrace/graph/notification-internal.h @@ -76,6 +76,10 @@ const char *bt_notification_type_string(enum bt_notification_type type) return "BT_NOTIFICATION_TYPE_PACKET_BEGIN"; case BT_NOTIFICATION_TYPE_PACKET_END: return "BT_NOTIFICATION_TYPE_PACKET_END"; + case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS: + return "BT_NOTIFICATION_TYPE_DISCARDED_EVENTS"; + case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS: + return "BT_NOTIFICATION_TYPE_DISCARDED_PACKETS"; default: return "(unknown)"; } diff --git a/include/babeltrace/graph/notification-iterator-internal.h b/include/babeltrace/graph/notification-iterator-internal.h index b7aafe01..9fcab16a 100644 --- a/include/babeltrace/graph/notification-iterator-internal.h +++ b/include/babeltrace/graph/notification-iterator-internal.h @@ -44,6 +44,8 @@ enum bt_notification_iterator_notif_type { BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END = (1U << 3), BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN = (1U << 4), BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END = (1U << 5), + BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS = (1U << 6), + BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS = (1U << 7), }; enum bt_notification_iterator_state { diff --git a/include/babeltrace/graph/notification.h b/include/babeltrace/graph/notification.h index 926c019f..b64d40ad 100644 --- a/include/babeltrace/graph/notification.h +++ b/include/babeltrace/graph/notification.h @@ -37,15 +37,17 @@ struct bt_notification; * Notification types. Unhandled notification types should be ignored. */ enum bt_notification_type { - BT_NOTIFICATION_TYPE_SENTINEL = -1000, - BT_NOTIFICATION_TYPE_UNKNOWN = -1, - BT_NOTIFICATION_TYPE_ALL = -2, - BT_NOTIFICATION_TYPE_EVENT = 0, - BT_NOTIFICATION_TYPE_INACTIVITY = 1, - BT_NOTIFICATION_TYPE_STREAM_BEGIN = 2, - BT_NOTIFICATION_TYPE_STREAM_END = 3, - BT_NOTIFICATION_TYPE_PACKET_BEGIN = 4, - BT_NOTIFICATION_TYPE_PACKET_END = 5, + BT_NOTIFICATION_TYPE_SENTINEL = -1000, + BT_NOTIFICATION_TYPE_UNKNOWN = -1, + BT_NOTIFICATION_TYPE_ALL = -2, + BT_NOTIFICATION_TYPE_EVENT = 0, + BT_NOTIFICATION_TYPE_INACTIVITY = 1, + BT_NOTIFICATION_TYPE_STREAM_BEGIN = 2, + BT_NOTIFICATION_TYPE_STREAM_END = 3, + BT_NOTIFICATION_TYPE_PACKET_BEGIN = 4, + BT_NOTIFICATION_TYPE_PACKET_END = 5, + BT_NOTIFICATION_TYPE_DISCARDED_EVENTS = 6, + BT_NOTIFICATION_TYPE_DISCARDED_PACKETS = 7, BT_NOTIFICATION_TYPE_NR, /* Not part of ABI. */ }; diff --git a/lib/graph/iterator.c b/lib/graph/iterator.c index 87fe6376..9cc3fbec 100644 --- a/lib/graph/iterator.c +++ b/lib/graph/iterator.c @@ -30,6 +30,9 @@ #include #include +#include +#include +#include #include #include #include @@ -48,14 +51,23 @@ #include #include #include +#include #include #include #include +#include #include +struct discarded_elements_state { + struct bt_ctf_clock_value *cur_begin; + uint64_t cur_count; +}; + struct stream_state { struct bt_ctf_stream *stream; /* owned by this */ struct bt_ctf_packet *cur_packet; /* owned by this */ + struct discarded_elements_state discarded_packets_state; + struct discarded_elements_state discarded_events_state; bt_bool is_ended; }; @@ -65,6 +77,8 @@ enum action_type { ACTION_TYPE_ADD_STREAM_STATE, ACTION_TYPE_SET_STREAM_STATE_IS_ENDED, ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET, + ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS, + ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS, }; struct action { @@ -98,6 +112,14 @@ struct action { struct stream_state *stream_state; /* weak */ struct bt_ctf_packet *packet; /* owned by this */ } set_stream_state_cur_packet; + + /* ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS */ + /* ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS */ + struct { + struct stream_state *stream_state; /* weak */ + struct bt_ctf_clock_value *cur_begin; /* owned by this */ + uint64_t cur_count; + } update_stream_state_discarded_elements; } payload; }; @@ -122,6 +144,8 @@ void destroy_stream_state(struct stream_state *stream_state) bt_put(stream_state->cur_packet); BT_LOGV_STR("Putting stream state's stream."); bt_put(stream_state->stream); + bt_put(stream_state->discarded_packets_state.cur_begin); + bt_put(stream_state->discarded_events_state.cur_begin); g_free(stream_state); } @@ -150,7 +174,12 @@ void destroy_action(struct action *action) break; case ACTION_TYPE_SET_STREAM_STATE_IS_ENDED: break; + case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS: + case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS: + BT_PUT(action->payload.update_stream_state_discarded_elements.cur_begin); + break; default: + BT_LOGF("Unexpected action's type: type=%d", action->type); abort(); } } @@ -191,6 +220,10 @@ const char *action_type_string(enum action_type type) return "ACTION_TYPE_SET_STREAM_STATE_IS_ENDED"; case ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET: return "ACTION_TYPE_SET_STREAM_STATE_CUR_PACKET"; + case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS: + return "ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS"; + case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS: + return "ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS"; default: return "(unknown)"; } @@ -262,7 +295,25 @@ void apply_actions(struct bt_notification_iterator *iterator) BT_MOVE(action->payload.set_stream_state_cur_packet.stream_state->cur_packet, action->payload.set_stream_state_cur_packet.packet); break; + case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS: + case ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS: + { + struct discarded_elements_state *state; + + if (action->type == ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS) { + state = &action->payload.update_stream_state_discarded_elements.stream_state->discarded_packets_state; + } else { + state = &action->payload.update_stream_state_discarded_elements.stream_state->discarded_events_state; + } + + BT_MOVE(state->cur_begin, + action->payload.update_stream_state_discarded_elements.cur_begin); + state->cur_count = action->payload.update_stream_state_discarded_elements.cur_count; + break; + } default: + BT_LOGF("Unexpected action's type: type=%d", + action->type); abort(); } } @@ -478,7 +529,9 @@ int create_subscription_mask_from_notification_types( BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_BEGIN | BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_STREAM_END | BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_BEGIN | - BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END; + BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END | + BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS | + BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS; break; case BT_NOTIFICATION_TYPE_EVENT: iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_EVENT; @@ -498,6 +551,12 @@ int create_subscription_mask_from_notification_types( case BT_NOTIFICATION_TYPE_PACKET_END: iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END; break; + case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS: + iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS; + break; + case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS: + iterator->subscription_mask |= BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS; + break; default: ret = -1; goto end; @@ -674,6 +733,12 @@ bt_notification_iterator_notif_type_from_notif_type( case BT_NOTIFICATION_TYPE_PACKET_END: iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_PACKET_END; break; + case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS: + iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_EVENTS; + break; + case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS: + iter_notif_type = BT_NOTIFICATION_ITERATOR_NOTIF_TYPE_DISCARDED_PACKETS; + break; default: abort(); } @@ -1015,6 +1080,38 @@ void add_action_set_stream_state_cur_packet( stream_state, packet); } +static +void add_action_update_stream_state_discarded_elements( + struct bt_notification_iterator *iterator, + enum action_type type, + struct stream_state *stream_state, + struct bt_ctf_clock_value *cur_begin, + uint64_t cur_count) +{ + struct action action = { + .type = type, + .payload.update_stream_state_discarded_elements = { + .stream_state = stream_state, + .cur_begin = bt_get(cur_begin), + .cur_count = cur_count, + }, + }; + + assert(stream_state); + assert(type == ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS || + type == ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS); + add_action(iterator, &action); + if (type == ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS) { + BT_LOGV("Added \"update stream state's discarded packets\" action: " + "stream-state-addr=%p, cur-begin-addr=%p, cur-count=%" PRIu64, + stream_state, cur_begin, cur_count); + } else if (type == ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS) { + BT_LOGV("Added \"update stream state's discarded events\" action: " + "stream-state-addr=%p, cur-begin-addr=%p, cur-count=%" PRIu64, + stream_state, cur_begin, cur_count); + } +} + static int ensure_stream_state_exists(struct bt_notification_iterator *iterator, struct bt_notification *stream_begin_notif, @@ -1079,6 +1176,377 @@ end: return ret; } +static +struct bt_ctf_field *get_struct_field_uint(struct bt_ctf_field *struct_field, + const char *field_name) +{ + struct bt_ctf_field *field = NULL; + struct bt_ctf_field_type *ft = NULL; + + field = bt_ctf_field_structure_get_field_by_name(struct_field, + field_name); + if (!field) { + BT_LOGV_STR("`%s` field does not exist."); + goto end; + } + + if (!bt_ctf_field_is_integer(field)) { + BT_LOGV("Skipping `%s` field because its type is not an integer field type: " + "field-addr=%p, ft-addr=%p, ft-id=%s", field_name, + field, ft, bt_ctf_field_type_id_string( + bt_ctf_field_type_get_type_id(ft))); + BT_PUT(field); + goto end; + } + + ft = bt_ctf_field_get_type(field); + assert(ft); + + if (bt_ctf_field_type_integer_is_signed(ft)) { + BT_LOGV("Skipping `%s` integer field because its type is signed: " + "field-addr=%p, ft-addr=%p", field_name, field, ft); + BT_PUT(field); + goto end; + } + +end: + bt_put(ft); + return field; +} + +static +uint64_t get_packet_context_events_discarded(struct bt_ctf_packet *packet) +{ + struct bt_ctf_field *packet_context = NULL; + struct bt_ctf_field *field = NULL; + uint64_t retval = -1ULL; + int ret; + + packet_context = bt_ctf_packet_get_context(packet); + if (!packet_context) { + goto end; + } + + field = get_struct_field_uint(packet_context, "events_discarded"); + if (!field) { + BT_LOGV("`events_discarded` field does not exist in packet's context field: " + "packet-addr=%p, packet-context-field-addr=%p", + packet, packet_context); + goto end; + } + + assert(bt_ctf_field_is_integer(field)); + ret = bt_ctf_field_unsigned_integer_get_value(field, &retval); + if (ret) { + BT_LOGV("Cannot get raw value of packet's context field's `events_discarded` integer field: " + "packet-addr=%p, field-addr=%p", + packet, field); + retval = -1ULL; + goto end; + } + +end: + bt_put(packet_context); + bt_put(field); + return retval; +} + +static +uint64_t get_packet_header_packet_seq_num(struct bt_ctf_packet *packet) +{ + struct bt_ctf_field *packet_header = NULL; + struct bt_ctf_field *field = NULL; + uint64_t retval = -1ULL; + int ret; + + packet_header = bt_ctf_packet_get_header(packet); + if (!packet_header) { + goto end; + } + + field = get_struct_field_uint(packet_header, "packet_seq_num"); + if (!field) { + BT_LOGV("`packet_seq_num` field does not exist in packet's header field: " + "packet-addr=%p, packet-header-field-addr=%p", + packet, packet_header); + goto end; + } + + assert(bt_ctf_field_is_integer(field)); + ret = bt_ctf_field_unsigned_integer_get_value(field, &retval); + if (ret) { + BT_LOGV("Cannot get raw value of packet's header field's `packet_seq_num` integer field: " + "packet-addr=%p, field-addr=%p", + packet, field); + retval = -1ULL; + goto end; + } + +end: + bt_put(packet_header); + bt_put(field); + return retval; +} + +static +int handle_discarded_packets(struct bt_notification_iterator *iterator, + struct bt_ctf_packet *packet, + struct bt_ctf_clock_value *ts_begin, + struct bt_ctf_clock_value *ts_end, + struct stream_state *stream_state) +{ + struct bt_notification *notif = NULL; + uint64_t diff; + uint64_t next_count; + int ret = 0; + + next_count = get_packet_header_packet_seq_num(packet); + if (next_count == -1ULL) { + next_count = stream_state->discarded_packets_state.cur_count; + goto update_state; + } + + if (next_count < stream_state->discarded_packets_state.cur_count) { + BT_LOGW("Current value of packet's header field's `packet_seq_num` field is lesser than the previous value for the same stream: " + "not updating the stream state's current value: " + "packet-addr=%p, prev-count=%" PRIu64 ", " + "cur-count=%" PRIu64, + packet, stream_state->discarded_packets_state.cur_count, + next_count); + goto end; + } + + diff = next_count - stream_state->discarded_packets_state.cur_count; + if (diff > 0) { + /* + * Add a discarded packets notification. The packets + * are considered to be lost betweem the state's last time + * and the current packet's beginning time. + */ + notif = bt_notification_discarded_elements_create( + BT_NOTIFICATION_TYPE_DISCARDED_PACKETS, + stream_state->stream, + stream_state->discarded_packets_state.cur_begin, + ts_begin, diff); + if (!notif) { + BT_LOGE_STR("Cannot create discarded packets notification."); + ret = -1; + goto end; + } + + add_action_push_notif(iterator, notif); + } + +update_state: + add_action_update_stream_state_discarded_elements(iterator, + ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_PACKETS, + stream_state, ts_end, next_count); + +end: + bt_put(notif); + return ret; +} + +static +int handle_discarded_events(struct bt_notification_iterator *iterator, + struct bt_ctf_packet *packet, + struct bt_ctf_clock_value *ts_begin, + struct bt_ctf_clock_value *ts_end, + struct stream_state *stream_state) +{ + struct bt_notification *notif = NULL; + uint64_t diff; + uint64_t next_count; + int ret = 0; + + next_count = get_packet_context_events_discarded(packet); + if (next_count == -1ULL) { + next_count = stream_state->discarded_events_state.cur_count; + goto update_state; + } + + if (next_count < stream_state->discarded_events_state.cur_count) { + BT_LOGW("Current value of packet's context field's `events_discarded` field is lesser than the previous value for the same stream: " + "not updating the stream state's current value: " + "packet-addr=%p, prev-count=%" PRIu64 ", " + "cur-count=%" PRIu64, + packet, stream_state->discarded_events_state.cur_count, + next_count); + goto end; + } + + diff = next_count - stream_state->discarded_events_state.cur_count; + if (diff > 0) { + /* + * Add a discarded events notification. The events are + * considered to be lost betweem the state's last time + * and the current packet's end time. + */ + notif = bt_notification_discarded_elements_create( + BT_NOTIFICATION_TYPE_DISCARDED_EVENTS, + stream_state->stream, + stream_state->discarded_events_state.cur_begin, + ts_end, diff); + if (!notif) { + BT_LOGE_STR("Cannot create discarded events notification."); + ret = -1; + goto end; + } + + add_action_push_notif(iterator, notif); + } + +update_state: + add_action_update_stream_state_discarded_elements(iterator, + ACTION_TYPE_UPDATE_STREAM_STATE_DISCARDED_EVENTS, + stream_state, ts_end, next_count); + +end: + bt_put(notif); + return ret; +} + +static +int get_field_clock_value(struct bt_ctf_field *root_field, + const char *field_name, + struct bt_ctf_clock_value **user_clock_val) +{ + struct bt_ctf_field *field; + struct bt_ctf_field_type *ft = NULL; + struct bt_ctf_clock_class *clock_class = NULL; + struct bt_ctf_clock_value *clock_value = NULL; + uint64_t val; + int ret = 0; + + field = get_struct_field_uint(root_field, field_name); + if (!field) { + /* Not an error: skip this */ + goto end; + } + + ft = bt_ctf_field_get_type(field); + assert(ft); + clock_class = bt_ctf_field_type_integer_get_mapped_clock_class(ft); + if (!clock_class) { + BT_LOGW("Integer field type has no mapped clock class but it's expected to have one: " + "ft-addr=%p", ft); + ret = -1; + goto end; + } + + ret = bt_ctf_field_unsigned_integer_get_value(field, &val); + if (ret) { + BT_LOGW("Cannot get integer field's raw value: " + "field-addr=%p", field); + ret = -1; + goto end; + } + + clock_value = bt_ctf_clock_value_create(clock_class, val); + if (!clock_value) { + BT_LOGE_STR("Cannot create clock value from clock class."); + ret = -1; + goto end; + } + + /* Move clock value to user */ + *user_clock_val = clock_value; + clock_value = NULL; + +end: + bt_put(field); + bt_put(ft); + bt_put(clock_class); + bt_put(clock_value); + return ret; +} + +static +int get_ts_begin_ts_end_from_packet(struct bt_ctf_packet *packet, + struct bt_ctf_clock_value **user_ts_begin, + struct bt_ctf_clock_value **user_ts_end) +{ + struct bt_ctf_field *packet_context = NULL; + struct bt_ctf_clock_value *ts_begin = NULL; + struct bt_ctf_clock_value *ts_end = NULL; + int ret = 0; + + packet_context = bt_ctf_packet_get_context(packet); + if (!packet_context) { + goto end; + } + + ret = get_field_clock_value(packet_context, "timestamp_begin", + &ts_begin); + if (ret) { + BT_LOGW("Cannot create clock value for packet context's `timestamp_begin` field: " + "packet-addr=%p, packet-context-field-addr=%p", + packet, packet_context); + goto end; + } + + ret = get_field_clock_value(packet_context, "timestamp_end", + &ts_end); + if (ret) { + BT_LOGW("Cannot create clock value for packet context's `timestamp_begin` field: " + "packet-addr=%p, packet-context-field-addr=%p", + packet, packet_context); + goto end; + } + + /* Move clock values to user */ + *user_ts_begin = ts_begin; + ts_begin = NULL; + *user_ts_end = ts_end; + ts_end = NULL; + +end: + bt_put(packet_context); + bt_put(ts_begin); + bt_put(ts_end); + return ret; +} + +static +int handle_discarded_elements(struct bt_notification_iterator *iterator, + struct bt_ctf_packet *packet, struct stream_state *stream_state) +{ + struct bt_ctf_clock_value *ts_begin = NULL; + struct bt_ctf_clock_value *ts_end = NULL; + int ret; + + ret = get_ts_begin_ts_end_from_packet(packet, &ts_begin, &ts_end); + if (ret) { + BT_LOGW("Cannot get packet's beginning or end clock values: " + "packet-addr=%p, ret=%d", packet, ret); + ret = -1; + goto end; + } + + ret = handle_discarded_packets(iterator, packet, ts_begin, ts_end, + stream_state); + if (ret) { + BT_LOGW("Cannot handle discarded packets for packet: " + "packet-addr=%p, ret=%d", packet, ret); + ret = -1; + goto end; + } + + ret = handle_discarded_events(iterator, packet, ts_begin, ts_end, + stream_state); + if (ret) { + BT_LOGW("Cannot handle discarded events for packet: " + "packet-addr=%p, ret=%d", packet, ret); + ret = -1; + goto end; + } + +end: + bt_put(ts_begin); + bt_put(ts_end); + return ret; +} + static int handle_packet_switch(struct bt_notification_iterator *iterator, struct bt_notification *packet_begin_notif, @@ -1105,6 +1573,17 @@ int handle_packet_switch(struct bt_notification_iterator *iterator, } } + /* + * Check the new packet's header and context fields for + * discarded packets and events to emit those automatic + * notifications. + */ + ret = handle_discarded_elements(iterator, new_packet, stream_state); + if (ret) { + BT_LOGE_STR("Cannot handle discarded elements for new packet."); + goto error; + } + /* Beginning of the new packet */ if (packet_begin_notif) { add_action_push_notif(iterator, packet_begin_notif); @@ -1190,6 +1669,35 @@ end: return ret; } +static +int handle_notif_discarded_elements( + struct bt_notification_iterator *iterator, + struct bt_notification *notif, + struct bt_ctf_stream *notif_stream) +{ + int ret = 0; + struct stream_state *stream_state; + + assert(notif->type == BT_NOTIFICATION_TYPE_DISCARDED_EVENTS || + notif->type == BT_NOTIFICATION_TYPE_DISCARDED_PACKETS); + assert(notif_stream); + ret = ensure_stream_state_exists(iterator, NULL, notif_stream, + &stream_state); + if (ret) { + BT_LOGE_STR("Cannot ensure that stream state exists."); + goto error; + } + + add_action_push_notif(iterator, notif); + goto end; + +error: + ret = -1; + +end: + return ret; +} + static int handle_notif_packet_begin( struct bt_notification_iterator *iterator, @@ -1349,7 +1857,10 @@ int enqueue_notification_and_automatic( * types above are allowed to be returned by a user * component. */ - goto error; + BT_LOGF("Unexpected notification type at this point: " + "notif-addr=%p, notif-type=%s", notif, + bt_notification_type_string(notif->type)); + abort(); } if (notif_packet) { @@ -1392,6 +1903,11 @@ handle_notif: ret = handle_notif_packet_end(iterator, notif, notif_stream, notif_packet); break; + case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS: + case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS: + ret = handle_notif_discarded_elements(iterator, notif, + notif_stream); + break; case BT_NOTIFICATION_TYPE_INACTIVITY: add_action_push_notif(iterator, notif); break; @@ -1616,6 +2132,23 @@ enum bt_notification_iterator_status ensure_queue_has_notifications( goto end; } + /* + * Ignore some notifications which are always + * automatically generated by the notification + * iterator to make sure they have valid values. + */ + switch (next_return.notification->type) { + case BT_NOTIFICATION_TYPE_DISCARDED_PACKETS: + case BT_NOTIFICATION_TYPE_DISCARDED_EVENTS: + BT_LOGV("Ignoring discarded elements notification returned by notification iterator's \"next\" method: " + "notif-type=%s", + bt_notification_type_string(next_return.notification->type)); + BT_PUT(next_return.notification); + continue; + default: + break; + } + /* * We know the notification is valid. Before we * push it to the head of the queue, push the diff --git a/lib/graph/notification/Makefile.am b/lib/graph/notification/Makefile.am index db32a43c..96560c10 100644 --- a/lib/graph/notification/Makefile.am +++ b/lib/graph/notification/Makefile.am @@ -8,4 +8,7 @@ libgraph_notification_la_SOURCES = \ event.c \ stream.c \ heap.c \ - inactivity.c + inactivity.c \ + discarded-events.c \ + discarded-packets.c \ + discarded-elements.c diff --git a/lib/graph/notification/discarded-elements.c b/lib/graph/notification/discarded-elements.c new file mode 100644 index 00000000..ee4e8a59 --- /dev/null +++ b/lib/graph/notification/discarded-elements.c @@ -0,0 +1,228 @@ +/* + * Copyright 2017 Philippe Proulx + * + * 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. + */ + +#define BT_LOG_TAG "NOTIF-DISCARDED" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static +void bt_notification_discarded_elements_destroy(struct bt_object *obj) +{ + struct bt_notification_discarded_elements *notification = + (struct bt_notification_discarded_elements *) obj; + + BT_LOGD("Destroying discarded elements notification: addr=%p", + notification); + BT_LOGD_STR("Putting stream."); + bt_put(notification->stream); + BT_LOGD_STR("Putting beginning clock value."); + bt_put(notification->begin_clock_value); + BT_LOGD_STR("Putting end clock value."); + bt_put(notification->end_clock_value); + g_free(notification); +} + +BT_HIDDEN +struct bt_notification *bt_notification_discarded_elements_create( + enum bt_notification_type type, + struct bt_ctf_stream *stream, + struct bt_ctf_clock_value *begin_clock_value, + struct bt_ctf_clock_value *end_clock_value, + uint64_t count) +{ + struct bt_notification_discarded_elements *notification; + struct bt_notification *ret_notif = NULL; + + if (!stream) { + BT_LOGW_STR("Invalid parameter: stream is NULL."); + } + + BT_LOGD("Creating discarded elements notification object: " + "type=%s, stream-addr=%p, stream-name=\"%s\", " + "begin-clock-value-addr=%p, end-clock-value-addr=%p, " + "count=%" PRIu64, + bt_notification_type_string(type), stream, + bt_ctf_stream_get_name(stream), begin_clock_value, + end_clock_value, count); + notification = g_new0(struct bt_notification_discarded_elements, 1); + if (!notification) { + BT_LOGE_STR("Failed to allocate one discarded elements notification."); + goto error; + } + + bt_notification_init(¬ification->parent, type, + bt_notification_discarded_elements_destroy); + ret_notif = ¬ification->parent; + notification->stream = bt_get(stream); + notification->begin_clock_value = bt_get(begin_clock_value); + notification->end_clock_value = bt_get(end_clock_value); + notification->count = (int64_t) count; + BT_LOGD("Created discarded elements notification object: " + "type=%s, stream-addr=%p, stream-name=\"%s\", " + "begin-clock-value-addr=%p, end-clock-value-addr=%p, " + "count=%" PRIu64 ", addr=%p", + bt_notification_type_string(type), stream, + bt_ctf_stream_get_name(stream), begin_clock_value, + end_clock_value, count, ret_notif); + goto end; + +error: + BT_PUT(ret_notif); + +end: + return ret_notif; +} + +BT_HIDDEN +struct bt_ctf_clock_value * +bt_notification_discarded_elements_get_begin_clock_value( + enum bt_notification_type type, + struct bt_notification *notification) +{ + struct bt_ctf_clock_value *clock_value = NULL; + struct bt_notification_discarded_elements *discarded_elems_notif; + + if (!notification) { + BT_LOGW_STR("Invalid parameter: notification is NULL."); + goto end; + } + + if (bt_notification_get_type(notification) != + BT_NOTIFICATION_TYPE_DISCARDED_EVENTS) { + BT_LOGW("Invalid parameter: notification has not the expected type: " + "addr%p, expected-type=%s, notif-type=%s", + notification, bt_notification_type_string(type), + bt_notification_type_string( + bt_notification_get_type(notification))); + goto end; + } + + discarded_elems_notif = container_of(notification, + struct bt_notification_discarded_elements, parent); + clock_value = bt_get(discarded_elems_notif->begin_clock_value); + +end: + return clock_value; +} + +BT_HIDDEN +struct bt_ctf_clock_value * +bt_notification_discarded_elements_get_end_clock_value( + enum bt_notification_type type, + struct bt_notification *notification) +{ + struct bt_ctf_clock_value *clock_value = NULL; + struct bt_notification_discarded_elements *discarded_elems_notif; + + if (!notification) { + BT_LOGW_STR("Invalid parameter: notification is NULL."); + goto end; + } + + if (bt_notification_get_type(notification) != + BT_NOTIFICATION_TYPE_DISCARDED_EVENTS) { + BT_LOGW("Invalid parameter: notification has not the expected type: " + "addr%p, expected-type=%s, notif-type=%s", + notification, bt_notification_type_string(type), + bt_notification_type_string( + bt_notification_get_type(notification))); + goto end; + } + + discarded_elems_notif = container_of(notification, + struct bt_notification_discarded_elements, parent); + clock_value = bt_get(discarded_elems_notif->end_clock_value); + +end: + return clock_value; +} + +BT_HIDDEN +int64_t bt_notification_discarded_elements_get_count( + enum bt_notification_type type, + struct bt_notification *notification) +{ + int64_t count = (int64_t) -1; + struct bt_notification_discarded_elements *discarded_elems_notif; + + if (!notification) { + BT_LOGW_STR("Invalid parameter: notification is NULL."); + goto end; + } + + if (bt_notification_get_type(notification) != + BT_NOTIFICATION_TYPE_DISCARDED_EVENTS) { + BT_LOGW("Invalid parameter: notification has not the expected type: " + "addr%p, expected-type=%s, notif-type=%s", + notification, bt_notification_type_string(type), + bt_notification_type_string( + bt_notification_get_type(notification))); + goto end; + } + + discarded_elems_notif = container_of(notification, + struct bt_notification_discarded_elements, parent); + count = discarded_elems_notif->count; + +end: + return count; +} + +BT_HIDDEN +struct bt_ctf_stream *bt_notification_discarded_elements_get_stream( + enum bt_notification_type type, + struct bt_notification *notification) +{ + struct bt_ctf_stream *stream = NULL; + struct bt_notification_discarded_elements *discarded_elems_notif; + + if (!notification) { + BT_LOGW_STR("Invalid parameter: notification is NULL."); + goto end; + } + + if (bt_notification_get_type(notification) != + BT_NOTIFICATION_TYPE_DISCARDED_EVENTS) { + BT_LOGW("Invalid parameter: notification has not the expected type: " + "addr%p, expected-type=%s, notif-type=%s", + notification, bt_notification_type_string(type), + bt_notification_type_string( + bt_notification_get_type(notification))); + goto end; + } + + discarded_elems_notif = container_of(notification, + struct bt_notification_discarded_elements, parent); + stream = bt_get(discarded_elems_notif->stream); + +end: + return stream; +} diff --git a/lib/graph/notification/discarded-events.c b/lib/graph/notification/discarded-events.c new file mode 100644 index 00000000..e6189231 --- /dev/null +++ b/lib/graph/notification/discarded-events.c @@ -0,0 +1,56 @@ +/* + * Copyright 2017 Philippe Proulx + * + * 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 +#include +#include +#include + +struct bt_ctf_clock_value * +bt_notification_discarded_events_get_begin_clock_value( + struct bt_notification *notification) +{ + return bt_notification_discarded_elements_get_begin_clock_value( + BT_NOTIFICATION_TYPE_DISCARDED_EVENTS, notification); +} + +struct bt_ctf_clock_value * +bt_notification_discarded_events_get_end_clock_value( + struct bt_notification *notification) +{ + return bt_notification_discarded_elements_get_end_clock_value( + BT_NOTIFICATION_TYPE_DISCARDED_EVENTS, notification); +} + +int64_t bt_notification_discarded_events_get_count( + struct bt_notification *notification) +{ + return bt_notification_discarded_elements_get_count( + BT_NOTIFICATION_TYPE_DISCARDED_EVENTS, notification); +} + +struct bt_ctf_stream *bt_notification_discarded_events_get_stream( + struct bt_notification *notification) +{ + return bt_notification_discarded_elements_get_stream( + BT_NOTIFICATION_TYPE_DISCARDED_EVENTS, notification); +} diff --git a/lib/graph/notification/discarded-packets.c b/lib/graph/notification/discarded-packets.c new file mode 100644 index 00000000..0425a346 --- /dev/null +++ b/lib/graph/notification/discarded-packets.c @@ -0,0 +1,56 @@ +/* + * Copyright 2017 Philippe Proulx + * + * 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 +#include +#include +#include + +struct bt_ctf_clock_value * +bt_notification_discarded_packets_get_begin_clock_value( + struct bt_notification *notification) +{ + return bt_notification_discarded_elements_get_begin_clock_value( + BT_NOTIFICATION_TYPE_DISCARDED_PACKETS, notification); +} + +struct bt_ctf_clock_value * +bt_notification_discarded_packets_get_end_clock_value( + struct bt_notification *notification) +{ + return bt_notification_discarded_elements_get_end_clock_value( + BT_NOTIFICATION_TYPE_DISCARDED_PACKETS, notification); +} + +int64_t bt_notification_discarded_packets_get_count( + struct bt_notification *notification) +{ + return bt_notification_discarded_elements_get_count( + BT_NOTIFICATION_TYPE_DISCARDED_PACKETS, notification); +} + +struct bt_ctf_stream *bt_notification_discarded_packets_get_stream( + struct bt_notification *notification) +{ + return bt_notification_discarded_elements_get_stream( + BT_NOTIFICATION_TYPE_DISCARDED_PACKETS, notification); +} -- 2.34.1