Remix.run Logo
jonpalmisc 7 hours ago

Tangential, but I really wish there would be a performance renaissance with Emacs.

Native-comp was a good step forward, but Emacs is still so much slower than Neovim, even in the case of launching and immediately quitting, with no config:

    $ time emacs -Q -e kill-emacs
    /Applications/Emacs.app/Contents/MacOS/Emacs -nw -Q -e kill-emacs  0.18s user 0.03s system 98% cpu 0.213 total
    
    $ time nvim -es --cmd 'vim.cmd("q")'
    nvim -es --cmd 'vim.cmd("q")'  0.02s user 0.01s system 82% cpu 0.034 total
Even with a very minimal set of packages, text insertion, etc. is slower, and opening Magit (when it hasn't been loaded yet) takes about a second due to slow package loading.

Emacs is my favorite editor, full stop.

But every time I open Neovim or Sublime for quick tasks, it's always painfully apparent how much faster they are when I CMD+Tab back to Emacs.

zelphirkalt 5 hours ago | parent | next [-]

Emacs' hard to solve issue is its use of global mutable state all across the board, which makes concurrency and parallelism very hard to add properly. It will take a lot of effort to slowly carefully reduce the error/bug surface and add proper parallelism constructs, that are easy to use for any package author.

truncate 27 minutes ago | parent [-]

Emacs is my editor/IDE of choice and consider myself power-user. However, I'm no expert in its internals or elisp. I understand that things are built with single-thread execution in mind over decades. However, I think things still can be more async, where you can offload heavy stuff to separate thread and stream results. E.g. Magit status doesn't need to block my entire editor. It can run what it needs to do in separate thread, send the results back to main thread just for rendering when its ready. Same with say consult-ripgrep / consult-find-file / find-file-in-project etc -- doens't need to wait for it in main thread and block the render / event handling until entire result set is ready (e.g. in this case things can be streamed). As in maybe there is a way around to make this much better by message passing/streaming instead of sharing state itself?

I love Emacs, but it really just fails to be effective for me when I work on monorepos and even more so, when I'm on tramp.

ishouldbework 7 hours ago | parent | prev | next [-]

While faster Emacs would always be nice, I think the idea is you just keep it running. Hence emacsclient program. So startup time is not such a big deal.

jonpalmisc 7 hours ago | parent [-]

Personally, I don't buy into this argument. I think having a globally shared buffer state, etc. is an antifeature. Plus, there's no reason that starting a TUI program should be that slow.

Either way, this only addresses startup time too. The rest of the issues: text insertion lag, `project-find-file` being slow in large repos, etc. all remain.

finaard 4 hours ago | parent | next [-]

The slowness on startup in my emacs mainly comes from my customizations - over the last almost 3 decades I've accumulated roughly 30k loc of custom lisp, plus a lot of 3rd party stuff.

But I typically start emacs at boot, and then it runs until I reboot. I usually have one GUI frame, and one tui frame running in tmux so I can easily attach to my emacs session from a different computer. I have an emacsclient wrapper that opens stuff from the command line in my running emacs (and also mail wrappers, so clicking on a mail link in a browser opens a mail compositor in emacs).

I'm using eyebrowse with a bunch of own convenience features for workspaces in emacs - stuff like "when I switch to a buffer it'll switch to the workspace wher e that buffer is open unless I tell it I want it here". Combine that with some custom SSH entry points and especially on the notebook where I only have one screen it's way more comfortable to use than the OS window management for a terminal/ssh session messy like me.

chriswarbo 6 hours ago | parent | prev | next [-]

> I think having a globally shared buffer state, etc. is an antifeature.

As someone who mostly lives in Emacs, I like it. If I'm away from a machine, I can SSH into it and carry on with whatever I was in the middle of.

It's also nice to set emacsclient as EDITOR, so that e.g. running `git commit` will open up a buffer in the existing Emacs session. This is especially useful since I use shell-mode, and it would be confusing/weird to have new Emacs instances popping up when I'm already in an editor! (They open in a "window" (i.e. pane) in the existing "frame" (i.e. window) instead)

ragall 5 hours ago | parent | prev | next [-]

> Plus, there's no reason that starting a TUI program should be that slow.

There's no reason why it shouldn't. You seem to think that the interface obliges a program into a certain performance pattern. No such obligation exists. And Emacs isn't a TUI program, it only happens to have a terminal interface among many others.

jonpalmisc 5 hours ago | parent [-]

> You seem to think that the interface obliges a program into a certain performance pattern.

I think all software (or at least, any text editor) regardless of interface type should launch instantly. But it's more unjustifiable with TUI programs.

ragall 3 hours ago | parent [-]

Nah. Here's a counter example: the TUIs that IBM wrote for many old store chains like Home Depot. They're at least an order of magnitude faster to operate for cashiers compared to web UIs but they're somewhat slow to start due to the caching and self-checks they do. This obsession with quick boot is more of a personal preference you have than a necessity.

qubidt 7 minutes ago | parent [-]

An inane point. Obviously it's a "preference" rather than a "requirement" that my text editor boot in less than 30 seconds. But it's also not a functional requirement that Home Depot's POS terminals take a long time to start. If you could do the same checks and caching in a few hundred milliseconds it would only improve the usability for the cashier. You haven't made a case for why some user interfaces shouldn't start instantly, only that their slow start-up _might_ be justified

dietr1ch 6 hours ago | parent | prev | next [-]

> having a globally shared buffer state, etc. is an anti-feature

Yeah, it feels a bit weird to not have some isolation.

Spacemacs offers layouts[^1] that give you some buffer-isolation. Each window has a "layout", and layouts have sets of buffers. It works well, but you can run into extra prompts if you open the same buffer from two layouts and try to kill it from one of them (kill the buffer (for all layouts)? just remove from this layout? In my mind the latter should just be the default).

[^1]: https://www.spacemacs.org/doc/DOCUMENTATION.html#layouts-and...

precompute 5 hours ago | parent | prev | next [-]

Emacs has globally shared buffer state amongst the frames that share the same "base frame" (no idea what this is called) or the same socket (could be wrong here).

Anyway, you can start N emacs instances and they can all have individual buffer states.

Emacs is not primarily a TUI program (although it does have a TUI with the -nw). The TUI version of emacs lacks visual customizability and introduces unnecessary overhead (terminal!). Use the GUI.

Text insertion lag is something I haven't experienced since 2019. Config issue?

project-find-file might be slow because of low gc-cons-threshold. I know consult gets around this by temporarily raising the threshold. These days, you can use the feature/igc branch to make these operations faster (although they are pretty fast anyway).

If you think emacs lacks <fundamental feature X>, think again!

MereInterest 3 hours ago | parent [-]

> Emacs is not primarily a TUI program (although it does have a TUI with the -nw). The TUI version of emacs lacks visual customizability and introduces unnecessary overhead (terminal!). Use the GUI.

Can you elaborate on this? I tend to use emacs exclusively in the terminal, since I'm often using them on remote workstations. For remote workstations, I can (a) open files using TRAMP, (b) open a remote GUI with X11 forwarding over SSH, or (c) open a remote TUI. TRAMP doesn't always play nicely with LSP servers, and remote TUIs are much, much more responsive than X11 forwarding.

Locally, the performance of emacs depends far more on the packages I load than on the GUI vs TUI, so I'm interested in hearing what overhead there would be.

smitty1e 6 hours ago | parent | prev [-]

> I think having a globally shared buffer state, etc. is an antifeature.

Maybe, but I'd like to hear why you think this is such an antifeature for a single-threaded application.

Given the extra resources available these days, for example, why not just bring up a stand-alone ERC instance for chatting, if shared state is a concern?

spudlyo 6 hours ago | parent | prev | next [-]

On my M1 Mac Pro I get 0.13s wall, so not much faster than your Mac. On my i9-9900K Linux box I get 0.04s. I would think my M1 single core performance would be on par, if not faster. Perhaps it has something to do with macOS and gatekeeper, as I notice I'm not getting as high of a CPU utilization.

    $ gtime /opt/homebrew/bin/emacs --batch --eval '(princ (format "%s\n" emacs-version))'
    30.2
    0.07user 0.03system 0:00.13elapsed 78%CPU (0avgtext+0avgdata 46064maxresident)k

    $ /usr/bin/time ~/bin/emacs --batch -eval '(princ (format "%s\n" emacs-version))'
    30.2
    0.02user 0.01system 0:00.04elapsed 95%CPU (0avgtext+0avgdata 57728maxresident)k
frantathefranta 5 hours ago | parent [-]

GUI Emacs on a 12 year old processor (i5-4590) feels faster than on a M4 Pro Macbook. I think it's just something to do with the window manager on each of the systems (my experience is mostly with Wayland KDE) rather than the speed of the CPU.

spudlyo 4 hours ago | parent [-]

I also run GUI Emacs on both Linux and macOS. I build it on Linux with --with-x-toolkit=lucid and for $REASONS I'm still on X11. I run it in a full-screen frame on its own monitor, and it does indeed feel faster.

dietr1ch 6 hours ago | parent | prev | next [-]

> Emacs is still so much slower than Neovim, even in the case of launching and immediately quitting

I agree, but there's ways around it. On my machine the Emacs daemon is ready before I even log-in (lingering [^0]).

I think I only restart the daemon when I update emacs and its packages, and yeah, Emacs and Spacemacs are slow, but do not slow me down.

[^0]: https://wiki.archlinux.org/title/Systemd/User#Automatic_star...

Ferret7446 3 hours ago | parent | prev | next [-]

Emacs is functionally a shell not an editor. Starting Emacs for each file is akin to starting and stopping Wayland for every web page you open.

So the miniscule increase in start time is a non issue

chriswarbo 6 hours ago | parent | prev | next [-]

Emacs can certainly be sluggish, but I'm not sure how much that's e.g. inherent to ELisp, or due to synchronous/single-threaded code, or choosing slow algorithms for certain tasks, etc.

For me, the best performance improvement has been handling long lines; e.g. Emacs used to become unusable if it was given a line of around 1MB. Since I run lots of shell-mode buffers, that would happen frustratingly-often. My workaround was to make my default shell a script that pipes `bash` through a pared-down, zero-allocation copy of GNU `fold`, to force a newline after hitting a certain length (crossing a lower threshold would break at the next whitespace; hitting an upper threshold would force a break immediately). That piping caused Bash to think it wasn't interactive, which required another work-around using Expect.

Thankfully the last few versions of Emacs have fixed long-line handling enough for me to get rid of my awful Rube-Goldberg shell!

Joe_Cool 5 hours ago | parent | prev | next [-]

What hardware are you on?

On my old Ryzen 3600X running Arch it's a lot faster. Does the UI eat so much performance on OSX?

  $ time emacs -Q -e kill-emacs
  real    0m0.076s
  user    0m0.058s
  sys     0m0.018s

  $ time nvim -es --cmd 'vim.cmd("q")'
  real    0m0.028s
  user    0m0.005s
  sys     0m0.003s
vim still is a lot faster though.
znpy 5 hours ago | parent [-]

> On my old Ryzen 3600X running Arch

> vim still is a lot faster though.

you might want to make sure you're comparing apples to apples though. the "emacs" command most likely is going to load the GUI emacs so a lot of gui libraries (if you're running a recent emacs then even GTK libraries) whereas the nvim command isn't going to load gui libraries at all.

