-
-
Notifications
You must be signed in to change notification settings - Fork 6.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Poor upload performance in Windows #6146
Comments
Trying Jay's PostUpload example I noted there were 3202 calls to:
The Ideal Send Backlog value started at 64kB, a few at 130kB and the remaining at 256 kB. Simply disabling the But I got around 9.3 MBit/s which IMHO is very good speed. In Google Chrome it reports 10.2 MBit/s blank to the same Frankfurt, DE server at https://testmy.net/upload. Using a 50 MByte test file for each test. |
I see the opposite, performance suffers without it.
Edit: When I run the 50MB test via the browser I get mbps results similar to what I get from 17f58c8, which is expected. |
If the 1 second delay comes from the timeout, the main question should be: why does it run into that timeout? |
All of them are slow. I think we should work from master for further testing.
That is the question alright and I don't know the answer. I assume the event is supposed to be signaled at that point since there is data, which would mean no wait. One strange thing I've noticed is in some of the results the speed is sometimes doubled or halved. For example, usually 100 seconds but sometimes 50 or 200.
5c8849c (master 2020-11-22)
|
I had one idea for an alternative implementation of this waiting in
This way we should be able to reduce again the overall number of syscalls, by doing one Curl_poll as readiness pre-check with the old logic and then just perform the waiting with the new logic including the new wakeup event instead of the old wakeup socket pair. This could potentially also reduce the number of ifdef's in the code again. |
How does that reduce the number of syscalls? It'd either be poll or objectwait, right? More importantly: that logic doesn't work if there's a timeout: In state (1) it only waits for socket and let's say we have a 1000ms timeout. During this period the wakeup event isn't checked and thus doesn't work. We delay the wakeup with this time. |
As I said, step 1 (" with no timeout") wouldn't use a timeout, it would just poll with a timeout of 0 as a pre-check. At the moment a pre-check is done with
|
We're only 6 days from release now. Can we revert this regression and work on a proper fix long-term? The only PR is still draft... |
One comment about this... In the old days of Win32 programming, you could It looks like the behavior has carried through to modern versions of Windows. See Sleep function (synchapi.h). If you would like to play nicely without a Wait function, then maybe try a Also be aware the Russinovich, Solomon and Ionescu discuss time slices in the Windows Internal books. Find the section on Quantums under Processes and Threads. |
So I know nothing about networking and nothing about usermode programming. But cold reading the code and the fine documentation
But this is about 10 minutes speculation based on zero insight either into cUrl or WSA. |
This may not be on the right track for why the timeout is being hit because I know nothing about the internals of curl. The WSAWaitForMultipleEvents is being used to wait until the socket is able to receive writes again correct? But, the FD_WRITE is only triggered if there has been a write attempt that was blocked. So, if the buffer sends without ever blocking wouldn't the WSAWaitForMultipleEvents always wait the timeout_ms duration for the next loop iteration in easy_transfer? I set a breakpoint in Curl_send_plain and I'm never hitting a case where the bytes_written is -1 so I don't think the FD_WRITE would ever be signaled for my scenario. This SO answer links to the relevant section about the behavior of FD_WRITE: |
@mback2k awesome, just tag me if there’s anything you’d like me to test! |
Actually the pre-checking with |
This is an attempt to restructure the code in Curl_multi_wait in such a way that less syscalls are made by removing individual calls to Curl_socket_check via SOCKET_READABLE/SOCKET_WRITABLE. Bug: curl#6146
I have a question, as I use libcurl 7.73.0 for our product on Windows. |
@Eliyahu-Machluf this issue is already fixed in later releases. It doesn't matter which public API you use to do transfers, they all use the same unified multi code underneath. |
@bagder, thanks for the quick response. Some more questions:
Thanks. |
Since this issue is already fixed, I will not spend time on it anymore. |
OK. Thanks. |
@Eliyahu-Machluf if your product is using libcurl 7.73.0 on Windows then it is affected. The performance slowdown is not constant, it depends on network conditions and even then is somewhat arbitrary. I would skip the metrics and upgrade as soon as you can. Sorry for the inconvenience. |
1. Consolidate pre-checks into a single Curl_poll call: This is an attempt to restructure the code in Curl_multi_wait in such a way that less syscalls are made by removing individual calls to Curl_socket_check via SOCKET_READABLE/SOCKET_WRITABLE. 2. Avoid resetting the WinSock event multiple times: We finally call WSAResetEvent anyway, so specifying it as an optional parameter to WSAEnumNetworkEvents is redundant. 3. Wakeup directly in case no sockets are being monitoring: Fix the WinSock based implementation to skip extra waiting by not sleeping in case no sockets are to be waited on and just the WinSock event is being monitored for wakeup functionality. Assisted-by: Tommy Odom Assisted-by: Jay Satiro Bug: curl#6146 Part of curl#6245
Reset FD_WRITE by sending zero bytes which is permissible and will be treated by implementations as successful send. Without this we won't be notified in case a socket is still writable if we already received such a notification and did not send any data afterwards on the socket. This would lead to waiting forever on a writable socket being writable again. Assisted-by: Tommy Odom Assisted-by: Jay Satiro Tested-by: Tommy Odom Tested-by: tmkk on github Bug: curl#6146 Part of curl#6245
@mback2k - Will I be able to just take multi.c changes for fixing this performance issue on my libcurl 7.73 source branch and rebuild? It will be too risky now to take 7.74 release into our code. Are there special instructions to enable the performance changes in this module |
You can just try to apply this PR, yes. |
ok - 6146 is the issue #, where is the associated PR? Iam seeing a lot of threads for related issues in this page |
So 7.74 and 7.75 have been fixed by reverting the problematic commits. And #6245 is the next attempt to implement the changes correctly, so you would have to apply all commits from that PR except the first one which reverts the reverting from 7.74. |
There's likely a much smaller risk to upgrade to the next release rather than to have you custom-patch code with patches you don't seem to have full control or understanding of. I would strongly advice against doing that. Use released versions instead. |
1. Consolidate pre-checks into a single Curl_poll call: This is an attempt to restructure the code in Curl_multi_wait in such a way that less syscalls are made by removing individual calls to Curl_socket_check via SOCKET_READABLE/SOCKET_WRITABLE. 2. Avoid resetting the WinSock event multiple times: We finally call WSAResetEvent anyway, so specifying it as an optional parameter to WSAEnumNetworkEvents is redundant. 3. Wakeup directly in case no sockets are being monitoring: Fix the WinSock based implementation to skip extra waiting by not sleeping in case no sockets are to be waited on and just the WinSock event is being monitored for wakeup functionality. Assisted-by: Tommy Odom Assisted-by: Jay Satiro Bug: curl#6146 Part of curl#6245
Reset FD_WRITE by sending zero bytes which is permissible and will be treated by implementations as successful send. Without this we won't be notified in case a socket is still writable if we already received such a notification and did not send any data afterwards on the socket. This would lead to waiting forever on a writable socket being writable again. Assisted-by: Tommy Odom Assisted-by: Jay Satiro Tested-by: Tommy Odom Tested-by: tmkk on github Bug: curl#6146 Part of curl#6245
1. Consolidate pre-checks into a single Curl_poll call: This is an attempt to restructure the code in Curl_multi_wait in such a way that less syscalls are made by removing individual calls to Curl_socket_check via SOCKET_READABLE/SOCKET_WRITABLE. 2. Avoid resetting the WinSock event multiple times: We finally call WSAResetEvent anyway, so specifying it as an optional parameter to WSAEnumNetworkEvents is redundant. 3. Wakeup directly in case no sockets are being monitoring: Fix the WinSock based implementation to skip extra waiting by not sleeping in case no sockets are to be waited on and just the WinSock event is being monitored for wakeup functionality. Assisted-by: Tommy Odom Assisted-by: Jay Satiro Bug: curl#6146 Part of curl#6245
Reset FD_WRITE by sending zero bytes which is permissible and will be treated by implementations as successful send. Without this we won't be notified in case a socket is still writable if we already received such a notification and did not send any data afterwards on the socket. This would lead to waiting forever on a writable socket being writable again. Assisted-by: Tommy Odom Assisted-by: Jay Satiro Tested-by: Tommy Odom Tested-by: tmkk on github Bug: curl#6146 Part of curl#6245
1. Consolidate pre-checks into a single Curl_poll call: This is an attempt to restructure the code in Curl_multi_wait in such a way that less syscalls are made by removing individual calls to Curl_socket_check via SOCKET_READABLE/SOCKET_WRITABLE. 2. Avoid resetting the WinSock event multiple times: We finally call WSAResetEvent anyway, so specifying it as an optional parameter to WSAEnumNetworkEvents is redundant. 3. Wakeup directly in case no sockets are being monitoring: Fix the WinSock based implementation to skip extra waiting by not sleeping in case no sockets are to be waited on and just the WinSock event is being monitored for wakeup functionality. Assisted-by: Tommy Odom Assisted-by: Jay Satiro Bug: curl#6146 Part of curl#6245
Reset FD_WRITE by sending zero bytes which is permissible and will be treated by implementations as successful send. Without this we won't be notified in case a socket is still writable if we already received such a notification and did not send any data afterwards on the socket. This would lead to waiting forever on a writable socket being writable again. Assisted-by: Tommy Odom Assisted-by: Jay Satiro Tested-by: Tommy Odom Tested-by: tmkk on github Bug: curl#6146 Part of curl#6245
1. Consolidate pre-checks into a single Curl_poll call: This is an attempt to restructure the code in Curl_multi_wait in such a way that less syscalls are made by removing individual calls to Curl_socket_check via SOCKET_READABLE/SOCKET_WRITABLE. 2. Avoid resetting the WinSock event multiple times: We finally call WSAResetEvent anyway, so specifying it as an optional parameter to WSAEnumNetworkEvents is redundant. 3. Wakeup directly in case no sockets are being monitoring: Fix the WinSock based implementation to skip extra waiting by not sleeping in case no sockets are to be waited on and just the WinSock event is being monitored for wakeup functionality. Assisted-by: Tommy Odom Reviewed-by: Jay Satiro Reviewed-by: Marcel Raad Bug: #6146 Closes #6245
Reset FD_WRITE by sending zero bytes which is permissible and will be treated by implementations as successful send. Without this we won't be notified in case a socket is still writable if we already received such a notification and did not send any data afterwards on the socket. This would lead to waiting forever on a writable socket being writable again. Assisted-by: Tommy Odom Reviewed-by: Jay Satiro Reviewed-by: Marcel Raad Tested-by: tmkk on github Bug: #6146 Closes #6245
User Jeffrey McKay has reported on the curl-library mailing list that after upgrading to 7.73.0 the upload performance decreased drastically. What was typically a 10 second upload took over 5 minutes.
(Click to expand his report) In summary, he describes it as "large chunks of data seem to be taking 1 second to upload".
I am able to reproduce in Windows and bisected it to d2a7d7c with the PostUpload example.
The 1 second delay is coming from this call to WSAWaitForMultipleEvents in multi_wait:
curl/lib/multi.c
Lines 1278 to 1282 in 315ee3f
Debug code:
Debug output (ret 258 is WSA_WAIT_TIMEOUT):
If that WSAWaitForMultipleEvents line is commented out then the transfer completes in the expected time (but then of course eats CPU in the interim since there's no poll wait).
According to the commit message in d2a7d7c, a previous version of that commit patch would erroneously wait the full timeout for the socket to become writable. It looks like that issue may not be fully fixed?
Ref: #5397
Ref: #5631
Ref: #5634
/cc @rcombs @mback2k @MarcelRaad @Togtja @ngg @rmja
The text was updated successfully, but these errors were encountered: