cygrunsrv + sshd + rsync = 20 times too slow -- throttled?
Corinna Vinschen
corinna-cygwin@cygwin.com
Mon Sep 6 12:49:55 GMT 2021
On Sep 6 20:16, Takashi Yano wrote:
> Hi Corinna,
>
> On Mon, 6 Sep 2021 10:13:10 +0200
> Corinna Vinschen wrote:
> > If you have multiple readers, all but one of them will hang in this
> > WFSO. They will block here without a chance to kill or Ctrl-C them
> > and thread cancellation won't work.
> >
> > To fix that you have to use cygwait and handle signals and thread
> > cancellation the same way as in the below code following the NtReadFile.
>
> OK. Thanks for the advice. Then what about the patch attached?
>
> > > /* If the pipe is empty, don't request more bytes than half the
> > > - pipe buffer size. Every pending read lowers WriteQuotaAvailable
> > > - on the write side and thus affects select's ability to return
> > > - more or less reliable info whether a write succeeds or not.
> > > -
> > > - Let the size of the request depend on the number of readers
> > > - at the time. */
> > > + pipe buffer size. Pending read lowers WriteQuotaAvailable on
> > > + the write side and thus affects select's ability to return
> > > + more or less reliable info whether a write succeeds or not. */
> > > + ULONG chunk = max_atomic_write / 2;
> > > status = NtQueryInformationFile (get_handle (), &io,
> > > &fpli, sizeof (fpli),
> > > FilePipeLocalInformation);
> > > - if (NT_SUCCESS (status) && fpli.ReadDataAvailable == 0)
> >
> > If the readers are serialized anyway, why fetch only half the remaining
> > buffer size? In that case fetching fpli.InboundQuota - 1 is as good
> > as fetching just the half of it, isn't it?
>
> It sounds reasonable. Adopted in the attached patch.
Patch looks ok.
I added one more patches:
- It occured to me that the code is lacking a CancelIo in case cygwait
is waiting for NtReadFile/NtWriteFile. Actually, calling cygwait
without "mask" parameter will result in cygwait performing the thread
cancellation by itself, but cancelling a thread does not cancel the
async IO started by that thread. So I fixed the cygwait calls in
raw_read/raw_write to return to the caller and then call CancelIo
before cancelling the thread.
I planned to push one more patch:
- Drop max_atomic_write, it's == DEFAULT_PIPEBUFSIZE anyway
But then some things were coming to mind, which we still have to discuss.
- I think setting chunk to DEFAULT_PIPEBUFSIZE - 1 in the read case and
DEFAULT_PIPEBUFSIZE in the write case by default is dangerous.
Assuming the pipe has been created by a non-Cygwin process, the values
may be way too high.
Suggestion: Actually set max_atomic_write to something useful.
Set max_atomic_write to DEFAULT_PIPEBUFSIZE in fhandler_pipe::create.
In case of stdio handles inherited from non-Cygwin processes, fetch
the pipe buffer size via NtQueryInformationFile in
dtable::init_std_file_from_handle(). Better, in a matching
fhandler_pipe method called from init_std_file_from_handle().
- What about calling select for writing on pipes read by non-Cygwin
processes? In that case, we still can't rely on WriteQuotaAvailable,
just as before.
I have a vague idea that we might want to count readers in that case,
but I have to think about it some more.
Corinna
More information about the Cygwin-developers
mailing list