Add split package logic to improve TCP send performance with delayed ACKs

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5538 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2013-01-19 16:40:43 +00:00
parent 621dfb4a5b
commit 82a2cd6155
4 changed files with 147 additions and 3 deletions

View File

@ -3987,3 +3987,5 @@
* configs/open1788: Board configuration for the Wave Share
Open1788 board. Still fragmentary (contribnuted by Rommel
Marcelo, adapted to use kconfig-frontends.
* net/send(): Add logic to work around delayed ACKs by splitting
packets (contributed by Yan T.).

View File

@ -193,6 +193,10 @@ CONFIG_NET_PRIORITY=0
# USB host driver options
#
#
# External Memory Configuration
#
#
# Architecture Options
#
@ -396,6 +400,10 @@ CONFIG_NET_NACTIVESOCKETS=16
CONFIG_NET_SOCKOPTS=y
CONFIG_NET_BUFSIZE=562
# CONFIG_NET_TCPURGDATA is not set
#
# TCP/IP Networking
#
CONFIG_NET_TCP=y
CONFIG_NET_TCP_CONNS=8
CONFIG_NET_MAX_LISTENPORTS=8
@ -403,6 +411,12 @@ CONFIG_NET_TCP_READAHEAD_BUFSIZE=562
CONFIG_NET_NTCP_READAHEAD_BUFFERS=16
CONFIG_NET_TCP_RECVDELAY=0
# CONFIG_NET_TCPBACKLOG is not set
CONFIG_NET_TCP_SPLIT=y
CONFIG_NET_TCP_SPLIT_SIZE=40
#
# UDP Networking
#
CONFIG_NET_UDP=y
CONFIG_NET_UDP_CHECKSUMS=y
CONFIG_NET_UDP_CONNS=8

View File

@ -97,14 +97,14 @@ config NET_TCPURGDATA
compiled in. Urgent data (out-of-band data) is a rarely used TCP feature
that is very seldom would be required.
menu "TCP/IP Networking"
config NET_TCP
bool "TCP/IP Networking"
default n
---help---
TCP support on or off
endif
if NET_TCP
config NET_TCP_CONNS
int "Number of TCP/IP connections"
@ -164,7 +164,36 @@ config NET_TCPBACKLOG
Incoming connections pend in a backlog until accept() is called.
The size of the backlog is selected when listen() is called.
config NET_TCP_SPLIT
bool "Enable packet splitting"
default n
---help---
send() will not return until the the transfer has been ACKed by the
recipient. But under RFC 1122, the host need not ACK each packet
immediately; the host may wait for 500 MS before ACKing. This
combination can cause very slow performance with small transfers are
made to an RFC 1122 client. However, the RFC 1122 must ACK at least
every second (odd) packet.
This option enables logic to trick the RFC 1122 host be exploiting
this last RFC 1122 requirement: If an odd number of packets were to
be sent, then send() will split the last even packet to guarantee
that an even number of packets will be sent and the RFC 1122 host
will ACK the final packet immediately.
if NET_TCP_SPLIT
config NET_TCP_SPLIT_SIZE
int "Split size threshold"
default 40
---help---
Packets of this size or smaller than this will not be split.
endif
endif
endmenu
menu "UDP Networking"
config NET_UDP
bool "UDP Networking"
@ -193,6 +222,7 @@ config NET_BROADCAST
Incoming UDP broadcast support
endif
endmenu
config NET_ICMP
bool "ICMP networking support"
@ -321,3 +351,4 @@ config SLIP_DEFPRIO
The priority of the SLIP RX and TX tasks. Default: 128
endif
endif

View File

@ -1,7 +1,7 @@
/****************************************************************************
* net/send.c
*
* Copyright (C) 2007-2012 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -42,7 +42,9 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <debug.h>
@ -62,6 +64,10 @@
* Definitions
****************************************************************************/
#if defined(CONFIG_NET_TCP_SPLIT) && !defined(CONFIG_NET_TCP_SPLIT_SIZE)
# define CONFIG_NET_TCP_SPLIT_SIZE 40
#endif
#define TCPBUF ((struct uip_tcpip_hdr *)&dev->d_buf[UIP_LLH_LEN])
/****************************************************************************
@ -85,6 +91,9 @@ struct send_s
#if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK)
uint32_t snd_time; /* last send time for determining timeout */
#endif
#if defined(CONFIG_NET_TCP_SPLIT)
bool snd_odd; /* True: Odd packet in pair transaction */
#endif
};
/****************************************************************************
@ -200,6 +209,14 @@ static uint16_t send_interrupt(struct uip_driver_s *dev, void *pvconn,
pstate->snd_sent = pstate->snd_acked;
#if defined(CONFIG_NET_TCP_SPLIT)
/* Reset the the even/odd indicator to even since we need to
* retransmit.
*/
pstate->snd_odd = false;
#endif
/* Fall through to re-send data from the last that was ACKed */
}
@ -242,6 +259,86 @@ static uint16_t send_interrupt(struct uip_driver_s *dev, void *pvconn,
/* Get the amount of data that we can send in the next packet */
uint32_t sndlen = pstate->snd_buflen - pstate->snd_sent;
#if defined(CONFIG_NET_TCP_SPLIT)
/* RFC 1122 states that a host may delay ACKing for up to 500ms but
* must respond to every second segment). This logic here will trick
* the RFC 1122 recipient into responding sooner. This logic will be
* activated if:
*
* 1. An even number of packets has been send (where zero is an even
* number),
* 2. There is more data be sent (more than or equal to
* CONFIG_NET_TCP_SPLIT_SIZE), but
* 3. Not enough data for two packets.
*
* Then we will split the remaining, single packet into two partial
* packets. This will stimulate the RFC 1122 not into ACKing sooner.
*
* Check if there is more data to be sent (more than or equal to
* CONFIG_NET_TCP_SPLIT_SIZE):
*/
if (sndlen >= CONFIG_NET_TCP_SPLIT_SIZE)
{
/* sndlen is the number of bytes remaining to be sent.
* uip_mss(conn) will return the number of bytes that can sent
* in one packet. The difference, then, is the number of bytes
* that would be sent in the next packet after this one.
*/
int32_t next_sndlen = sndlen - uip_mss(conn);
/* Is this the even packet in the packet pair transaction? */
if (!pstate->snd_odd)
{
/* next_sndlen <= 0 means that the entire remaining data
* could fit into this single packet. This is condition
* in which we must do the split.
*/
if (next_sndlen <= 0)
{
/* Split so that there will be an odd packet. Here
* we know that 0 < sndlen <= MSS
*/
sndlen = (sndlen / 2) + 1;
}
}
/* No... this is the odd packet in the packet pair transaction */
else
{
/* Will there be another (even) packet afer this one?
* (next_sndlen > 0) Will the split conidition occur on that
* next, even packet? ((next_sndlen - uip_mss(conn)) < 0) If
* so, then perform the split now to avoid the case where the
* byte count is less than CONFIG_NET_TCP_SPLIT_SIZE on the
* next pair.
*/
if (next_sndlen > 0 && (next_sndlen - uip_mss(conn)) < 0)
{
/* Here, we know that sndlen must be MSS <= sndlen <= 2*MSS
* and so (sndlen / 2) is <= MSS.
*/
sndlen /= 2;
}
}
}
/* Toggle the even/odd indicator */
pstate->snd_odd ^= true;
#endif /* CONFIG_NET_TCP_SPLIT */
if (sndlen > uip_mss(conn))
{
sndlen = uip_mss(conn);