cURL / Mailing Lists / curl-users / Single Mail

curl-users

Re: FTP upload speed problem and buffer size

From: Alessandro Vesely <vesely_at_tana.it>
Date: Fri, 12 Oct 2007 18:35:43 +0200

Daniel Stenberg wrote:
> On Fri, 12 Oct 2007, Alessandro Vesely wrote:
>
>> I captured another transfer of the same 8058822 bytes, using no
>> options, and obtained the same sending pattern. IMHO it happens
>> because cURL sends one buffer at a time, without refilling the buffer
>> after a partial send has taken place.
>>
>> The number of buffers sent this way is 5906 = (11+1)*491 + 9+1 + 2+2:
>> 12 buffers * 491 times + 14278 =
>> (11 * 1460 + 324) * 491 + 1460 * 9 + 1138,
>> where 1 buffer is 0x4000 bytes, see attached file.
>> (Curiously, this morning I had 10 packets more on the relevant capture
>> file.)
>>
>> Refilling the buffer each time gave 5523 = 5519 + 1 + 1+2:
>> 5519*1460 + 1*1082 = 8057740 + 1082 = 8058822.
>>
>> Thus, curl sent 383 data packets more. Assuming a constant time per
>> packet, that would result in approximately a 7% increase, roughly 1
>> second every 14. That, together with the rounded time in the xferlog,
>> more or less explains the timings I got. Dunno what curious TCP
>> pattern could have been triggered to obtain the much more relevant
>> difference that Ivan reported...
>
> I'm quite amazed that the TCP layer doesn't use its own buffering to
> even out this... Did you try building a curl with an "even" (for example
> 16*1460) buffer size instead to see if that then makes everything fly
> faster and thus really prove this theory?

Yup, after setting line 224 in curl.h to
#define CURL_MAX_WRITE_SIZE /* 16384 */ (16*1460)
I obtained "7" once and the packets' size stays steady. (I must have some
problems on the hub, since I captured 5540 packets --16 more than needed.)

> But I figure a more sensible fix for this flaw is to edit the code in
> lib/transfer.c around line 1400 to refill the buffer earlier than when
> it gets completely empty.

Hm... I've had an attempt at messing up Curl_readwrite, but it didn't work.
Curl_write writes the whole buffer. I guess it is the send function which
does a loop until the buffer is fully written.

> I can't but to feel that it seems utterly silly that this layer of code
> would need to know about and adjust to the transfer layer's MTU etc. I
> mean, sure 1460 bytes is for the typical TCP over IPv4 ethernet, but the
> lib/transfer.c code really is completely unaware and non-caring about
> that...

So it seems it doesn't need to know about that. However, that way it won't
get the best behavior either.

Perhaps this behavior should be optimized using bsd's SO_SNDLOWAT option,
which windows does not support. Instead, it has an SIO_IDEAL_SEND_BACKLOG_
CHANGE IOCTL, supported on Windows Server 2008 and later...

I never used tcp-nodelay today, so smaller packets should/might have been
queued. They didn't.

Anyway, it is probably the same in other OSes, since the code is the same.
Possibly, curl may set the buffer to an "even" value if it has some mean to
learn the MTU on a particular OS.
Received on 2007-10-12