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
kqueue.go: Remove timeout from reading kevents. #262
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
wasn't actually merged to master -- issue is still there. |
Expect a new release. This problem has caused me a big headache. |
7b30a8c
to
47b309e
Compare
Is it possible to merge this? Just rebased it against master, and we've been running with this patch on our software for about 8 months now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @paulquerna-okta @wweir and @gdey.
47b309e
to
ae21739
Compare
Rebased against current master -- just a note we've been running this patch for 18 months to reduce CPU usage on our MacOS app. Without it the app would consistently show up Activity Monitor's Energy tab. |
Any chance this could be merged in? |
ae21739
to
7206899
Compare
Instead of having a timeout that would trigger the readEvents to check it's done channel, run a seaprate go-routine that watches w.done, and directly closes the KQueue FD. This change allows a go-process to fully sleep and go into CPU idle mode, instead of waking up every 100ms on macOS.
7206899
to
21efafc
Compare
On FreeBSD and NetBSD this blocks forever on:
Called from the main event loop:
kqueue(2) on FreeBSD says:
kqueue(2) on OpenBSD and macOS have the same language; I added some debug printf statements, and got: OpenBSD:
FreeBSD:
So the difference is that on OpenBSD Kevent() will return if the file descriptor is closed, whereas on FreeBSD it won't. I assume it's the same on macOS, but I didn't try that yet. I can't really find this behaviour documented anywhere, and seems to be something of an implementation detail that may change on macOS and OpenBSD in the future too. Some other (minor) issues:
And my printf debugging, in case it's useful to anyone else:
|
#124 seems to fix the same problem, and doesn't seem to have any of the above issues in a quick check. Updated branch here, but needs some more work as it's a pretty old branch: https://github.com/fsnotify/fsnotify/tree/kqueue-no-timeout |
The timeout for unix.Kevent() is causing issues; every 100ms it will do a new unix.Kevent() syscall, which isn't too efficient: even if you have just one change an hour, you will still keep calling kevent() ten times per second, resulting in a needlessly high CPU usage. Without a timeout, kevent() will block indefinitely until there are some events, which is much more efficient. We can't just remove the timout however, since we can't interrupt the kevent() call on FreeBSD and NetBSD, and it will hang forever. This issue is described in more detail here: #262 (comment) To solve this we register a new kevent() with the file descriptor set to the closepipe; when this pipe is closed an event is sent and kevent() will stop blocking. This is a rebased version of #124. Fixes #89 Fixes #237 Fixes #333 Supersedes and closes #124 Supersedes and closes #262 Supersedes and closes #334
I created #480, which should solve this issue better. |
The timeout for unix.Kevent() is causing issues; every 100ms it will do a new unix.Kevent() syscall, which isn't too efficient: even if you have just one change an hour, you will still keep calling kevent() ten times per second, resulting in a needlessly high CPU usage. Without a timeout, kevent() will block indefinitely until there are some events, which is much more efficient. We can't just remove the timout however, since we can't interrupt the kevent() call on FreeBSD and NetBSD, and it will hang forever. This issue is described in more detail here: #262 (comment) To solve this we register a new kevent() with the file descriptor set to the closepipe; when this pipe is closed an event is sent and kevent() will stop blocking. This is a rebased version of #124. Fixes #89 Fixes #237 Fixes #333 Supersedes and closes #124 Supersedes and closes #262 Supersedes and closes #334 Co-authored-by: Felix Lange <fjl@twurst.com>
The timeout for unix.Kevent() is causing issues; every 100ms it will do a new unix.Kevent() syscall, which isn't too efficient: even if you have just one change an hour, you will still keep calling kevent() ten times per second, resulting in a needlessly high CPU usage. Without a timeout, kevent() will block indefinitely until there are some events, which is much more efficient. We can't just remove the timout however, since we can't interrupt the kevent() call on FreeBSD and NetBSD, and it will hang forever. This issue is described in more detail here: fsnotify/fsnotify#262 (comment) To solve this we register a new kevent() with the file descriptor set to the closepipe; when this pipe is closed an event is sent and kevent() will stop blocking. This is a rebased version of #124. Fixes #89 Fixes #237 Fixes #333 Supersedes and closes #124 Supersedes and closes #262 Supersedes and closes #334 Co-authored-by: Felix Lange <fjl@twurst.com>
What does this pull request do?
Instead of having a timeout that would trigger the readEvents to check it's
done channel, run a seaprate go-routine that watches w.done, and directly
closes the KQueue FD.
This change allows a go-process to fully sleep and go into CPU idle mode,
instead of waking up every 100ms on macOS.
Fixes #237