This PR allows Vim to run at the same priority as GUI applications on macOS. This makes Vim as responsive as other apps are when the system is under load.
https://github.com/user-attachments/assets/530051c2-3c5b-4dff-b95d-e244ac2e414a
The left terminal is before, and the right terminal is after. At first the system isn’t under load and both Vim instances scroll smoothly. Once I start a test program which pins all the cores of my machine, the left Vim instance’s responsiveness falls dramatically while the right one is barely affected.
Please let me know if I’ve put the code in the wrong spot, or if I should expand on how this change works.
https://github.com/vim/vim/pull/18120
(2 files)
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
@ychin please?
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
I'm honestly not sure about this. I cannot find a single example of another CLI tool that does this. I think one concern I have is that Vim can sometimes do pretty heavy work (e.g. running Vimscript) since it's a mostly single-threaded program. If you raise this to the UI level QoS I am a little worried that it will start starving resources from other programs if you are running a busy script, since Vim doesn't have a clearcut "UI thread" so to speak. Meanwhile, even interactive shells like bash / zsh are all using the same "default" QoS and it doesn't seem like people are complaining about them lagging? I'm just trying to see what are comparable here and what the impact would be.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Even though Vim sometimes performs heavy tasks on the main thread, GUI apps do this all the time too, and is actually all the more reason to use User Interactive QoS for Vim’s main thread! Starving other User Interactive tasks of CPU time here is good because what the user cares about is Vim (which likely is what they’re interacting with if Vim is processing something) being responsive, not other apps, and so it deserves all the CPU time it can get. It’s worth noting that Vim cannot affect the responsiveness of AppKit animations, moving around windows, Mission Control, etc because those tasks are performed by WindowServer, which runs at an AboveUI realtime priority. Also, the foreground GUI app is marked as “urgent” in the scheduler, so even if Vim is stuck searching for matches in a 100 KLOC file in the background it shouldn’t hugely affect the foreground app’s responsiveness.
If you look at the documentation Apple provides on what to use the various QoS classes for (1, 2, 3) it’s evident that the prime concern (outside of realtime tasks like audio) is to always keep the user interface responsive. And yes, shells and Vim are a form of user interface – if their main threads are preempted, then the interface will appear to be frozen. I suspect the reason why Apple clamps processes to Default QoS by default is that most processes on the system don’t present UI; the responsiveness of interactive command-line tools isn’t important enough to warrant an exception. Many command-line tools (like compilers, for instance) perform batch work which ideally would be demoted to Utility QoS, if anything.
I agree that this is a highly nonstandard thing for a command-line tool to do, but in my opinion Vim is important enough to warrant it.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Isn't Vim’s UI requirement similar to that of an interactive shell? Both are extremely lightweight and based on ncurses. The real “heavy” UI is provided by the terminal emulator itself (e.g., Terminal, iTerm). That makes TASK_DEFAULT_APPLICATION feel more appropriate for the terminal emulator rather than for Vim.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
That makes TASK_DEFAULT_APPLICATION feel more appropriate for the terminal emulator rather than for Vim.
I tend to agree for a terminal Vim. For a gui vim binary it may be a different thing however.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Terminal emulators are assigned TASK_FOREGROUND_APPLICATION and TASK_BACKGROUND_APPLICATION by the OS automatically. In my opinion both Vim and an interactive shell would ideally use TASK_DEFAULT_APPLICATION, since they conceptually “inherit” the terminal emulator’s priority because interaction with the terminal emulator is blocked on the program running in it responding. I’m not sure I understand why any of this would be different for CLI Vim vs GUI Vim.
One way to think about QoS is by looking at what work runs in each class:
IMHO it doesn’t make sense to let Vim lag while you open a large Word document, for instance.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
because interaction with the terminal emulator is blocked on the program running in it responding
We don’t want the terminal emulator’s UI to freeze when Vim is busy executing Vimscript/plugin or saving a file (to an older SSD) though. That means the first two QoS items in your list don’t really apply to Vim. Which QoS level would you say Vim is currently at (in your list)?
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
We don’t want the terminal emulator’s UI to freeze when Vim is busy executing Vimscript/plugin
Although you’re right, this will basically never occur in practice: an intensive Vim script would only occupy a single core, and the chance of every other core being busy with more User Interactive work (meaning the terminal emulator doesn’t get enough CPU time) is essentially zero. On top of that, foreground GUI apps are special-cased in the scheduler as “urgent”, so the terminal emulator would win any resource contention fights. If we really want to, we could call pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, -1) on the main thread to slightly depress its priority while staying within the User Interactive QoS class.
That means the first two QoS items in your list don’t really apply to Vim.
I don’t see why this would be the case? Vim does interactively respond to user events and draw UI.
Which QoS level would you say Vim is currently at
Since Vim has the default role of TASK_UNSPECIFIED all its threads are clamped to Default. This, along with every QoS class except for User Interactive, is inappropriate for Vim’s main thread.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Laptops often shut down all but one CPU core when running on low battery. Vim’s scheduling design cannot depend on multi-core always being present.
The “default” QoS setting sits below GUI applications but above background processes, which makes it appropriate for basic TUI programs such as Vim.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Laptops often shut down all but one CPU core when running on low battery
macOS does not do this.
Vim’s scheduling design cannot depend on multi-core always being present.
Even if you were to hypothetically disable all but one CPU core, Vim and the terminal emulator would still work correctly with this PR because the terminal emulator runs at a higher priority.
“default” QoS … appropriate for basic TUI programs such as Vim
This is incorrect. Vim handles user input and renders UI, & therefore its main thread ought to run at User Interactive.
I frequently run into second-long hangs when I try to use Vim while Instruments is stuck on “Modeling data stream…” because that task loads all my cores at User Initiated QoS. I would suggest you refer back to the screen recording I posted originally, which simulates this exact load and demonstrates meaningfully improved responsiveness.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
macOS does not do this.
What if Apple changes this design in the future?
Vim’s scheduling design cannot depend on multi-core always being present.
Even if you were to hypothetically disable all but one CPU core, Vim and the terminal emulator would still work correctly with this PR because the terminal emulator runs at a higher priority.>
No. Already discussed: #18120 (comment)
“default” QoS … appropriate for basic TUI programs such as Vim
This is incorrect. Vim handles user input and renders UI, & therefore its main thread ought to run at User Interactive.
Would you suggest that man, cat, less, and other Unix programs that handle user input (such as scrolling or searching) be recompiled with a higher QoS priority?
I frequently run into second-long hangs when I try to use Vim while Instruments is stuck on “Modeling data stream…” because that task loads all my cores at User Initiated QoS. I would suggest you refer back to the screen recording I posted originally, which simulates this exact load and demonstrates meaningfully improved responsiveness.
Perhaps the Instruments program should assign a lower priority to background tasks, isn't it? In cases like this, the right solution is to recompile Vim locally with your preferred QoS priority—rather than imposing that change on everyone as a general solution.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
What about (neo)mutt, mc, tig, weechat?
I am slightly negative about this change. It seems this is done at the wrong level, I really think this should be done at the terminal level and not each application needs to set this on its own, just because they receive user input and are drawing a UI.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
What about
(neo)mutt,mc,tig,weechat?
Ideally, yes, they’d make this change too. I imagine that Vim is the only TUI application for which this is really needed, though, because it’s so frequently-used and because scrolling is such a common operation.
I am slightly negative about this change. It seems this is done at the wrong level, I really think this should be done at the terminal level and not each application needs to set this on its own, just because they receive user input and are drawing a UI.
In theory, yes, I agree with you. In an ideal world Apple would automatically set a process’s role as appropriate if it enables raw mode, or something like that. (Any heuristic to distinguish interactive TUIs from batch processing CLIs could work.) Unfortunately this is not the world we live in – I suppose TUIs are just not important enough for the scheduler to special-case them – and we should support the macOS we have, not the one we wish we had.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Okay. Is there any impact to such a Vim running in a background? Or does it only affect a process running in the foreground?
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
This PR increases the priority of Vim even when it’s in the background. This won’t affect the foreground app’s smoothness, though, because:
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
I see thanks
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
I'll merge it under the assumption that this improves responsiveness on MacOS. But I'll revert it, if this causes any complaints.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()