maybe try with a non-gui version of emacs (or maybe calling emacs -nw)

Joe_Cool 4 hours ago | parent [-]

no, this is the TUI version. X11 emacs with all the composited effects needs about 200-250ms to open (about the duration of the animation for opening and closing it). That's more like OP's timings.

codygman 4 hours ago | parent [-]

No, you need to use -nw with emacs to make it apples to apples. Then it's emacs 0m0.095s vs nvim 0m0.057s:

    $ time nvim -es --cmd 'vim.cmd("q")'

    real 0m0.057s
    user 0m0.016s
    sys 0m0.017s

    $ time emacs -Q -e kill-emacs

    real 0m0.230s
    user 0m0.165s
    sys 0m0.064s

    $ time emacs -nw -Q -e kill-emacs

    real 0m0.095s
    user 0m0.057s
     sys 0m0.017s
Joe_Cool 4 hours ago | parent [-]

Shouldn't matter when I am not on GUI seat. In my SSH session with X11 forwarding there is no DISPLAY emacs could use.

Tried it anyways, looks the same:

  $ time emacs -nw -Q -e kill-emacs
  real    0m0.075s
  user    0m0.062s
  sys     0m0.013s
Joe_Cool 9 minutes ago | parent [-]

s/with/without/

weaksauce 2 hours ago | parent | prev | next [-]

