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:
parent
621dfb4a5b
commit
82a2cd6155
@ -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.).
|
||||
|
@ -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
|
||||
|
35
net/Kconfig
35
net/Kconfig
@ -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
|
||||
|
99
net/send.c
99
net/send.c
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user