-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
[windows] Use non blocking reads and writes #1221
Comments
Noteshttp://tinyclouds.org/iocp-links.html
https://msdn.microsoft.com/en-us/library/ms679360(v=vs.85).aspx
|
not sure I can help out with the C++ side, but happy to manually test! Let me know 😁 |
Async isn't always async. Dunno if it applies here. https://support.microsoft.com/en-us/help/156932/asynchronous-disk-i-o-appears-as-synchronous-on-windows |
General question regarding this - is it possible that this will help the CPU usage go below 30%? Maybe 5%-10%? |
Yes
|
I have a working proof-of-concept using WriteFileEx and (incorrectly) CreateThread. Need to use uv_thread_id, implement the same for Read'ing, and clean it up. Will possibly have a PR by end of week? |
Woh! This is great! Why do we need threads? |
From WriteFileEx: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365748(v=vs.85).aspx "When this I/O operation finishes, and the calling thread is blocked in an alertable wait state, the operating system calls the function pointed to by lpCompletionRoutine" An alertable wait state, from Alertable I/O: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363772(v=vs.85).aspx "To do this, it must enter an alertable state. A thread can only do this by calling one of the following functions with the appropriate flags: ..." The WriteFileEx calls needs to be on a thread that can be blocked (with something like SleepEx), otherwise the OS won't call the async callback. Perhaps there's something I'm missing with regards to how node's events work, but I think the only way to do this is use a thread from the uv pool. Hacking on it today, I couldn't get the callback to ever trigger with everything staying on the main event loop thread. Hope this doesn't conflict with the expected utilization and performance improvements. |
Actually, since the libuv threadpool only allows 3 or 4 threads, as mentioned a few times in this thread (sorry!) perhaps the correct solution is to actually use CreateThread for the WriteFileEx call and callback. That way, the libuv pool won't be exhausted. A new thread will be created for each write operation, which I don't understand the consequences of quite that well, but it doesn't seem possible to avoid it. |
There will only ever be a single write per port going on at one time. I
don't know if that helps.
…---
Francis Gulotta
[email protected]
On Tue, Aug 15, 2017 at 9:14 PM, Dustin Long ***@***.***> wrote:
Actually, since the libuv threadpool only allows 3 or 4 threads, as
mentioned a few times in this thread (sorry!) perhaps the correct solution
is to actually use CreateThread for the WriteFileEx call and callback. That
way, the libuv pool won't be exhausted. A new thread will be created for
each write operation, which I don't understand the consequences of quite
that well, but it doesn't seem possible to avoid it.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#1221 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AABlbkcCBodHNhnVOO_muusjIU_mPt63ks5sYmy2gaJpZM4OPBf1>
.
|
Update on my status:
Another possible approach would be to have two separate HANDLEs, one for reading and one for writing, so that reading could use WaitForSingleObject to see if there's data ready on the input buffer. I haven't tested this yet to see if it could work; I will put it off until later as a separate change. I've been figuring this out using a stand-alone command-line application, so will need to integrate into Serialport, which shouldn't be too difficult at this point. |
Wohhh! This is great!
|
…ws (#1313) Instead of ReadFile and WriteFile, which block and transfer data synchronously, use ReadFileEx and WriteFileEx, which both allow async callbacks. In addition, change how timeouts are used for ReadFile*, using an unlimited timeout for the first byte, and no timeout for the rest of the data in the input buffer. This removes the need to poll entirely, while still retrieving all data available in the input buffer. In both cases, the I/O operations happen in their own threads, since Windows requires IOCompletion callbacks to wait for their calling thread to be in an "alertable wait state". Fixes #1221
Some notes from testing;
|
Instead of ReadFile and WriteFile, which block and transfer data synchronously, use ReadFileEx and WriteFileEx, which both allow async callbacks. In addition, change how timeouts are used for ReadFile*, using an unlimited timeout for the first byte, and no timeout for the rest of the data in the input buffer. This removes the need to poll entirely, while still retrieving all data available in the input buffer. In both cases, the I/O operations happen in their own threads, since Windows requires IOCompletion callbacks to wait for their calling thread to be in an "alertable wait state". Fixes serialport#1221
Have some questions about the above testing results:
Should be fixed, now, if I understand correctly. I merged in the same fix from #1322 into the new PR.
I don't have a way to test this. Is this a regression? Does the current implementation handle it correctly?
How do I run this?
Is this the same as |
The previous implementation would block the libuv thread pool which has 4 threads by default. So worst your case your implementation does the same. full test suite is |
Instead of ReadFile and WriteFile, which block and transfer data synchronously, use ReadFileEx and WriteFileEx, which both allow async callbacks. In addition, change how timeouts are used for ReadFile*, using an unlimited timeout for the first byte, and no timeout for the rest of the data in the input buffer. This removes the need to poll entirely, while still retrieving all data available in the input buffer. In both cases, the I/O operations happen in their own threads, since Windows requires IOCompletion callbacks to wait for their calling thread to be in an "alertable wait state". Fixes #1221
Keeping this open because we need to verify the # of concurrent arduinos we can run.
|
So far I haven't gotten support requests for this. It's passed my muster. I think it's worth going to prod. I can't actually test how many concurrent connections we can make, it wouldn't be worse. We'll know for sure eventually. |
…ws (#1313) Instead of ReadFile and WriteFile, which block and transfer data synchronously, use ReadFileEx and WriteFileEx, which both allow async callbacks. In addition, change how timeouts are used for ReadFile*, using an unlimited timeout for the first byte, and no timeout for the rest of the data in the input buffer. This removes the need to poll entirely, while still retrieving all data available in the input buffer. In both cases, the I/O operations happen in their own threads, since Windows requires IOCompletion callbacks to wait for their calling thread to be in an "alertable wait state". Fixes #1221
Instead of ReadFile and WriteFile, which block and transfer data synchronously, use ReadFileEx and WriteFileEx, which both allow async callbacks. In addition, change how timeouts are used for ReadFile*, using an unlimited timeout for the first byte, and no timeout for the rest of the data in the input buffer. This removes the need to poll entirely, while still retrieving all data available in the input buffer. In both cases, the I/O operations happen in their own threads, since Windows requires IOCompletion callbacks to wait for their calling thread to be in an "alertable wait state". Fixes #1221
We need help with this one!
Right now we can only support 3 or 4 ports open at a time in the same process on windows unless the env var
UV_THREADPOOL_SIZE
is set to something higher than 4. This is because we're usingWriteFile
andReadFile
for our reads and writes which are blocking. We should transition toWriteFileEx
andReadFileEx
which support callbacks when data is read or written. This should allow us to support "any" number of ports and have lower cpu utilization.Relevant code; EIO_Write and EIO_Read
The text was updated successfully, but these errors were encountered: