-
Notifications
You must be signed in to change notification settings - Fork 38
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
Don't poll every second for kevents #22
base: master
Are you sure you want to change the base?
Conversation
I see, good idea to have a custom event to stop observing instead of polling all the time. |
Hey guys. Thanks for the all the activity. I'm happy to merge when I have time, but FSEvents is a much more performant, modern way to watch for file activity. I dropped kQueues from my apps many years ago when Apple finally fixed the huge FSEvents bug in OS X 10.11, El Capitan. If it's possible for you to migrate to FSEvents, I highly encourage that over using kQueues. |
Hi @bdkjones .
It's a bit hard to tell which ones are real improvement: |
@Coeur Yea. VDKQueue is a fork of UKKQueue, which I used back in 2008. I didn't write most of this; I just tweaked a few parts that I needed for my apps back then. I can tell you, definitively, that FSEvents works great for watching single files. I use it like that to watch literally hundreds of thousands of files and it's been flawless and easy to manage. |
(before I forget, my original patch deleted _keepWatcherThreadRunning=NO, but you actually still need that line or else the thread will never start back up again when you add new files) |
Regarding the alternatives, GCD and DispatchSource are really the same thing (DispatchSource is just the Swift version of gcd dispatch sources), and yes they use kqueue under the hood. NSFilePresenter, as I understand it, only works with other apps that adopt NSFilePresenter, so that's a no-go. So that just leaves FSEvents. In my project I actually am using both kqueue and FSEvents. FSEvents is especially useful with the On the other hand, FSEvents makes you declare the list of directories that you're interested in when you create the stream. You can't modify the list of directories; you'd have to destroy the current stream and create a new one with an updated array of paths, or create a new stream with the new paths that you're interested in. So conceptually it's a bit different from kqueue, where you can set up one fildes and add individual paths (whether files or directories) as you go along. @bdkjones when you're watching hundreds of thousands of files are you creating hundreds of thousands of FSEventStreamRef's? Or do you mean you're watching one directory with hundreds of thousands of files in it? I'm also curious as to why you say FSEvents is more performant... I can't seem to find anything online that compares the performance of it vs kqueue. How are you measuring performance here? |
I create one stream with multiple folders containing all the files I’m interested in. It’s more performant because there’s one fewer process constantly switching between kernel and user space, which is expensive. It also does not involve polling, which is much more power efficient on portables. Finally, the FSEvents daemon is optimized by Apple and a single process supplies information to every subscriber—less overhead, fewer resources used.On Dec 28, 2023, at 18:29, Dominic Yu ***@***.***> wrote:
Regarding the alternatives, GCD and DispatchSource are really the same thing (DispatchSource is just the Swift version of gcd dispatch sources), and yes they use kqueue under the hood. NSFilePresenter, as I understand it, only works with other apps that adopt NSFilePresenter, so that's a no-go. So that just leaves FSEvents.
In my project I actually am using both kqueue and FSEvents. FSEvents is especially useful with the kFSEventStreamCreateFlagFileEvents flag, which will, for example, give you individual events if files get added to the directory you're watching. This definitely beats using kqueue and having to compare before-and-after snapshots of your directories.
On the other hand, FSEvents makes you declare the list of directories that you're interested in when you create the stream. You can't modify the list of directories; you'd have to destroy the current stream and create a new one with an updated array of paths, or create a new stream with the new paths that you're interested in. So conceptually it's a bit different from kqueue, where you can set up one fildes and add individual paths (whether files or directories) as you go along. @bdkjones when you're watching hundreds of thousands of files are you creating hundreds of thousands of FSEventStreamRef's? Or do you mean you're watching one directory with hundreds of thousands of files in it?
I'm also curious as to why you say FSEvents is more performant... I can't seem to find anything online that compares the performance of it vs kqueue. How are you measuring performance here?
—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you were mentioned.Message ID: ***@***.***>
|
Got it. Yes, in your case (one list of directories where you're interested in everything in them) FSEvents is clearly the superior choice. I think kqueue is still more appropriate for certain use cases, e.g., if you're interested in a number of specific paths that may change over time (and if you're interested in specific files, rather than directories, kqueue is your only option). The polling problem is basically eliminated with this pull request, though. |
@synchronized(self) | ||
{ | ||
// Shut down the thread that's scanning for kQueue events | ||
kevent(_coreQueueFD, &(struct kevent){0, EVFILT_USER, EV_ENABLE, NOTE_TRIGGER, 0, NULL}, 1, NULL, 0, &(struct timespec){0,0}); |
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.
I could be wrong, but I think that EVFILT_USER
is not enough to assert that the event was created by us: it could be a different app also sending an EVFILT_USER
event. So we'll want a custom udata containing [[NSProcessInfo processInfo] processIdentifier]
instead of NULL, so that we can compare it with our own pid before shutting down the thread.
[edit]
Or maybe it doesn't matter, but I would rollback the while(1)
back to while(_keepWatcherThreadRunning)
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.
You can't send EVFILT_USER events to a different process. That would be some crazy easy interprocess communication. (Just as a sanity check I just tested this with two separate processes and verified you can't send kqueue user events from one to the other.) Even in the same process when you post a EVFILT_USER event you have to post it to a specific kqueue, it doesn't broadcast it to every thread waiting for a kevent.
@gobbledegook I wrote a possibly simplified version of your idea, by sending only a single |
ooh I like it! |
So, I decided to take steps and maintain a fork of VDKQueue: It has mostly all my pull requests included, and gobbledegook suggestions, and warnings/format fixed, and readme documented with the alternatives like FSEvents. |
In the watcher thread there is this comment:
Polling kqueue once a second is inefficient and kind of seems to defeat the purpose of using kqueue in the first place. The correct way to do this is to basically send a signal telling the thread to terminate. I believe the method here (see the second commit in this pull request) takes care of this, by registering for, then triggering a "user" event.
Hopefully this is useful for someone out there!
(@Coeur I realize this repo isn't maintained anymore, but it's easier for me to post this here than having to clone the entire source of Transmission)