I think that nativecomp represents a huge leap forward for emacs. I continually give kudos to Andrea Corallo and the entire team for making this a possibility.
I think that the next major leap for emacs needs to involve the garbage collector and allocation logic. I think that a large class of performance optimizations would be possible with an improved GC, including improvements to emacs existing threading capabilities.
I think nativcomp doesn't really improve what makes emacs "slow".
Emacs is a single threaded synchronous and blocking UI system. Sometimes when my autocomplete, C++ checking, git checking, auto formating, ... run, the editor freezes, for multiple seconds.
All this stuff runs in the UI thread. Braindamaged.
The other thing that makes emacs slow is remote editing. Emacs TRAMP uses one ssh connection per command. VS Code spawns a remote server and asynchronously updates the remote's state. VS Code remote editing experience is as good as the local one, but emacs experience is supper laggy, recurrent freezes of multiple seconds, etc. Particularly when navigating the filesystem in the remote in any modern emacs way (helm, ido, etc.). Or when auto-save happens and everything blocks for multiple seconds, etc.
---
I don't really care if native compilation makes single threaded code faster, if that single threaded code runs in the UI thread and blocks the editor for 10 seconds. Sure now it maybe blocks for 9 seconds, because you can't do much about those 9 seconds you have to wait for some IO operation to complete. But that still sucks.
A lot of this is down to configuration. For example, you say “Emacs TRAMP uses one ssh connection per command”, but that’s only true if you’re not using the ControlMaster SSH option. Add this to your ~/.ssh/config file:
ControlMaster auto
ControlPersist yes
ControlPath ~/.ssh/control/%C
Then run mkdir -p ~/.ssh/control/, if you haven’t already. Why this isn’t the default I don’t know, but once configured correctly you won’t have any problems from TRAMP.
I have this, yet I still see emacs sending individual I/O operations over SSH and blocking on their completion.
Everything that requires remote file system interaction is super slow. Emacs just seem to be doing lots of individual I/O operations.
VScode has a remote server that batches them before updating over the network.
The client sends operations to the server and queries the server for updates asynchronously. The server can perform multiple operations, and batch them into one response.
Stuff like, "regex on all files in this directory" is performed by emacs as "list all files in directory, wait, for each file, regex that file, wait". VScode just sends the "regex all files" and the server locally handles everything, and send one update back.
The difference is going from < 100ms for VSCode vs 5 seconds for emacs. Night and day.
The same happens for pretty much every modern feature (git status, diffs, blames and updates, autocompletion, correctness checks / intellisense, etc.).
This varies from command to command, but M-x grep literally just runs the program grep on the remote machine. It doesn’t enumerate the files and search each one individually. If you’re using something other than M-x grep, then sure, it might be written badly.
You might have already tried this: I’ve had fantastic performance starting a remote emacs server and using emacs (often in terminal mode) through ssh. It certainly has a one time cost: setup your local terminal for all keys to go through, and sync your init files. I still use tramp for certain rare cases but most work happens on 3 remote and 1 local machine with four different emacs servers running, and a couple of additional non-development machines that I simply ssh into from within emacs shells.
> The same happens for pretty much every modern feature (git status, diffs, blames and updates, autocompletion, correctness checks / intellisense, etc.).
Could it be a configuration issue in parts at least? Because it does start to sound like it. For example git status has never been slow for me in Emacs, except for huge diffs with lots of changes in lots of files. Same for diffs. I know, that autocompletion depends on the language and tools used for it and what things are checked for possible auto completion entries. It is possible to limit autocompletion to only use some sources, or to make it use a language server for some languages. When developing Rust, Python or TypeScript in Emacs, I did not experience slow correctness checks (I assume you mean type checks and unused variable kind of stuff.).
I searched a little and found the following blog, which claims, that there are issues with it, when you do heavy data transfers, for example via many rsyncs at the same time:
I suppose that’s a good point. With multiple large simultaneous flows, multiple TCP connections probably will be better, unless SSH goes to all of the trouble to reimplement all of TCP’s nicer features. And at that point you should just be using a real VPN anyway.
I wonder if ssh shouldn’t have a sensible default like ~/.ssh/control/%C for ControlPath, so that you could just turn on ControlMaster and have it just work. Then TRAMP could set the ControlMaster option on the command line when it runs ssh. At least then people wouldn’t have to mess with their SSH config, and they wouldn’t have to consider whether it will break something else.
Emacs is definitely capable of multithreading. Still using a single thread might actually be a boon because it simplifies the programming model. Right now, Elisp code can work under the assumption that there is only one thread accessing editor state at the same time.
Disentangling this is probably going to be difficult, but the Emacs folks are probably smart enough to come up with something that matches with the spirit of Emacs. Libuv and callbacks might be a way, but cooperative scheduling of user threads on backing threads together with structured concurrency, like Java's Project Loom is attempting, are another way.
The emergence of the LSP protocol is a very promising development in the architecture of editors and IDEs. Many things can and maybe should be passed off to background processes to handle, both to expand the feature set of every editor out there, and to increase speed and stability.
To outsource things step-by-step to lightweight processes seems to be a good incremental way to disentangle. Perhaps one could protect access to resources not initially invented by Emacs packages (Emacs core?) and make Emacs query a separate process, without a package knowing about that, so that it channels all communication to the separate process. Then deprecate directly the resource at some point and offering a more direct way of communicating with the separate process. Finally removing the state in the main process. I think more Emacs internals knowledgeable people would need to judge this idea.
Is there anything in the communication of LSP making the LSP stand out from any other protocol? (I really mean the protocol, not the infrastructure on which it is used.) Other than that it is quite an old idea to have things at the ready running in a separate process. This time it is applied to editors, completion, type checking and other features. In general this simplifies making use of multi-core systems. Watch any Joe Armstrong talk about it. The question is, why it was not thought of before, or perhaps, if it was, then why it was not done before.
In terms of LSP, I don’t think there’s anything particularly novel about it. It’s really only better than other similar protocols in the sense that it is gaining in popularity. I.e., the biggest thing that was missing is consensus on a shared protocol.
In terms of the protocol itself, I suspect it’s actually worse than a lot of other ones.
> I suspect it’s actually worse than a lot of other ones.
Choosing JSON to communicate certainly could have been more wisely decided. Moreover since sending entire file contents across for some queries, what a waste.
It indeed isn't. Some Emacs packages use that approach, and others are well-known to employ Unix utilities to do the legwork. Maven and Gradle both have daemon modes. Unfortunately, all these integrations are custom, so there is no chance for it to take off. Ycmd is also worth mentioning.
What really made the difference is that VS Code uses LSP to integrate languages. Instead of dozens of ad-hoc integrations, there is one unified way to integrate a language now, and Microsoft's backing ensured there is an ecosystem for it from day one.
Not all is rosy though, mind you. LSP uses JSON/RPC after all. Also, we are touching the Microsoft world here, which means that standard adherence is not necessarily a given[0].
Indeed. It does not need precisely multithreading, but at least asynchrony, which is to allow side tasks to not block the main function of editing text. I have low familiarity with emacs internals, but I can assume there is an event loop, which is a basic form of this.
Perhaps this needs be used more, or there is another mechanism to be developed allowing tasks to be interrupt/resumed in priority service to the editing functions. A key example may be mode line refresh: this certainly must happen on the main thread, but it ought not block other more important items.
With a few exceptions, I don't think moving stuff into the background promotes speed and stability. It makes it way easier to get away with reductions to both.
The first consumer processors with multiple cores came out around 2005. Before there were multiple cores in consumer machines, there was no reason to implement concurrency in a way that would scale to multiple cores.
Not to mention, back when the Emacs we know today was created, there weren't many GUI platforms available in the first place. First public release of GNU Emacs - the one with Emacs Lisp - was in 1985, so the Emacs we know is ~3 years older than X11. Emacs added GUI support in 1986[0] - before X11 was a thing (though X itself existed since 1984).
Emacs started as a terminal app, the GUI was added as an afterthought, by pretending it's a TTY. The concept of a "UI thread" wasn't on Stallman's mind back then. It continued to evolve from there; fast forward 35 years, and now we're living with a GUI program that still thinks it's writing to a teletype[1].
I agree about this issue, maybe in the distant future this could be fixed as well but where will VSCode be at that stage? Probably even more miles ahead, due to MS funding. When there is good async support in Emacs a lot of packages would need to be rewritten.
However I prefer Emacs anyday over VSCode, I am very productive in Emacs because I'm used to doing almost everything in it
I don't think VSCode is ahead of Emacs on some objective scale. I tried to re-create my Emacs configuration with it and found it impossible. Also VSC appeared to be notably slower when tuned closer to my needs. At the end of the day there are always users who delighted by innumerable choices of configuration possibilities, and those who believe it's unnecessary cognitive load. Emacs being DIY kit appeals to the former, while VSC is built like a browser with rich plugin system, it's in between but closer to the latter. I'm sure VSC does and will have larger audience, but only better Emacs can unseat Emacs on its side of the spectrum.
Btw the effects of MS funding can be overvalued - e.g. MsTeams is among the worst IMs in the existence.
Emacs allows you to open multiple windows that share the same local server / process and essentially work as one editor.
You can open the same or different files in the different views, use one of the views for debugging, shells, remotely running tests, while you use the other views for other stuff (showing different files side-by-side, etc.).
I often see vim and vs code users doing a lot of shuffling around when working with multiple open files to switch back and forth between files or across tabs, but with emacs none of this is really necessary.
I think that the next major leap for emacs needs to involve the garbage collector and allocation logic. I think that a large class of performance optimizations would be possible with an improved GC, including improvements to emacs existing threading capabilities.