[Spice-devel] [RFC PATCH 3/3] worker: use manual flushing on stream to decrease packet fragmentation

Jonathon Jongsma jjongsma at redhat.com
Tue Feb 23 17:38:53 UTC 2016


On Mon, 2016-02-22 at 13:38 -0500, Frediano Ziglio wrote:
> > 
> > On Tue, 2016-02-16 at 15:36 +0000, Frediano Ziglio wrote:
> > > Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
> > > ---
> > >  server/red-channel.c | 12 ++++++++----
> > >  server/red-worker.c  | 24 +++++++++++++-----------
> > >  2 files changed, 21 insertions(+), 15 deletions(-)
> > > 
> > > diff --git a/server/red-channel.c b/server/red-channel.c
> > > index d7ff37e..c2a0c78 100644
> > > --- a/server/red-channel.c
> > > +++ b/server/red-channel.c
> > > @@ -1364,10 +1364,14 @@ void red_channel_client_push(RedChannelClient
> > > *rcc)
> > >      while ((pipe_item = red_channel_client_pipe_item_get(rcc))) {
> > >          red_channel_client_send_item(rcc, pipe_item);
> > >      }
> > > -    if (red_channel_client_no_item_being_sent(rcc) && ring_is_empty(&rcc
> > > ->pipe)
> > > -        && rcc->stream->watch) {
> > > -        rcc->channel->core->watch_update_mask(rcc->stream->watch,
> > > -                                              SPICE_WATCH_EVENT_READ);
> > > +    if (red_channel_client_no_item_being_sent(rcc) && ring_is_empty(&rcc
> > > ->pipe)) {
> > > +        if (rcc->stream->watch) {
> > > +            rcc->channel->core->watch_update_mask(rcc->stream->watch,
> > > +                                                 
> > >  SPICE_WATCH_EVENT_READ);
> > > +        }
> > > +        reds_stream_flush(rcc->stream);
> > > +    } else if (red_channel_client_waiting_for_ack(rcc)) {
> > > +        reds_stream_flush(rcc->stream);
> > 
> > Can you explain the reason for flushing when we're waiting for an ACK? Is
> > there
> > a reason we couldn't just move the flush completely outside of the if
> > statement
> > and flush in all circumstances in this function?
> > 
> 
> Mainly it's the optimal way.
> For Ack you need to flush as otherwise you risk to wait an pong for a not sent
> ping if the messages are really small.
> For the other if you want to flush only if there are nothing queued (neither
> data neither other messages).
> Note that you can have lot of messages in the queue but you are waiting for
> ack (pong) before sending other data.
> 
> OT: I don't like the idea of ACKs on bytes and as discussed with Pavel in Brno
> I don't see the point of using additional Acking on top of tcp (which already
> implements flow control) but one problem at a time.
> 
> > >      }
> > >      rcc->during_send = FALSE;
> > >      red_channel_client_unref(rcc);
> > > diff --git a/server/red-worker.c b/server/red-worker.c
> > > index bf12a22..b368a63 100644
> > > --- a/server/red-worker.c
> > > +++ b/server/red-worker.c
> > > @@ -416,17 +416,19 @@ static int
> > > common_channel_config_socket(RedChannelClient
> > > *rcc)
> > >  
> > >      // TODO - this should be dynamic, not one time at channel creation
> > >      ccc->is_low_bandwidth = main_channel_client_is_low_bandwidth(mcc);
> > > -    delay_val = ccc->is_low_bandwidth ? 0 : 1;
> > > -    /* FIXME: Using Nagle's Algorithm can lead to apparent delays,
> > > depending
> > > -     * on the delayed ack timeout on the other side.
> > > -     * Instead of using Nagle's, we need to implement message buffering
> > > on
> > > -     * the application level.
> > > -     * see: http://www.stuartcheshire.org/papers/NagleDelayedAck/
> > > -     */
> > > -    if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY, &delay_val,
> > > -                   sizeof(delay_val)) == -1) {
> > > -        if (errno != ENOTSUP) {
> > > -            spice_warning("setsockopt failed, %s", strerror(errno));
> > > +    if (!reds_stream_set_auto_flush(rcc->stream, false)) {
> > > +        delay_val = ccc->is_low_bandwidth ? 0 : 1;
> > > +        /* FIXME: Using Nagle's Algorithm can lead to apparent delays,
> > > depending
> > > +         * on the delayed ack timeout on the other side.
> > > +         * Instead of using Nagle's, we need to implement message
> > > buffering
> > > on
> > > +         * the application level.
> > > +         * see: http://www.stuartcheshire.org/papers/NagleDelayedAck/
> > > +         */
> > > +        if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY,
> > > &delay_val,
> > > +                       sizeof(delay_val)) == -1) {
> > > +            if (errno != ENOTSUP) {
> > > +                spice_warning("setsockopt failed, %s", strerror(errno));
> > > +            }
> > 
> > 
> > I don't quite understand why you're setting NODELAY if CORK fails here. Can
> > you
> > provide a bit more justification/explanation here?
> > 
> 
> It's a fallback. Cork and flush are a better way to achieve no delay sending
> data also avoiding also too much fragmentation (which was the reason for
> Nagle).
> It's actually a bit paranoid as the socket and system (Linux) we are using
> supports TCP_CORK so function won't fail but we are ready for failures or
> porting (I don't know... *BSD, Mac).


I apologize, somehow I completely missed the fact that the old code was already
setting NODELAY. For some reason I thought that your patch added that part. I'll
blame it on Monday.


> 
> Note that the flush APIs are independent on the implementation. They can be
> used with SSL and compression too.
> Assume we are sending (not impossible!) 20 messages of 50 bytes each. The
> standard framing for ethernet (wire or wireless) + tcp is about 80 bytes.
> Sending as separate network packets you use 20 * ( 50 + 80 ) = 2600 bytes
> while with cork you just spend 1080 ( 20 * 50 + 80 ).
> Using SSL assuming a cipher of 128 bit we can assume to encrypt N bytes
> we need 3 + ROUNDUP(N + 8, 16) (3 is the TLS framing, 8 is for the padding
> and 16 is the key size in bytes)that is for 50 bytes 67 bytes so we could
> have 20 * ( 67 + 80 ) = 2940 bytes instead of
> 3 + ROUNDUP(20 * 50 + 8, 16) = 1011 bytes .
> Similar padding+framing apply to compression algorithms.
> 
> > 
> > >          }
> > >      }
> > >      return TRUE;
> > 
> 
> Frediano


More information about the Spice-devel mailing list