Hacker News new | past | comments | ask | show | jobs | submit login
Bringing GNU Emacs to Native Code (2020) (arxiv.org)
369 points by textread on May 1, 2021 | hide | past | favorite | 130 comments



The speedup is very noticeable. Like others I'm running the "native-comp" branch of Emacs, since months, without any issue.

It's now been merged into trunk and it's going to be the default:

https://news.ycombinator.com/item?id=26935401

The only drawback I saw is that compiling Emacs itself takes 3x to 4x longer when compiling the native-comp branch.


I tried this on macOS a few months ago and it was pretty rocky just getting the thing compiled. I tried again last night and it pretty much Just Worked(tm) thanks to this[1] project.

Note: this was on an Intel mac; anyone with an M1 tried this yet?

I did run into some problems with some newer packages on the GNU ELPA. (Specifically consult, marginalia, and vertico by github.com/minad) Straight.el complained about not being able to find the packages. Any suggestions on what I might try to fix this?

[1]: https://github.com/jimeh/build-emacs-for-macos


Maybe try and write out the complete path for the github repo when using straight, I am using the abo e packages (except vertico) and have not had any issues


  brew install emacs-plus@28 --with-native-comp
might be a more standard "easy" approach on MacOS.


TBH the emacs-plus install didn't work for me (the Emacs.app produced failed with `LSOpenURLsWithRole failed`), whereas build-emacs-for-macos did work.


I suppose

brew tap d12frosted/emacs-plus

