cygrunsrv + sshd + rsync = 20 times too slow -- throttled?

Ken Brown kbrown@cornell.edu
Mon Aug 30 19:12:18 GMT 2021


On 8/30/2021 2:59 PM, Ken Brown wrote:
> On 8/30/2021 1:00 PM, Corinna Vinschen wrote:
>> On Aug 30 17:53, Corinna Vinschen wrote:
>>> On Aug 30 16:05, Corinna Vinschen wrote:
>>>> On Aug 30 09:36, Ken Brown wrote:
>>>>> BTW, when I was working on the pipe approach to AF_UNIX sockets
>>>>> (topic/af_unix branch), I had occasion to step through
>>>>> select.cc:pipe_data_available in gdb, and the use of fpli.OutboundQuota -
>>>>> fpli.ReadDataAvailable definitely seemed wrong to me.  So when I wrote
>>>>> peek_socket_unix on that branch, I used fpli.WriteQuotaAvailable, as Takashi
>>>>> is suggesting now.
>>>>
>>>> If that's working reliable these days (keeping fingers crossed for W7),
>>>> it's ok if we use that.  We may want to check if the above observation
>>>> in terms on WriteQuotaAvailable on a pipe with pending read is still an
>>>> issue.
>>>
>>> Ok, I wrote a small testcase.  It creates a named pipe, reads from the
>>> pipe, then, later, writes to the pipe.  Interlaced with these calls, it
>>> calls NtQueryInformationFile(FilePipeLocalInformation) on the write side
>>> of the pipe.  Kind of like this:
>>>
>>>    CreatePipe
>>>    NtQueryInformationFile
>>>    ReadFile
>>>    NtQueryInformationFile
>>>    WriteFile
>>>    NtQueryInformationFile
>>>
>>> Here's the result:
>>>
>>> Before ReadFile:
>>>
>>>    InboundQuota: 65536
>>>    ReadDataAvailable: 0
>>>    OutboundQuota: 65536
>>>    WriteQuotaAvailable: 65536
>>>
>>> While ReadFile is running:
>>>
>>>    InboundQuota: 65536
>>>    ReadDataAvailable: 0
>>>    OutboundQuota: 65536
>>>    WriteQuotaAvailable: 65494    !!!
>>>
>>> After WriteFile and ReadFile succeeded:
>>>
>>>    InboundQuota: 65536
>>>    ReadDataAvailable: 0
>>>    OutboundQuota: 65536
>>>    WriteQuotaAvailable: 65536
>>>
>>> That means, while a reader on the reader side is waiting for data, the
>>> WriteQuotaAvailable on the write side is decremented by the amount of
>>> data requested by the reader (42 bytes in my case), just as outlined in that
>>> mail from 2004.  And this is on W10 now.
>>>
>>> What to do with this information?  TBD.
>>
>> Ok, let's discuss this.  I added more code to my testcase and here's
>> what I see.  I dropped all data from the output which doesn't change.
>>
>> What I'm trying to get a grip on are the dependencies here.
>>
>> After creating the pipe:
>>
>>    read side: ReadDataAvailable: 0
>>    write side: WriteQuotaAvailable: 65536
>>
>> After writing 20 bytes...
>>
>>    read side: ReadDataAvailable: 20
>>    write side: WriteQuotaAvailable: 65516
>>
>> After writing 40 more bytes...
>>
>>    read side: ReadDataAvailable: 60
>>    write side: WriteQuotaAvailable: 65476
>>
>> After reading 42 bytes...
>>
>>    read side: ReadDataAvailable: 18
>>    write side: WriteQuotaAvailable: 65518
>>
>> After writing 20 bytes...
>>
>>    read side: ReadDataAvailable: 38
>>    write side: WriteQuotaAvailable: 65498
>>
>> *While* reading 42 bytes with an empty buffer...
>>
>>    read side: ReadDataAvailable: 0
>>    write side: WriteQuotaAvailable: 65494
>>
>> Another important fun fact:  Assuming the read and write buffer sizes
>> are differently specified.  I called CreateNamedPipe with an outbuffer
>> size of 32K and an inbuffer size of 64K:
>>
>> After creating the pipe:
>>
>>    read side:
>>      InboundQuota: 65536
>>      ReadDataAvailable: 0
>>      OutboundQuota: 32768
>>      WriteQuotaAvailable: 32768
>>    write side:
>>      InboundQuota: 65536
>>      ReadDataAvailable: 0
>>      OutboundQuota: 32768
>>      WriteQuotaAvailable: 65536    !!!
>>
>> This last data point shows that:
>>
>> - InboundQuota and OutboundQuota are always constant values and
>>    do not depend on the side the information has been queried on.
>>    That certainly makes sense.
>>
>> - WriteQuotaAvailable does not depend on the OutboundQuota, but on
>>    the InboundQuota, and very likely on the InboundQuota of the read
>>    side.  The OutboundQuota *probably* only makes sense when using
>>    named pipes with remote clients, which we never do anyway.
>>
>> The preceeding output shows that ReadDataAvailable on the read side and
>> WriteQuotaAvailable on the write side are connected.  If we write 20
>> bytes, ReadDataAvailable is incremented by 20 and WriteQuotaAvailable is
>> decremented by 20.
>>
>> So: write.WriteQuotaAvailable == InboundQuota - read.ReadDataAvailable.
>>
>> Except when a ReadFile is pending on the read side.  It's as if the
>> running ReadFile already reserved write quota.  So the write side
>> WriteQuotaAvailable is the number of bytes we can write without blocking,
>> after all pending ReadFiles have been satisfied.
>>
>> Unfortunately that doesn't really make sense when looked at it from the
>> user space.
>>
>> What that means in the first place is that WriteQuotaAvailable on the
>> write side is unreliable.  What we really need is InboundQuota -
>> read.ReadDataAvailable.  The problem with that is that the write side
>> usually has no access to the read side of the pipe.
> 
> For the purposes of select.cc:pipe_data_available, we only need to know whether 
> InboundQuota - read.ReadDataAvailable is positive.  If WriteQuotaAvailable is 
> positive, then we're OK, even though its precise value might be too small.  But 
> if WriteQuotaAvailable == 0, we don't know whether the buffer is actually full 
> or there's a pending ReadFile.  It's only in this case that we need access to 
> the read side.
> 
> What if we reverse the roles of the read and write sides of the pipe, so that 
> the write side is the server and the read side is the client.  We can then try 
> to use ImpersonateNamedPipeClient to get information about the read side when 
> WriteQuotaAvailable == 0.  If we succeed, then we can determine whether or not 
> there's space in the buffer.  If we fail, we simply report, possibly 
> incorrectly, that there is space.  This is no worse than the current situation 
> (on the master branch), in which we use OutboundQuota - ReadDataAvailable, which 
> is always positive.

I should add that I know absolutely nothing about ImpersonateNamedPipeClient, so 
this might be complete nonsense.

Ken


More information about the Cygwin-developers mailing list