From 4cee2896972f35a11d004bd2a842f774e0a6b747 Mon Sep 17 00:00:00 2001 From: Pieter Hintjens Date: Sun, 1 Nov 2015 12:57:32 +0100 Subject: [PATCH 1/2] Problem: Windows 7 TCP slow start See issue #1608. This is an old issue with Windows 7. The effect is that we see a latency ramp on the first 500 messages. * The ramp is unaffected by message size. * Sleeping up to 100msec between sends has no effect except to switch off ZeroMQ batching so making the ramp more visible. * After 500 messages, latency falls back down to ~10-40 usec. * Over inproc:// the ramp happens when we use the signaler class. * Client-server over inproc:// does not show the ramp. * Client-server over tcp:// shows a similar ramp. We know that the signaller is using TCP on Windows. We can 'prime' the connection by doing 500 dummy sends. This potentially causes new sockets to be delayed on creation, which is not a good solution. Note that the signaller sends zero-byte messages. This may also be confusing TCP. Solution: flood the receive buffer when creating a new FD pair; send a 1M buffer and discard it. Fixes #1608 --- src/signaler.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/signaler.cpp b/src/signaler.cpp index e6fa9833..462a30d6 100644 --- a/src/signaler.cpp +++ b/src/signaler.cpp @@ -454,6 +454,27 @@ int zmq::signaler_t::make_fdpair (fd_t *r_, fd_t *w_) if (rc != SOCKET_ERROR) *r_ = accept (listener, NULL, NULL); + // Send/receive large chunk to work around TCP slow start + // This code is a workaround for #1608 + if (*r_ != INVALID_SOCKET) { + size_t dummy_size = 1024 * 1024; // 1M to overload default receive buffer + unsigned char *dummy = (unsigned char *) malloc (dummy_size); + int still_to_send = (int) dummy_size; + int still_to_recv = (int) dummy_size; + while (still_to_send || still_to_recv) { + int nbytes; + if (still_to_send > 0) { + nbytes = ::send (*w_, (char *) (dummy + dummy_size - still_to_send), still_to_send, 0); + wsa_assert (nbytes != SOCKET_ERROR); + still_to_send -= nbytes; + } + nbytes = ::recv (*r_, (char *) (dummy + dummy_size - still_to_recv), still_to_recv, 0); + wsa_assert (nbytes != SOCKET_ERROR); + still_to_recv -= nbytes; + } + free (dummy); + } + // Save errno if error occurred in bind/listen/connect/accept. int saved_errno = 0; if (*r_ == INVALID_SOCKET) From 87dd03750bf7ce0f8926e6d757b62604f7f952e9 Mon Sep 17 00:00:00 2001 From: Pieter Hintjens Date: Tue, 16 Feb 2016 12:02:26 +0100 Subject: [PATCH 2/2] Updated NEWS for fix #1608 --- NEWS | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 34cb20e7..9d738d54 100644 --- a/NEWS +++ b/NEWS @@ -3,7 +3,10 @@ * Fixed #1673 - CMake on Windows put PDB in wrong directory. -* Fixed #1723 - Family is not set when resolving NIC on android. +* Fixed #1723 - Family is not set when resolving NIC on Android. + +* Fixed #1608 - Windows 7 TCP slow start issue. + 0MQ version 4.1.4 stable, released on 2015/12/18 ================================================