first? (I haven't tried it yet, and not sure I will.)


Can't help as I'm on Linux (also I use ivy/avy/counsel and not consult/marginalia/vertico).


Out of curiosity, why did you reply?


He was replying to some questions I asked him in my reply to his top-level post. I was confused too, but now that I figured it out, I appreciate the reply.


Eh, I don't know... I suspect the speed up depends a lot on how a person uses Emacs.

I've been using it for a few months as well, and I haven't noticed any change. My start up time, as measured with 'emacs-init-time, is 0.6-0.7 seconds instead of 0.7-0.8, but that's about all I've noticed, and there hasn't been any difference in day-to-day editting.

I haven't had any problems, so that's good at least.


Definitely. Depends on how much you stuff your Emacs is running. Bare-bones Emacs was generally pretty snappy, but once you activated all the quality-of-life features and added a bunch of third-party packages, there was a noticeable performance impact.

The first thing where it usually affected me was org-mode. It runs a lot of complex text-parsing and redisplay code on the buffers, and some frequently used operations (like folding/unfolding big sections of the file, or generating agenda) would noticeably slow down with files over a couple hundred lines. That problem is now mostly gone with nativecomp - probably in part because Org Mode itself is improving its performance, but in big part because all that Elisp just runs faster across the board.

LSP mode would probably be another common case - but I only started using it on nativecomp and with the new JSON parsing module (Emacs 27 started supporting libjansson in place of whatever it was doing before). It works very well, but I imagine it was pretty unusable before these two changes.


> but once you activated all the quality-of-life features and added a bunch of third-party packages, there was a noticeable performance impact.

I'm not sure I understand what you mean there. Unless those third-party packages are scheduling tasks on the event loop then they should not be impacting performance of your other operations. Just having lots of things installed and activated doesn't affect performance.


It's not having lots of things installed. It's actually using them. Basically how much custom elisp is running in your buffer.


With respect, I think you're confused. But even if I'm right, that's OK, software is complicated, and it took me a while to get these things straight.

Multiple installed emacs packages do not execute their code simultaneously unless they are using something like run-with-timer to schedule tasks on the event loop. Can you give me an example of an emacs package that causes custom elisp to be "running in your buffer" continuously?

For example, org-mode does many complicated things, but only when you ask it to -- i.e. when you issue one of its keybindings, or call one of its functions. Then, you enter a blocking ("synchronous") function call: the main thread is executing the org-mode code and nothing else until it's done. So, if things happen as I'm describing, you can see that it doesn't matter how many packages you have installed: only one of them is taxing the CPU at any one time, and they are not all queuing up work and causing the event loop to get bogged down.

Similarly, swiper, ivy, counsel, magit -- they only do things when you ask them to.

To put this another way: in general, your installed packages are not active simultaneously. Therefore, the performance of your editing operations is not affected by how many packages you use.


> Multiple installed emacs packages do not execute their code simultaneously unless they are using something like run-with-timer to schedule tasks on the event loop.

It's true that few things run in the background constantly. You can check for that easily, with M-x list-timers. On my work laptop, my most feature-packed Emacs instance, I currently have three timers active (and 11 waiting for a trigger). Those three are:

  Repeat   Function
     5.0   auto-revert-buffers
    60.0   ac-clear-variables-every-minute
  3600.0   url-cookie-write-file
So there's only one frequently updating timer running, that was put there by (I think) lsp-mode.

Of the inactive timers, there are a bunch on a really short trigger - for features like highlighting indentation guides, highlighting parentheses, etc. But these are the ones that wake up when you do just about anything in a relevant buffer - along with various hooks being fired.

Because it's the hooks that seem to be missing in your current understanding.

I just switched to a random buffer, and in it, I have 18 functions in post-command-hook, and 2 functions in post-self-insert-hook. That's 20 functions to execute on pretty much every single key press, and all of them come from optional features, both built-in and from additional packages. Syntax highlighting (font-lock-mode), error checking (flycheck), documentation helpers (eldoc), LSP stuff, snippet expansion, etc.

All these functions are usually fast (plenty of them just reschedule aforementioned inactive timers), but every now and then, one of them gets some heavier workload. And you notice a stutter. Perhaps inserting a character took more milliseconds than you're used to, because it caused font-lock to re-render the entire screen. Perhaps autocompletion triggered some expensive checks. Or perhaps there's just too many badly-written functions firing, and it added up to a noticeable delay.

For me, the three most common cases of annoying little delays were autocompletion (in Elisp, and Common Lisp via SLIME), font-lock and org mode folding. The latter two were an issue when working with large org mode files.

Native compilation improved Elisp performance across the board, and all but eliminated these issues for me. It won't help you if you put a badly written function in a frequently firing hook, but it does push some of the more expensive computations below the threshold of visibility, and makes it less likely that a lot of functions in a hook will add up to a noticeable delay.


Similarly, I wanted to check what was taking up time on redoing org-agenda, profiler says the majority of the time is spent doing `kill-all-local-variables`

         524  57%            - kill-all-local-variables
          56   6%             + magit-wip-after-save-mode-cmhh
          56   6%             + global-evil-quickscope-mode-cmhh
          56   6%             + global-eldoc-mode-cmhh
          52   5%             + global-page-break-lines-mode-cmhh
          52   5%             + global-font-lock-mode-cmhh
          48   5%             + smartparens-global-mode-cmhh
          44   4%             + global-prettify-symbols-mode-cmhh
          40   4%             + magit-auto-revert-mode-cmhh
          40   4%             + global-tree-sitter-mode-cmhh
          40   4%             + evil-mode-cmhh
          40   4%             + global-evil-collection-unimpaired-mode-cmhh
These are all third-party packages, have nothing to do with org-mode. Pretty much any globalized minor mode you enable will add some constant time to switching into fundamental-mode, and it all adds up.

(Also, half the time when I run the profiler, the culprit ends up being evil-mode. Unfortunately it's so useful …)


Wow, that's an interesting result, I never noticed it directly - I've seen -cmhh functions before, but never bothered to check what they are before.

As it turns out, these are automatically created by `define-globalized-minor-mode' macro - per docstring, it's used to define a global mode for buffer-local minor modes. I.e. that's how you get all these `global-XXX-mode` functions that turn on XXX-mode in every (relevant) buffer.

One of the things this macro does is create a `global-XXX-cmhh' function, and attaches it to `change-major-mode-hook', which is invoked by `kill-all-local-variables' whenever buffer's mode is changed. I imagine that, as part of generating org mode's agenda, files get opened and modes get switched a lot. Curiously, it also seems that (digging into `kill-all-local-variables' source in C), each call to it forces mode-line redisplay, so further computation may be caused by whatever is in your mode line (which can also be nontrivial). I haven't checked that though, maybe it redisplays mode line only once.

Thanks for bringing this up, it's another place where pretty much every mode stuff some hook, that I didn't know about :).

EDIT: curiously enough, I just profiled my agenda - both doing from scratch and redoing it - and `kill-all-local-variables' isn't even on its radar. I wonder what runs in your hooks (and/or modeline) then. The result from refreshing an existing agenda was roughly what I expected. Building it anew, after killing all open org buffers, was interesting. In my case, 69% of total time was spent opening files (`find-file-noselect'), before even doing any mode switching. In that, `projectile-find-file-hook-function' accounted for 50% of total agenda building time, half of that spent updating the mode line!

From what I see, it's just trying to determine the project to which a file belongs. I'll probably look for an option to make projectile stop being interested in files that aren't in the "known projects" subtrees without explicitly instructing it so.


Ah, thanks for explaining that so clearly and thoroughly. You're right that I was forgetting hooks. (And I learned something else from what you wrote -- that often a library will have it's triggered function merely enqueue a task. Of course that makes sense but I'd forgotten that in an emacs context (whereas I might have thought of it in a backend web dev context)). Two questions/comments:

1. I had it in my head that emacs arranged for font lock to be done in a separate thread? (Also, why is it called "lock"? I just use that word cos the emacs docs and code do)

2. Isn't org mode folding/unfolding just a blocking call that happens when you ask it to?


> emacs arranged for font lock to be done in a separate thread

I'm not sure, but I don't think so. There's this thing called `jit-lock-mode' (check out the docstring of the function named jit-lock-mode for details) that makes Emacs fontify only visible parts of the buffer when triggered by redisplay code (in C core), + some extra fontification of the invisible parts on idle timer. But I don't believe it actually happens on a separate thread, given that redisplay can run arbitrary user code, e.g. through 'display property attached to a piece of text in a visible buffer.

> Also, why is it called "lock"? I just use that word cos the emacs docs and code do

So do I. I did a little googling, but couldn't find any definitive answer. Most likely explanation[0] seems to be that "lock" here means the fontification spec is attached to the text and updated automatically, vs. being refreshed globally on user request.

> Isn't org mode folding/unfolding just a blocking call that happens when you ask it to?

It is, but it's also something I do very frequently in quick succession. I'll usually press S-Tab in quick succession to perform global visibility cycling, because I often want to take a quick look at the outline of my file, and then get back to editing where I was. If it takes more than a fraction of a second, it's distracting for that use case.

--

[0] - https://old.reddit.com/r/emacs/comments/b3jsfc/what_does_loc...


It certainly might have been perceived that way. IIRC, Font-lock mode included logic to defer the heavier execution of fontification until a certain amount of idle time accrued (particularly helpful from a UX perspective as people are typing there can often be dramatic shifts in fontification, and it isn't worth slowing them down just to make a change that will disappear at the next keystroke). There are also tricks in it to do partial fontification. I believe this is now handled in a sub-module called jit-lock-mode (Just-in-time Lock Mode).

However, font-lock-mode never executed in a separate preemptive thread.


> Multiple installed emacs packages do not execute their code simultaneously unless they are using something like run-with-timer to schedule tasks on the event loop.

Yes, that's accurate, but that's the whole problem. The code executes sequentially, so each custom execution adds latency. It's not unusual to have elisp from several packages executing with every keypress.


i also don't notice any speedup. it was a bit disappointing :)

i use gnus and org-mode heavily. 80% of my day is in one or the other.

i would add that emacs28 w/o compilation feels faster than emacs27.

emacs28 w and wo compilation feel the same.


Is the speedup during editing or does it also improve startup time?


> Is the speedup during editing or does it also improve startup time?

During editing/usage for sure: it is noticeable. Not that it was slow before but nearly everything now feels really snappy.

As for startup I don't know as I rarely relaunch it but I just tried (only for the native-comp branch):

    time emacs -Q -eval '(kill-emacs)'

gives 160 ms. Or launching Emacs with -Q and then calling emacs-init-time gives basically the same (-Q bypasses the config files).

Starting with my entire config which is quite beefy takes 1.2s. I could probably speed it up but haven't really looked into optimizing Emacs startup in a while.


Emacs has been pretty slow in editing, ever since Visual Code came along to set the bar higher. Good thing that Emacs is back in the game though, that editor has heart.


last I tried VSCode there was a noticeable input lag (keystroke to character on screen). Is there some trick to fix this?

I found it incredibly distracting. In Emacs... Magit is instantaneous while orgmode tangle/export is embarrassingly slow - but never a dealbreaker

anecdotally eshell has some of the lowest latencies as well https://danluu.com/term-latency/


I switched back from VSCode to Sublime Text (despite enjoying Intellisense) due to how much more responsive the scrolling is in Sublime.


Same here, maybe it’s only in my head, but for me subl is just better.


It is massively better in latency than any other editor I've tried. No surprise, since I believe it's C++.

Unfortunately sublime's plugin ecosystem isn't very lively.


I couldn't even type 2 chars in vscode on a 2nd gen i5. To be fair it's been decades since I've experienced that amount of delay. Thanks I guess


If you're have a problem with performance in vscode 95/100 times it's memory not cpu bound. Obviously emacs uses less memory than vscode, at least at base configuration.


Maybe, it's still incredible to think that memory pressure would create that much latency. And I'm not that picky, I use a hp48 calc (on which lag is almost a feature). I'm just shocked when people say emacs is sluggish while vscode flies.


It seems to still have trouble compiling code using old-style advices. By not supporting LLVM JIT, this also brings in a lot of extra dependencies on macOS, although, not as egregious as librsvg.


By not supporting LLVM JIT it gains a lot of significant advantages:

Small jit dependency. 1MB compared to 30MB.

Fast JIT. At least 3x faster than llvm.

All architectures. LLVM only supports a tiny amount of architectures, gccjit all.

Only the desperate do llvm jitting.


Besides ARM and AMD64, what other arch do you need to support? RISC-V?

I'm using MacPorts and I have no idea how to hand compile just libgccjit there. The libgcc port doesn't even produce the jit language.


I think you want to do

    port install emacs-devel +nativecomp
or

    port install emacs-app-devel +nativecomp


I did this last night. It failed to compile. OSX 10.14. Frustratingly.


I'm on macOS 11.2.3 (20D91) and it worked fine, though it took a while to compile since there were no binaries.

You may try to report a bug[0] for Mojave but I wouldn't hold my breath.

[0] https://trac.macports.org/wiki/MojaveProblems


That's a MacPorts problem. Debian has libgccjit0 package for example. In due time, MacPorts will also package gccjit.


Google helps: https://gist.github.com/AllenDang/f019593e65572a8e0aefc96058...

Macports has gccjit since gcc10, just somebody needs to update Emacs.

What others archs? All of course


Google should also help you understand that the libgcc port does not provide for libgccjit for whatever reason.

I'm writing my own Portfile to get libgccjit 11 now. The emacs-devel port does bring in the entire gcc10, but I just want libgccjit.


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.


The command I use is `M-x find-grep`.

I also use `helm`, `ido`, etc. to navigate the file system and they are all super slow.


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.


I was going to say, there is a way to do the server side logic with Emacs... ;-)


See my comment about TRAMP and file system operations from a couple of months ago for some of the underlying issues.

https://news.ycombinator.com/item?id=25626412


> 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.).