my non-command line gui version of doom emacs with a bunch of packages enabled loads up fully for me in 0.45s which is hardly slow. sure it's slower than neovim but also not slow in the absolute sense and i don't have the emacs daemon running which would make that even faster.

ahoka 7 hours ago | parent | prev | next [-]

/usr/bin/time emacs -Q -e kill-emacs 0.03 real 0.02 user 0.00 sys

Altough I'm not using Emacs.app.

jonpalmisc 7 hours ago | parent [-]

Not using Emacs.app because you aren't on macOS, or using some other build/setup? If the latter, I'm curious.

8s2ngy 6 hours ago | parent | prev | next [-]

I share your wish. Emacs, as wonderful as it is, has accumulated a lot of cruft over the decades and would benefit immensely from a rewrite. A "Neo-Emacs" could be multithreaded from the ground up and drop support for archaic platforms. The rewrite could even be in Rust to attract younger developers.

umanwizard 6 hours ago | parent | next [-]

There would be no point to writing emacs in a language that can’t be developed interactively in a repl. Emacs being written in lisp is an essential quality.

BigTTYGothGF 5 hours ago | parent [-]

> Emacs being written in lisp is an essential quality

Not for the parts of it I use.

precompute 5 hours ago | parent | prev [-]

>a lot of cruft

Like what? Emacs is written in C and there are ports of it out there (all half-abandoned). Emacs, the way it exists, works very well.

umanwizard 5 hours ago | parent [-]

The vast majority of emacs is written in lisp, not C.

BigTTYGothGF 6 hours ago | parent | prev | next [-]

I'm not sure I'm capable of noticing or caring about the difference between 0.18 and 0.02 seconds for something that doesn't happen on a rapid cadence.

precompute 5 hours ago | parent | prev [-]

Startup time does not matter, use the daemon. Opening a new frame is ~instantaneous.

I practically live in Emacs and it's not slow at all. It's very zippy, and my setup isn't the lightest!

There's a new branch (feature/igc) with incremental garbage collection (via MPS) that makes routine actions faster. I've been using it and it has been incredibly stable and has completely eliminated stutters (which used to happen very infrequently, but were present). Also, to me, it seems like it improves latency. The cursor feels more responsive.