home

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

2020-04-15-emacs-bankruptcy-is-fun.org (4864B)


      1 #+title: Emacs bankruptcy is fun
      2 #+date: <2020-04-15 Wed>
      3 #+filetags: emacs configuration optimization
      4 #+setupfile: ../templates/post.org
      5 
      6 * Introduction
      7 
      8 Since go 1.14 go released, I've had a broken =go-mode= setup on my Emacs. I was using
      9 =lsp-mode= and =gopls= and well, the update broke everything. I initally try to fix it but
     10 I made it worse. At the same time, I started to get fed up with some performance issue of
     11 my configuration and how slow my Emacs starts, about 6s.
     12 
     13 I, thus, declared my third Emacs bankruptcy, =:disabled= everything and slowly started
     14 from scratch, with the following goal:
     15 
     16 - Have it start quick, as less than a second, not too much more than =emacs -Q= would
     17 - Disable anything that I don't use often initially
     18 - Try to use as much built-in as possible (example: using =icomplete= instead of
     19   =ivy=/=counsel=)
     20 
     21 * Do I really need this feature
     22 
     23 Following [[https://protesilaos.com/][Protesilaos Stavrou]]'s emacs videos (and [[https://protesilaos.com/dotemacs/][=dotemacs=]]) for a while now, I have a
     24 tendency to try to use built-in feature as much as possible. The most obvious example is
     25 using =icomplete= instead of =ivy=/=counsel=.
     26 
     27 When I started my /bankruptcy/, I disabled every single customization I had, either using
     28 =:disabled= when using =use-package= *or* the =(when nil)= /hack/. I then started Emacs
     29 and acted on what was missing :
     30 
     31 1. Do I really miss it ? An example would be, at least initially, the completion in a =go=
     32    file. I do miss it, but I miss it *way less* than having Emacs lagging because of
     33    =lsp-mode= and showing me wrong completion.
     34 2. Is there a built-in option to what I previously used ? Here, the =icomplete= example
     35    fits well, or =isearch= instead of =swiper=.
     36 3. Do I need it at startup or /on-demand/ ?
     37 
     38 * Looking into what takes time
     39 
     40 In "Advanced Techniques for Reducing Emacs Startup Time"[fn:1], I discovered the [[https://github.com/jschaf/esup][=esup=]]
     41 emacs library. In a gist, this is a profiler for Emacs. It starts a new Emacs instance and
     42 look at the loading time.
     43 
     44 #+CAPTION: esup "result" view
     45 [[../images/2020-04-15-16-12-54.png]]
     46 
     47 Then, you can do a simple loop:
     48 
     49 - Run =esup=
     50 - Look at the top result
     51 - Fix it (lazy load, removing the feature, …)
     52 - Re-iterate
     53 
     54 * Loading on-demand
     55 
     56 Once you have the setup to know what takes time and what not, it's time to look into how
     57 to load the most thing on demand.
     58 
     59 For this, [[https://github.com/jwiegley/use-package][=use-package=]] is amazing, it tremendously help autoloading modules on-demand. If
     60 you are not using =use-package=, usually you are using =require=, which loads the
     61 underlying source file (all of it).
     62 
     63 With =use-package=, there is multiple ways to load on demand:
     64 
     65 - =:commands= to add callable that will trigger loading the package
     66 - =:bind=, =:bind*=, =:bind-keymap= and =:bind-keymap*= to bind key sequences to the
     67   global keymap or a specific keymap.
     68 - =:mode= and =:interpreter= establish a deferred binding with the =auto-mode-alist= and
     69   =interpreter-mode-alist=.
     70 - =:hook= allows adding functions onto the package hook
     71 - =:defer= is the most generic one, all the previous keyword imply =:defer=. You can
     72   specify a number of second of idle to load the package.
     73 
     74 #+BEGIN_aside
     75 In a gist for =org-babel=, use =use-package ob-python= and never call =org-babel-do-languages=.
     76 #+END_aside
     77 Once this is done, you are left with edge cases, like =org-babel-do-languages=.  Those are
     78 to be handle case by case. The good thing about those cases is that you'll learn what
     79 those function do and this will give you an even better understanding of what is
     80 happening.
     81 
     82 Doing this exercise also forces you to make you see if you really use that feature or
     83 not. I ended up removing entire feature from my configuration because they were taking
     84 quite some time to load, and was used almost never. Instead I am forcing myself to learn
     85 more what I can do with the built-in features first.
     86 
     87 * Conclusion
     88 
     89 All in all, this /bankruptcy/ was the most fun I had to do. I consider myself still in the
     90 process but the base is there.
     91 
     92 1. I learned a lot !
     93 2. My Emacs starts in 0.6s against previously in 5s — =emacs -q= starts in about 0.3s so
     94    there is still a little bit of room for improvement.
     95 3. I discovered / re-discovered a lot of built-in feature
     96 4. I started documenting my configuration, see [[../configurations/emacs.org][here]].
     97 
     98 🎉
     99 
    100 :update:
    101 Well, I've look into the /portable dump/ feature of Emacs, thanks to [[https://archive.casouri.cat/note/2020/painless-transition-to-portable-dumper/index.html][Painless Transition
    102 to Portable Dumper]]. And I am now down to =0.091s= for the startup. There is a few gotchas
    103 with /portable dump/, I'll try to write about it later.
    104 :end:
    105 
    106 * Footnotes
    107 
    108 [fn:1]: [[https://blog.d46.us/advanced-emacs-startup/][Advanced Techniques for Reducing Emacs Startup Time]]