> Why this isn’t the default I don’t know (…)

It is, it has been for a while. Check the TRAMP FAQ for details when it is being used automatically (grep for "ControlMaster"): https://www.gnu.org/software/emacs/manual/html_node/tramp/Fr...


I guess things are getting better.


> Why this isn’t the default I don’t know, [...]

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:

https://www.anchor.com.au/blog/2010/02/ssh-controlmaster-the...

I did not test it myself. This would seem like an appropriate reason to not make it the default.


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].

[0] https://www.reddit.com/r/vim/comments/b3yzq4/a_lsp_client_ma...


SLIME is another good example.


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.


> All this stuff runs in the UI thread. Braindamaged.

Calling this "braindamaged" is hardly fair; I'm sure this decision was made ~35 years ago when it made more sense.


Forgive my ignorance, but why would doing all of the application work on a single thread make more sense 35 years ago?


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].

--

[0] - https://stackoverflow.com/questions/10084842/first-gui-versi...

[1] - https://m.facebook.com/nt/screen/?params=%7B%22note_id%22%3A...


Isn't the issue more concurrency than parallelism, though? Concurrency works just fine with a single core thanks to kernel-level juggling.

They would've been wildly forward-looking if they had figured this out 35 years ago though.


VSCode's remote editing simply does not work on unstable networks. Tramp works like a champ in those situations.


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.


