emacs slow startup time


Before tuning, it worth of checking Emacs startup time itself. Firstly you would need to create a file, let’s call it emacs-startup-time.el and put follow content into it:

(add-hook 'emacs-startup-hook
          (lambda ()
            (message "*** Emacs loaded in %s with %d garbage collections."
                     (format "%.2f seconds"
                             (float-time
                              (time-subtract after-init-time before-init-time)))
                     gcs-done)))

then run it:

emacs -q -l emacs-startup-time.el

In status line you should see time that was needed to load Emacs. This time could show if it’s already something wrong with your installation of Emacs. If it something less than 0.5 sec than there are nothing to worry about, but don’t forget to add this time in total load time with your configuration.

Time to check your configuration! I used ESUP (Emacs Start Up Profiler) package with follow configuration:

(use-package esup)

Then just run it M-x esup. That should display list of packages and their time to load.

Full configuration of how it may be look like:

;; Startup time
(add-hook 'emacs-startup-hook
          (lambda ()
            (message "*** Emacs loaded in %s with %d garbage collections."
                     (format "%.2f seconds"
                             (float-time
                              (time-subtract after-init-time before-init-time)))
                     gcs-done)))

;; Package Management
(require 'package)

(setq package-archives '(("elpa" . "http://elpa.gnu.org/packages/")
                         ("nongnu" . "https://elpa.nongnu.org/nongnu/")
                         ("melpa" . "https://melpa.org/packages/")
                         ("melpa-stable" . "https://stable.melpa.org/packages/")))

(package-initialize)

;; Bootstrap `use-package`
(unless (package-installed-p 'use-package)
    (package-refresh-contents)
    (package-install 'use-package))

(require 'use-package)
;; Always ensure packages
(setq use-package-always-ensure t)

(use-package esup
    :commands esup)

;; Your configuration

Some techniques to reduce package load time for use-package:

  1. Use :defer t
  2. Use :hook, e.g. :hook (typescripe-mode . lsp-deferred) or :hook (after-init . keychain-refresh-environment)
  3. Use :mode, e.g. :mode ("\\.ya?ml\\'" . yaml-mode)- there are no need of using :defer t if you have mode added

All of them described in documentation of use-package.

Overall, using this tool helped me to identify problematic area reduce Emacs startup time from 10s to 2.3s. That’s 4.5x times less and make it more snappy!

Also, I tried Profile Dot Emacs option that does not help me to profile startup time.

P.S. For older version of Emacs there was an error:

error in process sentinel: Wrong type argument: (or eieio-object class), nil, obj [2 times]

that could be fixed with adding esup-depth configuration:

(use-package esup
  :config
  ;; Work around a bug where esup tries to step into the byte-compiled
  ;; version of `cl-lib', and fails horribly.
  (setq esup-depth 0))

Thanks a lot benley for solution https://github.com/jschaf/esup/issues/54#issuecomment-651247749

comments powered by Disqus