[Spice-devel] [spice-gtk PATCH v2] spice-channel: check message queue length
Victor Toso
lists at victortoso.com
Mon Oct 12 01:51:01 PDT 2015
CC hans about this one as well.
Btw, this was tested on windows client (related to rhbz#1201387) and it
seems to improve well.
https://bugzilla.redhat.com/show_bug.cgi?id=1201387
Thanks for any input,
On Fri, Oct 09, 2015 at 02:59:05PM +0200, Victor Toso wrote:
> When channel wants to send much more data then the wire can handle, the
> queue grows fast. This patch does not limit the queue growth but
> introduces an internal API to check if queue size is too big.
>
> In the case of usbredir, video devices on high latency can easily
> trigger this situation.
>
> An easy way to test locally is sharing and webcam and simulating high
> latency with tc:
> tc qdisc add dev lo root netem delay 100ms
> tc qdisc change dev lo root netem delay 1000ms
> tc qdisc del dev lo root netem
>
> Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1264156
> ---
> src/channel-usbredir.c | 7 +++++++
> src/spice-channel-priv.h | 2 ++
> src/spice-channel.c | 27 ++++++++++++++++++++++++++-
> 3 files changed, 35 insertions(+), 1 deletion(-)
>
> diff --git a/src/channel-usbredir.c b/src/channel-usbredir.c
> index 89f5c9d..fb7bd07 100644
> --- a/src/channel-usbredir.c
> +++ b/src/channel-usbredir.c
> @@ -475,6 +475,13 @@ static void usbredir_write_flush_callback(void *user_data)
> if (!priv->host)
> return;
>
> + if (spice_channel_has_full_queue (SPICE_CHANNEL(channel))) {
> + g_warning ("device %04x:%04x is loosing data due high traffic",
> + spice_usb_device_get_vid(priv->spice_device),
> + spice_usb_device_get_pid(priv->spice_device));
> + return;
> + }
> +
> usbredirhost_write_guest_data(priv->host);
> }
>
> diff --git a/src/spice-channel-priv.h b/src/spice-channel-priv.h
> index 436a521..ae8d01e 100644
> --- a/src/spice-channel-priv.h
> +++ b/src/spice-channel-priv.h
> @@ -111,6 +111,7 @@ struct _SpiceChannelPrivate {
> gboolean xmit_queue_blocked;
> STATIC_MUTEX xmit_queue_lock;
> guint xmit_queue_wakeup_id;
> + guint64 queue_size;
>
> char name[16];
> enum spice_channel_state state;
> @@ -171,6 +172,7 @@ void spice_channel_wakeup(SpiceChannel *channel, gboolean cancel);
>
> SpiceSession* spice_channel_get_session(SpiceChannel *channel);
> enum spice_channel_state spice_channel_get_state(SpiceChannel *channel);
> +gboolean spice_channel_has_full_queue (SpiceChannel *channel);
>
> /* coroutine context */
> typedef void (*handler_msg_in)(SpiceChannel *channel, SpiceMsgIn *msg, gpointer data);
> diff --git a/src/spice-channel.c b/src/spice-channel.c
> index 2ce52c7..d574b90 100644
> --- a/src/spice-channel.c
> +++ b/src/spice-channel.c
> @@ -697,10 +697,12 @@ void spice_msg_out_send(SpiceMsgOut *out)
> {
> SpiceChannelPrivate *c;
> gboolean was_empty;
> + guint32 size;
>
> g_return_if_fail(out != NULL);
> g_return_if_fail(out->channel != NULL);
> c = out->channel->priv;
> + size = spice_marshaller_get_total_size(out->marshaller);
>
> STATIC_MUTEX_LOCK(c->xmit_queue_lock);
> if (c->xmit_queue_blocked) {
> @@ -710,6 +712,7 @@ void spice_msg_out_send(SpiceMsgOut *out)
>
> was_empty = g_queue_is_empty(&c->xmit_queue);
> g_queue_push_tail(&c->xmit_queue, out);
> + c->queue_size = (was_empty) ? size : c->queue_size + size;
>
> /* One wakeup is enough to empty the entire queue -> only do a wakeup
> if the queue was empty, and there isn't one pending already. */
> @@ -2104,8 +2107,11 @@ static void spice_channel_iterate_write(SpiceChannel *channel)
> STATIC_MUTEX_LOCK(c->xmit_queue_lock);
> out = g_queue_pop_head(&c->xmit_queue);
> STATIC_MUTEX_UNLOCK(c->xmit_queue_lock);
> - if (out)
> + if (out) {
> + guint32 size = spice_marshaller_get_total_size(out->marshaller);
> + c->queue_size = (c->queue_size < size) ? 0 : c->queue_size - size;
> spice_channel_write_msg(channel, out);
> + }
> } while (out);
>
> spice_channel_flushed(channel, TRUE);
> @@ -2813,6 +2819,25 @@ enum spice_channel_state spice_channel_get_state(SpiceChannel *channel)
> return channel->priv->state;
> }
>
> +#define QUEUE_MEMORY_LIMIT_MB 10
> +
> +G_GNUC_INTERNAL
> +gboolean spice_channel_has_full_queue (SpiceChannel *channel)
> +{
> + SpiceChannelPrivate *c = channel->priv;
> + gdouble ret_mb;
> + guint mb_limit;
> + const gchar *env = g_getenv("SPICE_CHANNEL_QUEUE_SIZE");
> + mb_limit = (env == NULL) ? QUEUE_MEMORY_LIMIT_MB : strtoul(env, NULL, 10);
> +
> + STATIC_MUTEX_LOCK(c->xmit_queue_lock);
> + ret_mb = c->queue_size/1024.0/1024.0;
> + STATIC_MUTEX_UNLOCK(c->xmit_queue_lock);
> + CHANNEL_DEBUG(channel, "queue length: %u with total size: %4.4f MB (max = %u MB)",
> + g_queue_get_length(&c->xmit_queue), ret_mb, mb_limit);
> + return (ret_mb > mb_limit);
> +}
> +
> G_GNUC_INTERNAL
> void spice_channel_swap(SpiceChannel *channel, SpiceChannel *swap, gboolean swap_msgs)
> {
> --
> 2.5.0
>
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel
More information about the Spice-devel
mailing list