vscode doesn't even support multiple monitors, it's far behind in many areas.


What does it mean for an editor to "support multiple monitors?"


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.


There were two attempts to solve that - Guile Emacs[1] and Common Lisp Emacs[2]. Sadly, both are effectively dead now.

[1] https://www.emacswiki.org/emacs/GuileEmacs

[2] https://www.cliki.net/cl-emacs


My impression is that the major bottleneck is the redisplay loop.


gccemacs is amazing! I've been using for more than a year on macOS and NixOS, and it's been superb (though from time to time I clear downloaded packages and the native cache just in case). It's definitely an impressive feat of engineering as well. If you haven't seen the developer's website on it[0], you should definitely check it out.

For Nix users on macOS, see[1]. Here's how I used it in my home-manager config[2]. For Nix users on Linux and NixOS, see the Emacs overlay[3]. There's even Emacs nativecomp + wayland support (emacsPgtkGcc) there.

[0] https://akrl.sdf.org/gccemacs.html

[1] https://github.com/twlz0ne/nix-gccemacs-darwin

[2] https://github.com/siraben/dotfiles/blob/8161e1b72965b48f822...

[3] https://github.com/nix-community/emacs-overlay


Getting much better fps in Doom in Emacs now.


Is there a Doom module for this?



It was a joke. Until you asked this.


