reddit / emacs

An easy trick I found to improve Emacs start-up time

zemja_ 路 2022-11-19 12:52
The variable `gc-cons-threshold` is the threshold beyond which Emacs will run garbage collection. So if more memory is allocated than this (in bytes) the garbage collector runs. The default value is 800000 - just 7.6MiB! Starting Emacs and looking at `gcs-done` gives 67 for me (the garbage collector has run 67 times) and `(emacs-init-time)` gives `"5.464376 seconds"`. At the start of my `init.el`, I've put: ;; Don't collect garbage while initialising. (setq gc-cons-threshold most-positive-fixnum) And at the end: (setq gc-cons-threshold (* 1024 1024 100)) ; 100 MiB You could also put `(garbage-collect)` at the end to collect garbage if that tickles your fancy. Now `gcs-done` is 12 (for some reason), and `(emacs-init-time)` is `"3.598263 seconds"`, which is a decent improvement of nearly two seconds. I have a very heavy and badly-written configuration file, so I need all the help I can get 馃檪. You could probably get away with higher values of `gc-cons-threshold`, but bear in mind that the larger the threshold, the rarer the garbage collection, but the longer it takes. So you might end up with tiny but noticeable pauses while you're typing, which would be annoying. Not sure about that so it's worth experimenting. EDIT: This is probably crappy advice, read the comments.
anaumann 路 2022-11-19 12:57
You don't need to shave off seconds off your startup time, you need to learn to use emacsclient ;) No, seriously.. If I want an editor quickly, even 3.5s are annoying to stare at an empty screen for.. With emacsclient, opening new windows is pretty much instantaneous and I don't care very much if the first window takes 5 or 25 seconds to appear, because I only have to endure that once every day. Some people even run the emacs server from a systemd unit so it will be already there whenever they need an editor, I have it started from the first call of emacsclient..
MitchellMarquez42 路 2022-11-19 13:30
Shaving startup time is definitely doable - I had mine down to 0.4 seconds. Now I use eshell so it's similar to using emacsclient, but even if I have to close it, no big deal, a fresh emacs -f eshell a blink away. An Emacs should run like a well-oiled machine. If yours takes 25 seconds to open, something is wrong.
anaumann 路 2022-11-19 13:31
It doesn't take 25s, but I don't really care how much time it really takes, because I pretty much start it once every day and then spend all day in vterm :)
eli-zaretskii 路 2022-11-19 13:40
The GC threshold setting after init is too high, IMNSHO, and its value seems arbitrary. If the OP thinks that Emacs will GC as soon as it allocates 100 MiB, then that's a grave mistake! What really happens is the first time Emacs *considers doing GC*, if at that time more than 100 MiB have been allocated for Lisp objects, Emacs will GC. And since neither Lisp programs nor the user have *any* control on how soon Emacs will decide to check whether GC is needed, the actual amount of memory by the time Emacs checks could be many times the value of the threshold. My advice is to spend some time measuring the effect of increased GC threshold on operations that you care about and that take a long enough time to annoy, and use the lowest threshold value which produces a tangible improvement. Start with the default value, then enlarge it by a factor of 2 until you see only insignificant speedups. I would not expect the value you arrive at to be as high as 100 MiB.
Icommentedtoday 路 2022-11-19 14:30
We already had millions of threads covering this...
Icommentedtoday 路 2022-11-19 14:31
Are you not getting tired of explaining this every time? IIRC you've been explaining this so often, on the mailing list and especially reddit. Thanks for always giving great info
fieldri1 路 2022-11-19 15:43
I use the i3 window manager, and start the daemon when I log in. If I'm not tweaking the configuration then it stays running in the background, and launches as fast as vim 馃榿
anaumann 路 2022-11-19 15:47
If it took a minute or so, I might worry about the startup time, but for 3 or 5 seconds, I value my spare time too much to even care :)
Nhaco 路 2022-11-19 15:58
Can you share your config? I'm really curious on what it is possible to do to shave startup time
OS6aDohpegavod4 路 2022-11-19 16:31
The thing that makes me apprehensive about it is it feels good for me to start up from scratch again. Are there any LSP servers running? Huge log buffers? I'm too worried if I run it as a server that I'll just want to restart the instance anyway just for undoing any crap I have going on that I don't know about.
thetemp_ 路 2022-11-19 17:08
The greatest improvement comes from taking advantage of autoloading. Most `feature`s aren't needed immediately at startup, so don't `require` them. Just make sure that the commands you would call first are set up to `autoload` the package. Most of the entry points you'd use are already set up to autoload. In the rare case that one isn't, use the `autoload` function to make it that way. Then all you have to set up are the keybindings, hooks, and `with-eval-after-load` forms that will call a package's autoloaded commands when they're needed (and will thus cause the package to be loaded at that time). This is what "use-package" does.
tonicinhibition 路 2022-11-19 17:30
I leave my Emacs daemon for days or weeks sometimes, and wrote some little watchdog aliases to start / restart the emacs it. If I ever have it fully shut down, I run it when I'm having my first sip of coffee. Start Emacs from scratch is much faster than bootstrapping my aging brain.
anaumann 路 2022-11-19 17:31
But those you can kill from within emacs.. I had my very first contact with emacs when "eight megabytes and constantly swapping" stroke fear into people, so I'm kind of eager to clear unused buffers often.. And with Python as my most frequently used language, I find myself killing the language server buffer, switching virtualenvs and visiting a fresh python file regularly, but that's only because I don't work on python code often enough to learn how to do it properly..
anaumann 路 2022-11-19 17:33
I've had my fair share of pet servers, golden images and otherwise irreproducable environments, so I enjoy starting the laptop from scratch every morning :) It doesn't take long, nowadays and by the time, I've dialled into the VPN/gone off reddit(depending on work/private laptop), emacs is there anyway and it won't go anywhere for the rest of the day :)
nullmove 路 2022-11-19 17:45
On an unrelated note (since Eli has already said all that's needed to be said about this approach), if someone is interested in the topic of reducing start-up time, they should checkout the Doom Emacs repo. Their early-init.el and specially the [lisp/doom.el](https://github.com/doomemacs/doomemacs/blob/master/lisp/doom.el) file that's loaded in it, has many cool (and hacky) tricks that I nicked from it, even though my interest is purely academic since I just use server-mode so slow start-up doesn't bother me in the least.
tonicinhibition 路 2022-11-19 17:47
I know someone was teasing you for oft-repeating yourself here, but this actually helped me. I built upon a seed config file from someone else - it turns out my threshold was set even higher than this! I simply never had any reason to investigate the "optimization" settings since I use the client anyway. I'm lucky to have a workhorse of a PC with excessive RAM due to the nature of my work and haven't noticed. I'm wondering if there's a process you recommend for profiling Emacs. Are there any in-built tools, or test-scripts I could run while monitoring the process resources?
zemja_ 路 2022-11-19 17:52
Thank you for your advice. Sorry, I didn't realise this was such a common thing. I didn't expect a value that was too large would do much harm (within reason), so I picked an arbitrary value that seemed like it would definitely be large enough.
zemja_ 路 2022-11-19 17:53
I already do this in Linux, but Emacs clients hang when starting up in Windows for some reason and I can't be bothered to figure out why.
OS6aDohpegavod4 路 2022-11-19 17:54
Sure, I can kill them manually... If I am aware of what's running, what to look for, how to look for it, and anything else that could have gotten messed up along the way by me fat fingering something.
anaumann 路 2022-11-19 17:56
The only time I was forced to use Windows, I had the company hand me a Macbook :D Coming from that experience, I would run 90% of my regular workload in WSL nowadays :)
anaumann 路 2022-11-19 18:00
Most things in emacs are buffers and there's a handy menu system to manage them :) But I'm a hands-on person in most aspects of life.. I guess, I would rather learn more about what I'm doing than copying some obscure garbage-collector optimisations off the internet. On the other hand.. From the original post's gc-optimisation to switching to nativecomp to being more clever in how to use emacs, there are many paths that lead to more enjoyment :D
Pay08 路 2022-11-19 18:07
The Windows and MacOS ports aren't official, so it's probably just a bug in the port itself. Or one of your packages depends on Linux and hangs on Windows.
eli-zaretskii 路 2022-11-19 18:08
Some day this will be common knowledge. Until then...
eli-zaretskii 路 2022-11-19 18:09
> I'm wondering if there's a process you recommend for profiling Emacs. The built-in `M-x profiler-start` should cover many needs in profiling.
tonicinhibition 路 2022-11-19 18:12
ROFL of course there is... thanks! Will try when I get home.
WallyMetropolis 路 2022-11-19 18:20
The profiler is a fantastic tool.
your_sweetpea 路 2022-11-19 18:57
Mine isn't quite as fast, but I was about to comment similar: My startup time hovers around 0.5-0.8 seconds and I'm perfectly happy with starting and closing emacs frequently with that.
your_sweetpea 路 2022-11-19 19:06
I also set `gc-cons-percentage` and nil out `file-name-handler-alist`! I strongly recommend doing both. Pro tip, you can keep all of this code in one spot by just hooking `emacs-startup-hook` rather than putting the "restore" code at the end of your config. (setq gc-cons-threshold most-positive-fixnum ; 2^61 bytes gc-cons-percentage 0.6) (defvar config:file-name-handler-alist-cache file-name-handler-alist) (setq file-name-handler-alist nil) (defun config:restore-post-init-settings () (setq gc-cons-threshold 16777216 ; 16mb gc-cons-percentage 0.1) (setq file-name-handler-alist config:file-name-handler-alist-cache)) (add-hook 'emacs-startup-hook #'config:restore-post-init-settings) Also related to avoiding GC pauses, I recommend doing the same while the minibuffer is open! Often you're going to be doing intensive blocking operations from the minibuffer and avoiding multiple GCs will speed them up. (defun config:defer-gc () (setq gc-cons-threshold most-positive-fixnum)) (defun config:-do-restore-gc () (setq gc-cons-threshold 16777216)) (defun config:restore-gc () (run-at-time 1 nil #'config:-do-restore-gc)) (add-hook 'minibuffer-setup #'config:defer-gc) (add-hook 'minibuffer-exit #'config:restore-gc) The `(run-at-time 1 ...)` bit is important to avoid noticeable lag, since it means it runs *right after* the minibuffer exits rather than *while* it's exiting. EDIT: It occurs to me that I should probably close over a local variable to restore file-name-handler-alist rather than using a global variable, might change that in my config.
MitchellMarquez42 路 2022-11-19 19:42
Here's the big one: https://git.mitchmarq42.xyz/mitch/emacs.d/src/branch/main/lisp/mitch-packages.el Basically just a lot of use-package. A very useful tool for achieving faster startup is `esup` (https://github.com/jschaf/esup) which times each code block that runs in the emacs startup. Most things that take time, you don't need right away. And when you do need them, there's less delay when loading because you're only loading that one thing. Side note. When I was using emacs at work, I would occasionally open an Org file. Emacs took about 10 seconds to load, plus another 7-8 for just Org. I don't know why. Probably some interaction with git or just filesystem churning. Either way, at that point you choose your battles. If I used Org more I would have loaded it at startup just to save time after.
YakumoYoukai 路 2022-11-19 20:23
Never gonna happen. Unless the default settings & behavior prevent Emacs from working at all, the vast majority of users will never ever have any reason to understand the GC settings, let alone put in the effort to optimize them.
andyjda 路 2022-11-19 20:46
This looks cool! Can you say a little more about file-name-handler-alist, and how setting it to nil helps startup time? I did a quick describe-variable; it looks like Emacs uses this to open files?
zemja_ 路 2022-11-19 22:30
> The Windows and MacOS ports aren't official Huh, I never knew that. It used to work fine, but suddenly stopped. It's something to do with my configuration for sure. (Interestingly, running it normally and doing `M-x sever-start` works fine. It's just running `emacsclient` that doesn't work.)
danderzei 路 2022-11-20 00:27
Why worry about saving a couple of second when you can run Emacs as a daemon and start it instantly?
Michal_Atlas 路 2022-11-20 00:28
And one more educated user here, thank you very much, many more to go.
zemja_ 路 2022-11-20 01:22
Might it be possible to put an explanation like this in the `*Help*` text for `gc-cons-threshold`? (Or mention the `(elisp) Garbage Collection` info page I found thanks to this?)
your_sweetpea 路 2022-11-20 02:16
I suspect I stole this initially from Doom, but even if I didn't `doom.el` has a pretty good explanation [here](https://github.com/doomemacs/doomemacs/blob/9d4d5b756a8598c4b5c842e9f1f33148af2af8fd/lisp/doom.el#L322-L325). Essentially it attempts to run ANY opened file (including via `load`, `require`, etc.) through the regexes in this list, and if they match it calls the associated function to handle it specially somehow. For my emacs there are 4 default values, which means it attempts to match every filename loaded 4 times with the regex engine. As long as you aren't going to load any compressed or gpg-encrypted files or use tramp during startup it should be consistently safe to unset, as long as you restore it.
redguardtoo 路 2022-11-20 02:50
You can use below setup, In `early-init.el` ``` (setq gc-cons-threshold most-positive-fixnum)\ ``` Then at the end of `init.el`, ``` (defun my-cleanup-gc () "Clean up gc." (setq gc-cons-threshold 67108864) ; 64M or whatever value you like (garbage-collect)) (run-with-idle-timer 4 nil #'my-cleanup-gc) ``` gc setup need be restored to "normal" value when startup is finished. BTW, most popular distributions already used similar setup.
dsemy 路 2022-11-20 06:44
This isn't correct - there are 3rd party ports for MacOS (not aware of any for Windows) but the GNU project also provides official ports for both (and various other operating system too). See https://www.gnu.org/software/emacs/download.html#nonfree
Pay08 路 2022-11-20 06:52
>However, GNU Emacs includes support for some other systems that volunteers choose to support.
draxil 路 2022-11-20 07:44
Why not have both!
dsemy 路 2022-11-20 07:54
I don鈥檛 see how this contradicts what I said; all Emacs versions are developed by volunteers. The GNU project hosts official binaries for Windows. The official Emacs you might install through a package manager on Linux includes code specifically to support Windows and MacOS, and their distinct features/issues are documented in the official manual: https://www.gnu.org/software/emacs/manual/html_node/emacs/Mac-OS-_002f-GNUstep.html https://www.gnu.org/software/emacs/manual/html_node/emacs/Microsoft-Windows.html (The Windows version even has a separate official FAQ). AFAIK changes which break even the MS-DOS build are not allowed in the main Emacs repository, not to mention Windows or MacOS.
deaddyfreddy 路 2022-11-20 08:27
I just use `gcmh` (put as early as possible in init file).
danderzei 路 2022-11-20 10:25
I use both only when using different configs, usually for testing
eli-zaretskii 路 2022-11-20 11:10
Thanks, done.
Pay08 路 2022-11-20 11:36
Yes, however, that disclaimer is not present for Linux and BSD. My takeaway is that they simply host the ports, but they aren't official. But it also says "We include support", so it really isn't clear.
github-alphapapa 路 2022-11-20 15:33
You work hard, so we don't have to. Thanks. :)