Thursday, July 19, 2018

Libcurl and slow uploads on Windows

Recently I started using libCurl 7.60 to upload files from Windows machines to Amazon cloud using HTTP POST. The uploads don't perform well. They are limited by the send buffer used by Windows.
On Windows 2008R2 (and probably on more recent versions as well) the system only puts on the wire the bytes it has buffered, and this is limited by SO_SNDBUF (default 8KB) or by the send buffer used by application code (CURL_MAX_WRITE_SIZE, 16KB), whichever is higher. In case of CURL uploads, the system buffers 16KB, then waits for acknowledgement from the other end before buffering and sending the next batch. This is readily visible in Wireshark traces.

Starting with Windows 7 / 2008R2, Windows implements send buffer autotuning. This is well described here.

Theoretically on these systems the send buffer should be automatically adjusted to optimize throughput. I run a couple experiments to confirm that, and found that the send buffer is only adjusted if the socket is blocking and application buffer size is reasonably large (in my experiment 16KB was too small, but 20KB was sufficient), and buffer stays at 8192 if the socket is nonblocking regardless of the application buffer size.

Curl is using nonblocking sockets, and switching to blocking would break existing functionality. In order to use the optimal buffer size, it would need to periodically update SO_SNDBUF to a value provided by SIO_IDEAL_SEND_BACKLOG_QUERY or SIO_IDEAL_SEND_BACKLOG_CHANGE.

I sent a proof-of-concept patch to curl-library mailing list. With some luck the patch will find its way to the next curl release.