He's talking about Doom Emacs: https://github.com/hlissner/doom-emacs


This is my favorite comment of the day! Kudos :) I don’t care if it gets downvoted by guidelines lawyers


Here is a stream of the corresponding lecture at the European Lisp Symposium 2020: https://www.youtube.com/watch?v=zKHYZOAc_bQ

And here are the slides: https://www.european-lisp-symposium.org/static/2020/corallo-...


Really hope to see Emacs get more attention after `native-comp` branch merged to master.

Recently, I have switched to Emacs full-time (first spacemacs[0], now doom[1]). So far, it has been a great experience. Spacemacs is a bit slow but with doom and `native-comp`, I rarely encounter any performance issues.

[0]: https://github.com/syl20bnr/spacemacs

[1]: https://github.com/hlissner/doom-emacs


I love Doom but it needs more documentation and more developers/maintainers. If your Elisp is good and you use Doom I would strongly recommend contributing to the code. Even if your Elisp is not good, you can totally contribute towards documentation.


One related thread from last year:

Bringing GNU Emacs to native code [video] - https://news.ycombinator.com/item?id=23066971 - May 2020 (83 comments)


Every time I try Emacs I get annoyed by it's slowness and go back to vim and VS Code.

This might entice me to build it and try out my Emacs Doom setup again.


There are number of things you can do to improve your situation. Obviously you should not have packages loaded that you don't rely use. There are also ways to perform "lazy" loading, so that memory image is minimal until a package is really needed. I'm not using this myself.

My usage model is such that I only start one Emacs and use emacsclient to add files for editing from terminals. Emacs is running all the time (weeks/months).

Since Emacs is my primary interface to my Linux box, I give it some priviledges. In the .xsession I do:

vmtouch -t $HOME/.emacs.d; vmtouch -ld /usr/bin/emacs-gtk

Which effectively ensures that critical Emacs images and data is present in the memory all the time. Check out vmtouch utility. It might be useful for other purposes as well.


My problem is really not the startup/loading time, but the regular stutters and long latency for input and commands.

I need my editor to "feel" really smooth and instant during editing. Emacs just never gives me that experience.

I think many long-time Emacs (and Jetbrains IDEs, for that matter) users just don't notice how laggy it is because they are so used to it, or are not very latency sensitive.


As a vim user who's transitioned to Emacs with evil, response latency just feels so much better in vim, and although I love and use the daemon-client tip, it misses that point.


It’s quite strange that the reputation for Emacs being slow hasn’t changed in decades even though hardware has advanced significantly...


Probably because it's relative. Emacs being single-threaded hurts it the most I think.


Wirth's law: Software gets slower faster than hardware gets faster.


Try doom emacs and see what you think. I don't use it, I prefer pretty GUIs (I don't care what the HN crowd thinks of me and my love of graphics) but sometimes I'm in a terminal and DOOM emacs works great.


hell yeah me too, this will make it get back to Emacs again :D


I am excited by this. I tried it a few months ago, then switched to a M1 Mac and went back to a current stable version. I find IDEs that are M1 native are noticeably faster. I look forward to a M1 native libgccjit Emacs.


