-
Notifications
You must be signed in to change notification settings - Fork 29.9k
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
Extensions using the "type" command (for ex. Vim) have poor performance due to being single-threaded with other extensions #75627
Comments
In general, I agree. But running each extension in its own separate thread has implications such as: text buffer memory duplication or a variant of a text buffer written in C++ that can be snapshotted and shared safely across threads, native node modules loaded by extensions in the ext host which are not multi-process aware, or sync API dependencies between extensions. It also means that the renderer process will need to host N extension hosts (sending messages to N different endpoints) with its perf implications... I don't think we will change this architecture too soon...
The extension that eats 1s from the event loop is definitely doing something wrong and should get a bug. IMHO, 1s is a very very long time to be blocking the event loop, even that of the extension host. |
That's true, but 1s is way longer than is required to make typing feel sluggish. Even 200ms could feel sluggish, and saying we shouldn't block for 200ms across any machines is an impossible task (I've had logs where things that take only 10-20ms on my machine, many hundreds of ms on some users machines). Even if extensions only ever blocked for shorter periods - some users have tons of them installed, so they could still easily add up. I understand it's hard to solve, but a lot of time goes into debugging performance issues (both by users and extension authors). I've personally spent a lot of time digging into this (I got a report that typing was super sluggish, and I was under the impression that keystrokes were always handled in the main VS process - it was a lot of digging to figure out what was actually going on - especially as I couldn't repro it for a long time because I didn't know about Vim and how it worked), and I'm certain I'm not the only one. If it's going to remain like this, maybe there should at least be a warning in the console the first time a keystroke takes longer than ` few hundred ms because it went via the extension host and was slow. That would've saved a lot of time. |
I agree and appreciate your frustration and wasted time on this and I am sorry about it... I don't have a good answer except to point out that things could be worse... I'm happy extensions are not running with the rest of VS Code on the renderer process... That was one of my contributions to the architecture of VS Code, one which I had to defend quite sternly to more experienced folks coming in with an Eclipse background (where everything is single proc, albeit with multiple threads, but oftentimes stuff ended up on the UI thread...), or looking at Atom or other editors... The current reality is that extensions today share a single event loop and that everyone needs to play nice (and yield every now and then) for things to work out well. Sharing a single event loop doesn't mean you can't do expensive stuff per-se, it means you shouldn't block for extended periods of time. If you were to yield every 10ms, in the spirit of "cooperative threading", things would work out... In any case, I am not against improving this, by all means I would like to have it better, but please accept that I believe it is difficult and costly to improve now, and it is not at the top of the list priority wise. We have all kind of automatic warnings when the extension host becomes unresponsive for a certain time, but nothing so small as a few hundred ms... It is also worth keeping in mind that for us, there is no correlation between pressing a keystroke and vim issuing an edit. In other words, typing ends up invoking the I am sorry I don't have better answers, I am open to ideas... For a while I thought that perhaps we should do a special case and have 2 extension hosts, one for vim, and one for everything else... |
FWIW, I'm also happy about this. It does add some limitations (for ex. the "Flutter UI Guides" in IntelliJ are synced perfectly to editing), but I hate a laggy editor - that's why I opened this issue to start a discussion - it feels like a backdoor :-)
Ofc, I didn't mean to sound like I thought you had to fix this - but I think it would be a shame to just close it "as designed" without thinking about options (even if they're way down the list).
Good point - I thought you could wait until the command finished executing (I presume you know when that happens) - but it didn't occur to me that it could do its own async work and return early :(
That's what I meant with "separate extension host for type-handling extensions might work" above. Assuming only one extension can take it, it could be an additional host just for the type-handling extension. It would be better if it wasn't Vim-specific ofc (which might mean you'd need something in the manifest to declare that it handles typing - which might not be a bad thing to ensure the user doesn't have two of them). Since you said "For a while", I presume you no longer think that? It does add complexity, but if supporting these kinds of extensions is important, it doesn't sound completely crazy to me (with my very limited understanding of VS Code :-)). It would solve the "who should fix this?" confusion with current behaviour - Vim should understandably be upset if other extensions hog the thread and make them perform badly, but it's easy for other extensions to argue "well you delegated your key presses to the extension host, you gotta deal with added latency during typing".. If it's not really obvious where the fault lies, it's likely not to be fixed by either. |
I am pretty bummed that we have brought the Vim extension to where it is now, and are constantly bombarded with performance issue reports. It is almost "good enough" but this caveat is enough to turn a percentage of users away from the experience and it is a bit demoralizing at times to have no path forward. Thanks for the explanations in this issue report though, the comments have cleared up a few things for me. |
The Rust analyzer extension also uses this command: I suspect its use will become more common as extensions want to provide additional functionality that the VS Code API doesn't support. I think this problem is only going to get worse. Maybe as a start, VS Code should prompt users when an extension registers this (like it does when an extension tries to override |
However desirable it may be in theory to run extensions in a separate process, in practice, the way that was implemented in VSCode has resulted in far worse and less likely to get fixed Vim emulation performance than all of the following IDEs:
When it comes to user experience I prefer IDEs that take the risk of running extensions in process, even when buggy extensions have ended up crashing the process. |
@bpasero @jrieken @joaomoreno @mjbvz @isidorn @alexdima @sandy081 @Tyriar @aeschli @roblourens I'm happy to try to dig in and implement a solution, but I'll have to know what kinds of core architectural changes would be approved so I don't spend my time in vain (because fixing this will take core architectural changes). It's really disappointing to see new features being added when catastrophic technical debt performance issues like this languish. If you're not a Vim user, you probably don't realize how awful it is. I usually even have to disable the builtin TypeScript and JavaScript langauge features extension to get acceptable keyboard responsiveness. At this point, my own workflow with VSCode extensions I've contributed to the ecosystem is the only thing keeping me hanging on to VSCode. But I'll have to jump ship and start contributing to another IDE ecosystem if this issue doesn't get fixed. |
@jedwards1211 Can you please profile the extension host the next time you notice typing is unresponsive for you? This can be easily done by opening |
@alexdima fixing extensions one at a time, forever, is not a reasonable answer to this problem. Text input clearly needs special handling - whilst it would be nice for non-interactive extensions to also do the right thing, they do not need to be on the critical path, however text extensions do. |
This problem two years ago is still unresolved. For me, vim is irreplaceable, but vscode is replaceable. If fleet is released, I think I will give up vscode, which is really frustrating. |
In our latest Insiders Build, we have added a new experimental setting that would allow to execute the vim extension in a dedicated extension host process. Configure the following in your
You can double check that vim is loaded in a separate process using |
@alexdima can we expect this to come in the next release? I'm hesitant to move to Insiders from stable (just as a general rule of thumb) but am willing to move over if it'll be "experimental" for a while before officially released. UPDATE: today's 1.66 release of VSCode has apparently added this setting (although it isn't noted in the changelog, as far as I can tell). I'll take it! |
This feature came too late. It's available now and it's great. |
This fix is working great for me. Both the |
Does affinity work on https://vscode.dev/ as well? |
Thanks to #164150 , it will also work on |
Thank you. This makes a huge difference 👍 |
I'm using M1 mac. arm 64 version is here |
Windows x86_64. A lot better, but still not at IntelliJ VIM / terminal VIM speed. (C# omnisharp file analysis running in background on 350 files w/ .NET host ~50% CPU usage) |
I stumbled upon this issue while searching for laggy typing and missed input. After running the profiler I found two extension that had >150ms runtime where other had <1ms: vim and Intellicode. Using the affinity setting I moved vim out of the way (affinity=1), but the lagginess remained. I also moved intellicode (and the intellicode completion extension) in yet another process (affinity=2 for both of them), and the issue disappeared. Thanks for that. I'm not sure how desirable it could be to auto-adjust this setting when some extension misbehave, but even as a clutch it works well enough. |
I'm having this issue re-appear after seemingly being fixed a few months ago with the affinity setting. It seems to be an interaction of two or more extensions. If I disable either pylance or vscodevim, it seems to work happily. But with both of them installed, as soon as I start typing something (in insert mode), I get crazy lag and skipped and repeated keystrokes (and sometimes it treats inline blame annotations (via Gitlens) as actual text in the editor). While the madness is happening (and indeed, every single time I start typing something, VSCode starts analyzing some number of files). Restarting VSCode doesn't fix the issue. |
I don't know if this is a known/accepted issue, but I've had a number of users complain of poor performance in the editor when using my extension along with the Vim extension.
This appears to be because the Vim extension uses the
type
command to handle keypresses (in the extension host). This means if pressing a key triggers a command that blocks in another extension (for example the first character press can trigger code completion, which if the list is 20,000 items can block the thread for a little while while they're build + serialised) the typing in the editor is really sluggish.You can easily reproduce this by making an extension that blocks for 1s when asked for completions:
If you run this and enabled the Vim plugin, when you start typing on a newline (which triggers completion), the characters you type won't appear for a while.
Of course, extensions should try to avoid blocking the extension host as much as possible, but sometimes it's unavoidable (for ex. assembling and serialising a huge number of completion items). It's not clear where users should raise bugs, since in isolation neither extension is really doing anything wrong.
I don't know what the fix is (separate extension host for type-handling extensions might work, but that might also be a huge task), but I couldn't find any issues discussing this and figured it was worth some discussion (even if only to have the information described in one place we can point people to that hit these issue).
The text was updated successfully, but these errors were encountered: