multihandlesink: Use the monotonic clock for detecting timeouts and connection durations

Otherwise real-time clock changes can wrongly trigger timeouts, or not
cause timeouts to happen in time.

Unfortunately real-time clock times still have to be kept track inside
the elements for the statistics. Switching those over to the monotonic
clock would cause behaviour changes from the application point of view.

The statistics are extended with fields with monotonic times though.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/1137>
This commit is contained in:
Sebastian Dröge 2021-05-04 18:09:07 +03:00 committed by GStreamer Marge Bot
parent 26b8a96b84
commit 5a65f5f3b7
4 changed files with 36 additions and 17 deletions

View file

@ -671,7 +671,7 @@ gst_multi_fd_sink_handle_client_write (GstMultiFdSink * sink,
{
gboolean more;
gboolean flushing;
GstClockTime now;
GstClockTime now, now_monotonic;
GstMultiHandleSink *mhsink = GST_MULTI_HANDLE_SINK (sink);
GstMultiHandleSinkClass *mhsinkclass =
GST_MULTI_HANDLE_SINK_GET_CLASS (mhsink);
@ -685,6 +685,7 @@ gst_multi_fd_sink_handle_client_write (GstMultiFdSink * sink,
gint maxsize;
now = g_get_real_time () * GST_USECOND;
now_monotonic = g_get_monotonic_time () * GST_USECOND;
if (!mhclient->sending) {
/* client is not working on a buffer */
@ -811,6 +812,7 @@ gst_multi_fd_sink_handle_client_write (GstMultiFdSink * sink,
/* update stats */
mhclient->bytes_sent += wrote;
mhclient->last_activity_time = now;
mhclient->last_activity_time_monotonic = now_monotonic;
mhsink->bytes_served += wrote;
}
}
@ -903,7 +905,7 @@ gst_multi_fd_sink_handle_clients (GstMultiFdSink * sink)
if (G_UNLIKELY (result == 0)) {
GstClockTime now;
now = g_get_real_time () * GST_USECOND;
now = g_get_monotonic_time () * GST_USECOND;
CLIENTS_LOCK (mhsink);
for (clients = mhsink->clients; clients; clients = next) {
@ -914,7 +916,7 @@ gst_multi_fd_sink_handle_clients (GstMultiFdSink * sink)
mhclient = (GstMultiHandleClient *) client;
next = g_list_next (clients);
if (mhsink->timeout > 0
&& now - mhclient->last_activity_time > mhsink->timeout) {
&& now - mhclient->last_activity_time_monotonic > mhsink->timeout) {
mhclient->status = GST_CLIENT_STATUS_SLOW;
gst_multi_handle_sink_remove_client_link (mhsink, clients);
}

View file

@ -543,9 +543,12 @@ gst_multi_handle_sink_client_init (GstMultiHandleClient * client,
/* update start time */
client->connect_time = g_get_real_time () * GST_USECOND;
client->connect_time_monotonic = g_get_monotonic_time () * GST_USECOND;
client->disconnect_time = 0;
client->disconnect_time_monotonic = 0;
/* set last activity time to connect time */
client->last_activity_time = client->connect_time;
client->last_activity_time_monotonic = client->connect_time_monotonic;
}
static void
@ -807,21 +810,28 @@ gst_multi_handle_sink_get_stats (GstMultiHandleSink * sink,
result = gst_structure_new_empty ("multihandlesink-stats");
if (mhclient->disconnect_time == 0) {
interval = (g_get_real_time () * GST_USECOND) - mhclient->connect_time;
if (mhclient->disconnect_time_monotonic == 0) {
interval =
(g_get_monotonic_time () * GST_USECOND) -
mhclient->connect_time_monotonic;
} else {
interval = mhclient->disconnect_time - mhclient->connect_time;
interval =
mhclient->disconnect_time_monotonic -
mhclient->connect_time_monotonic;
}
gst_structure_set (result,
"bytes-sent", G_TYPE_UINT64, mhclient->bytes_sent,
"connect-time", G_TYPE_UINT64, mhclient->connect_time,
"disconnect-time", G_TYPE_UINT64, mhclient->disconnect_time,
"connect-duration", G_TYPE_UINT64, interval,
"last-activity-time", G_TYPE_UINT64, mhclient->last_activity_time,
"buffers-dropped", G_TYPE_UINT64, mhclient->dropped_buffers,
"first-buffer-ts", G_TYPE_UINT64, mhclient->first_buffer_ts,
"last-buffer-ts", G_TYPE_UINT64, mhclient->last_buffer_ts, NULL);
"connect-time-monotonic", G_TYPE_UINT64,
mhclient->connect_time_monotonic, "disconnect-time", G_TYPE_UINT64,
mhclient->disconnect_time, "disconnect-time-monotonic", G_TYPE_UINT64,
mhclient->disconnect_time_monotonic, "connect-duration", G_TYPE_UINT64,
interval, "last-activity-time-monotonic", G_TYPE_UINT64,
mhclient->last_activity_time_monotonic, "buffers-dropped",
G_TYPE_UINT64, mhclient->dropped_buffers, "first-buffer-ts",
G_TYPE_UINT64, mhclient->first_buffer_ts, "last-buffer-ts",
G_TYPE_UINT64, mhclient->last_buffer_ts, NULL);
}
noclient:
@ -891,6 +901,7 @@ gst_multi_handle_sink_remove_client_link (GstMultiHandleSink * sink,
mhsinkclass->hash_removing (sink, mhclient);
mhclient->disconnect_time = g_get_real_time () * GST_USECOND;
mhclient->disconnect_time_monotonic = g_get_monotonic_time () * GST_USECOND;
/* free client buffers */
g_slist_foreach (mhclient->sending, (GFunc) gst_mini_object_unref, NULL);
@ -1652,7 +1663,7 @@ gst_multi_handle_sink_queue_buffer (GstMultiHandleSink * mhsink,
}
max_buffer_usage = 0;
now = g_get_real_time () * GST_USECOND;
now = g_get_monotonic_time () * GST_USECOND;
/* now check for new or slow clients */
restart:
@ -1670,7 +1681,8 @@ restart:
/* check hard max and timeout, remove client */
if ((max_buffers > 0 && mhclient->bufpos >= max_buffers) ||
(mhsink->timeout > 0
&& now - mhclient->last_activity_time > mhsink->timeout)) {
&& now - mhclient->last_activity_time_monotonic >
mhsink->timeout)) {
/* remove client */
GST_WARNING_OBJECT (sink, "%s client %p is too slow, removing",
mhclient->debug, mhclient);

View file

@ -163,8 +163,11 @@ typedef struct {
/* stats */
guint64 bytes_sent;
guint64 connect_time;
guint64 connect_time_monotonic;
guint64 disconnect_time;
guint64 disconnect_time_monotonic;
guint64 last_activity_time;
guint64 last_activity_time_monotonic;
guint64 dropped_buffers;
guint64 avg_queue_size;
guint64 first_buffer_ts;

View file

@ -825,7 +825,7 @@ gst_multi_socket_sink_handle_client_write (GstMultiSocketSink * sink,
{
gboolean more;
gboolean flushing;
GstClockTime now;
GstClockTime now, now_monotonic;
GError *err = NULL;
GstMultiHandleSink *mhsink = GST_MULTI_HANDLE_SINK (sink);
GstMultiHandleClient *mhclient = (GstMultiHandleClient *) client;
@ -834,6 +834,7 @@ gst_multi_socket_sink_handle_client_write (GstMultiSocketSink * sink,
now = g_get_real_time () * GST_USECOND;
now_monotonic = g_get_monotonic_time () * GST_USECOND;
flushing = mhclient->status == GST_CLIENT_STATUS_FLUSHING;
@ -951,6 +952,7 @@ gst_multi_socket_sink_handle_client_write (GstMultiSocketSink * sink,
/* update stats */
mhclient->bytes_sent += wrote;
mhclient->last_activity_time = now;
mhclient->last_activity_time_monotonic = now_monotonic;
mhsink->bytes_served += wrote;
}
}
@ -1115,7 +1117,7 @@ gst_multi_socket_sink_timeout (GstMultiSocketSink * sink)
GList *clients;
GstMultiHandleSink *mhsink = GST_MULTI_HANDLE_SINK (sink);
now = g_get_real_time () * GST_USECOND;
now = g_get_monotonic_time () * GST_USECOND;
CLIENTS_LOCK (mhsink);
for (clients = mhsink->clients; clients; clients = clients->next) {
@ -1125,7 +1127,7 @@ gst_multi_socket_sink_timeout (GstMultiSocketSink * sink)
client = clients->data;
mhclient = (GstMultiHandleClient *) client;
if (mhsink->timeout > 0
&& now - mhclient->last_activity_time > mhsink->timeout) {
&& now - mhclient->last_activity_time_monotonic > mhsink->timeout) {
mhclient->status = GST_CLIENT_STATUS_SLOW;
gst_multi_handle_sink_remove_client_link (mhsink, clients);
}