Slime didn't work for me in this version of Emacs. (Slime is the Common Lisp IDE for Emacs). I don't remember the details but I think Slime was getting confused about .el vs .elc files and assuming there was no third option, but now there is.


Interesting, I've been using Slime with nativecomp for a long time.


Wow. Guess I need to try again.


I'm 100% not trolling with this question, I really like Emacs, buuut:

Does it fix having to restart Emacs after at most 8-16 hours of use?

Could this experience be a plugin I use, or my own idiocy? Originally, I assumed "YES! Of course! I am idiot... This is my fault!" Then came the observation when pairing with people (across a variety of languages) who use Emacs, who all say on a regular basis, without so much as a thought to it:

"one sec, I just need to restart Emacs."

Followed by 30 seconds of restarting Emacs and 30 more seconds setting up the buffers. I'd definitely use Emacs but the inevitable, and uncontrollable, lockups kill it for me.


I'd bet it's just your setup. I had one Emacs session run for almost a month straight—and that was with LSP mode running on a fairly large Elixir project. I only restarted it because I needed to restart the machine I was running it on. It was using barely over 300 MB of RAM. (Lots and lots of open buffers and whatnot.) That's not an unusual occurrence for me—and I'm not even running the native-comp branch yet!

FWIW, my Emacs init time (run `emacs-init-time`) is between 2–7 seconds, and I'm not doing anything particularly special to get that working.

I'd start out with a fresh .emacs config file and then add the packages you want with the excellent `use-package` macro, setting `:defer t` as much as possible. (Often this will be implicit if you have `:mode`, `:hook`, or `:bind` configured, if I'm not mistaken.)

It would be better if Emacs were less sensitive to how your config is setup, but alas, we live in a fallen world. You can also ask around on r/emacs and get some better tips than mine.


I basic used `:defer t` for a while (Doom Emacs lazy loaded under the hood), but when I switched to my own config I decided to just run it in daemon mode and use `:demand t` on everything. I didn't like pauses sometimes when opening a new file while it loaded a package.

Actually, I just checked my init time with that command, and it's ~2.5 seconds. I wouldn't call my config heavyweight, but it does have evil, lsp, vterm, ivy, magic, etc. I am using the native-comp branch though.


You can try this code snippet to detect large variables:

https://lists.gnu.org/archive/html/emacs-devel/2008-12/msg00...

It is a major attraction of Emacs that its inspection facilities can be easily used to automatically analyze such issues.

My expectation of Emacs is that I never have to restart it. If it crashes or fails to reliably reclaim memory, please consider filing an issue with M-x report-emacs-bug RET.


Definitely your setup. Long uptimes for Emacs with no performance degradation are common. Mine are typically month+. Currently, M-x uptime on my desktop (Linux) shows 33 days; on my work machine (Windows, with Emacs in WSL) it's 5 days - but that's only because I wrote a lot of tricky Elisp code to optimize my work some, and I rebooted Emacs to check it will actually work when reloaded afresh. Normally, Emacs runs uninterrupted on that machine, until Windows forces me to reboot for updates.

Startup time with nativecomp? Typically around 5 seconds on Linux, 15 seconds on WSL. If I happened to update a lot of packages before restarting (as I sometimes do, I like to clean out runtime state when I do bulk updates), then on WSL the startup goes up to about 1-2 minutes - that is, Emacs is usable in about 30 seconds, but async native compilation keeps pinning most CPU cores, so I just let it work in peace for that extra minute.


I run Emacs on both Linux and Windows and I find that with more or less the same packages, the Windows Emacs tends to "slow down" after a while. I've used the profiler to track down a couple of things that were causing slowdowns (ibuffer auto refresh, etc), but still haven't quite go to the point where Windows runs as fast as Emacs. On both cases I have fairly long running Emacs sessions - around a month on Linux, when I pickup distro updates, and a week on Windows as we do mandatory reboots weekly. I recommend you try profiling to see if something shows up [1].

[1] https://200ok.ch/posts/2020-10-01_introduction_to_profiling_...


