* fhandler_socket.cc (fhandler_socket::send_internal): Improve loop to

write streams in chunks of wmem() bytes to raise performance when
	writing small buffers.  Rename variables and add comments to help
	understanding the code in years to come.
This commit is contained in:
Corinna Vinschen 2014-07-07 12:57:03 +00:00
parent 72506dd846
commit f135cbdd45
2 changed files with 48 additions and 15 deletions

View File

@ -1,3 +1,10 @@
2014-07-07 Corinna Vinschen <corinna@vinschen.de>
* fhandler_socket.cc (fhandler_socket::send_internal): Improve loop to
write streams in chunks of wmem() bytes to raise performance when
writing small buffers. Rename variables and add comments to help
understanding the code in years to come.
2014-07-07 Corinna Vinschen <corinna@vinschen.de> 2014-07-07 Corinna Vinschen <corinna@vinschen.de>
* passwd.cc (pg_ent::enumerate_ad): Revert to simply skipping a domain * passwd.cc (pg_ent::enumerate_ad): Revert to simply skipping a domain

View File

@ -1664,8 +1664,8 @@ inline ssize_t
fhandler_socket::send_internal (struct _WSAMSG *wsamsg, int flags) fhandler_socket::send_internal (struct _WSAMSG *wsamsg, int flags)
{ {
ssize_t res = 0; ssize_t res = 0;
DWORD ret = 0, err = 0, sum = 0, off = 0; DWORD ret = 0, err = 0, sum = 0;
WSABUF buf; WSABUF out_buf[wsamsg->dwBufferCount];
bool use_sendmsg = false; bool use_sendmsg = false;
DWORD wait_flags = flags & MSG_DONTWAIT; DWORD wait_flags = flags & MSG_DONTWAIT;
bool nosignal = !!(flags & MSG_NOSIGNAL); bool nosignal = !!(flags & MSG_NOSIGNAL);
@ -1673,19 +1673,41 @@ fhandler_socket::send_internal (struct _WSAMSG *wsamsg, int flags)
flags &= (MSG_OOB | MSG_DONTROUTE); flags &= (MSG_OOB | MSG_DONTROUTE);
if (wsamsg->Control.len > 0) if (wsamsg->Control.len > 0)
use_sendmsg = true; use_sendmsg = true;
for (DWORD i = 0; i < wsamsg->dwBufferCount; /* Workaround for MSDN KB 823764: Split a message into chunks <= SO_SNDBUF.
off >= wsamsg->lpBuffers[i].len && (++i, off = 0)) in_idx is the index of the current lpBuffers from the input wsamsg buffer.
in_off is used to keep track of the next byte to write from a wsamsg
buffer which only gets partially written. */
for (DWORD in_idx = 0, in_off = 0;
in_idx < wsamsg->dwBufferCount;
in_off >= wsamsg->lpBuffers[in_idx].len && (++in_idx, in_off = 0))
{ {
/* CV 2009-12-02: Don't split datagram messages. */ /* Split a message into the least number of pieces to minimize the
/* FIXME: Look for a way to split a message into the least number of number of WsaSendTo calls. Don't split datagram messages (bad idea).
pieces to minimize the number of WsaSendTo calls. */ out_idx is the index of the next buffer in the out_buf WSABUF,
also the number of buffers given to WSASendTo.
out_len is the number of bytes in the buffers given to WSASendTo.
Don't split datagram messages (very bad idea). */
DWORD out_idx = 0;
DWORD out_len = 0;
if (get_socket_type () == SOCK_STREAM) if (get_socket_type () == SOCK_STREAM)
{ {
buf.buf = wsamsg->lpBuffers[i].buf + off; do
buf.len = wsamsg->lpBuffers[i].len - off; {
/* See net.cc:fdsock() and MSDN KB 823764 */ out_buf[out_idx].buf = wsamsg->lpBuffers[in_idx].buf + in_off;
if (buf.len >= (unsigned) wmem ()) out_buf[out_idx].len = wsamsg->lpBuffers[in_idx].len - in_off;
buf.len = (unsigned) wmem (); out_len += out_buf[out_idx].len;
out_idx++;
}
while (out_len < (unsigned) wmem ()
&& (in_off = 0, ++in_idx < wsamsg->dwBufferCount));
/* Tweak len of the last out_buf buffer so the entire number of bytes
is less than wmem (). */
if (out_len > (unsigned) wmem ())
out_buf[out_idx - 1].len -= out_len - (unsigned) wmem ();
/* Add the bytes written from the current last buffer to in_off,
so in_off points to the next byte to be written from that buffer,
or beyond which lets the outper loop skip to the next buffer. */
in_off += out_buf[out_idx - 1].len;
} }
do do
@ -1693,7 +1715,7 @@ fhandler_socket::send_internal (struct _WSAMSG *wsamsg, int flags)
if (use_sendmsg) if (use_sendmsg)
res = WSASendMsg (get_socket (), wsamsg, flags, &ret, NULL, NULL); res = WSASendMsg (get_socket (), wsamsg, flags, &ret, NULL, NULL);
else if (get_socket_type () == SOCK_STREAM) else if (get_socket_type () == SOCK_STREAM)
res = WSASendTo (get_socket (), &buf, 1, &ret, flags, res = WSASendTo (get_socket (), out_buf, out_idx, &ret, flags,
wsamsg->name, wsamsg->namelen, NULL, NULL); wsamsg->name, wsamsg->namelen, NULL, NULL);
else else
res = WSASendTo (get_socket (), wsamsg->lpBuffers, res = WSASendTo (get_socket (), wsamsg->lpBuffers,
@ -1711,9 +1733,13 @@ fhandler_socket::send_internal (struct _WSAMSG *wsamsg, int flags)
if (!res) if (!res)
{ {
off += ret;
sum += ret; sum += ret;
if (get_socket_type () != SOCK_STREAM) /* For streams, return to application if the number of bytes written
is less than the number of bytes we intended to write in a single
call to WSASendTo. Otherwise we would have to add code to
backtrack in the input buffers, which is questionable. There was
probably a good reason we couldn't write more. */
if (get_socket_type () != SOCK_STREAM || ret < out_len)
break; break;
} }
else if (is_nonblocking () || err != WSAEWOULDBLOCK) else if (is_nonblocking () || err != WSAEWOULDBLOCK)