I spent some time poking Emacs on Windows with a profiler too, also to no avail (few things I identified as suspect turned out to didn't matter). I eventually resigned to running Emacs under WSL1 and rendering it on VcXsrv on Windows side. It's very fast this way, though some filesystem-heavy operations are still slightly slower than they would be on Linux (that's a limitation of WSL and NTFS).

About the only issue I have with this setup is that I can't get color emojis to work using Microsoft's Segoe UI Emoji :). That, and if I want to call out to some Windows executable, I have to ensure I use :connection-type 'pipe instead of (the default) TTY in make-process, because otherwise I get a disconnected process that can't communicate with Emacs. But the latter is a very rare case (I only need it to drive the build system I use at work from Emacs, because it lives Windows-side).


> Could this experience be a plugin I use, or my own idiocy?

Considering how lots of people prefer to start Emacs once, preferably as a server (maybe even as a systemd user-unit!), and keep it running forever, not even closing buffers, until eventually the machine must be rebooted for whatever reason...

I would have to say yes.


I never need to restart emacs. It's generally only when I reboot that I have to start emacs again.


30 seconds for startup is really weird. Mine starts in a few seconds, and is far from fully customized. Initializing the language servers of open buffers takes by far the most time.

Emacs has many solutions to restore buffers. I use `desktop`, which is built-in. Use whichever you like, I really can't tell you the pros/cons.

Have you ever tried setting the garbage collection treshold to a large value? There's definitely no use for it during startup. It might make sense though to trigger it in a hook after startup.


Sounds like you have a memory leak somewhere or some code in your emacs setup is using a lot of memory and is causing lots of gc. Turning on garbage-collection-messages and profiling memory usage will be a start to debug this.


I would say it likely is your, and their, setups. But not idiocy. The way Emacs configuration works makes it very easy to break (but also very powerful)


I had an org-mode emacs session running 24/7 on a server for months at a time without any issues. It's something with your setup.


It's your own setup's fault. I use emacs daily, and I almost never have to restart it.


I used to get that all the time until I uninstalled some melpa package.


I've never experienced this. I autostart emacs in daemon mode, and right now my desktop's uptime is... 3 days. And that's only because I updated my kernel, normally I'll go for a lot longer than that.


I'm not affected by this, so you might have something weird specific to your setup.


I've been running Emacs for almost 30 years. Stability has never been a problem and the last 5-10 years it has been rock solid for me. I can run Emacs for months without restart. Hence instability must be an issue with some packages.


It makes LSPs usable for me on my desktop 5950x. Still a bit laggy on my laptop.


Unfortunately, Emacs won't really benefit since it is a (mostly) single-threaded application by design. But that sweet 5950x should definitely speed up running dozens of language servers and indexers at the same time :-D


Yes it’s a shame. I really like emacs but the lagginess is just too jarring while working.


I have really liked native-comp so far on Arch Linux. I think in the last year or so I have had total two hiccups only due to nativ-comp.


The requisite libgccjit AUR package was broken for a bit, fixed just a day or so ago.


Given an installed emacs, what's the best way to check whether it was built with this feature and that the feature is active?


Several ways (overkill answer, but leaving all options I know because why not):

You can try evaluating this in the scratch buffer

    (if (member 'nativecomp features)
        (message "yay")
      (message "nay"))
Or check if a non-interactive function called `native-compile` exists.

Or open help for an elisp function (next-line, for example):

    c-h f next-line RET
Gives me:

    next-line is an interactive native compiled Lisp function in ‘simple.el’.
Or, m-x disassemble next-line RET


Has anyone tried this with gnus? Is it noticeably faster?


Genuine question: why is this on Arxiv? It seems like a design document in the format of a research paper.


It's the submission paper to the 13th European Lisp Symposium (ELS20) last year in Zurich. Lisp conferences put a higher demand on their submissions to be like formal papers. With external reviewers and such. This is one.

At this stage nativecomp was not yet finished, see his webpage for the progress. Expect another paper for the final evaluation of the improvements. It has big impact on programming languages implementations, esp. compared to llvm.

It's the very first big gccjit project, and a huge success.


Experience reports are also common as scientific papers. [1]

[1] https://sigdoc.acm.org/conference/2017/guidelines-experience...


Your question comes across as uncharitable and I suspect you have no relevant experience. Without implying that your question has any validity, if you have an academic career, you need publications. Therefore it's the opposite of what you imply. We want people to feel welcome to write up all sorts of computing achievements in academic forums, because that is what will help the authors be able to carry on doing what they are doing and thus allow us to benefit from their work.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: