esup 20170729.1742(in MELPA)
the Emacs StartUp Profiler (ESUP)

init-loader.elに対応するにはnofletも必要です。
M-x package-install noflet

概要

esup(Emacs Start Up Profiler)は、Emacsの起動が遅い問題を解決します。

遅い原因を見付けるにはプロファイラをかけるのが一番!

時間がかかる処理から順に式を表示してくれます。

使い方はM-x esupを実行するだけです。

すると、子プロセスでEmacsが立ち上がり、
その結果が*esup*バッファに表示されます。

以下のサイトがとても詳しいです。

特に後者はesupに限らず、
高速起動のためのあらゆるTipsがまとまっています。

インストール

パッケージシステムを初めて使う人は
以下の設定を ~/.emacs.d/init.el の
先頭に加えてください。

(package-initialize)
(setq package-archives
      '(("gnu" . "http://elpa.gnu.org/packages/")
        ("melpa" . "http://melpa.org/packages/")
        ("org" . "http://orgmode.org/elpa/")))

初めてesupを使う方は
以下のコマンドを実行します。

M-x package-install esup

アップグレードする方は、
以下のコマンドでアップグレードしてください。
そのためにはpackage-utilsパッケージが必要です。

M-x package-install package-utils (初めてアップグレードする場合のみ)
M-x package-utils-upgrade-by-name esup

GCの結果

まず目立つのがGCの結果です。

Total User Startup Time: 11.558sec
Total Number of GC Pauses: 149
Total GC Time: 3.671sec

GCだけで3秒以上もかかってるので、これを潰しましょう。

(setq gc-cons-threshold (* 128 1024 1024))

これをinit.elの先頭に加えます。

今のパソコンならこれくらいでかい値でも問題ないです。

すると、こちらではGCにかかる時間は0.1秒になりました。

init-loaderに対応させる

しかし、 init-loader.el を使っていると、
init-loader-load全体がプロファイルされてしまうため、
そのままでは使いものになりません。

Total User Startup Time: 9.435sec     Total Number of GC Pauses: 29     Total GC Time: 0.161sec

init.el:4  9.435sec   99%
(if (equal system-name "ririn")
    (load "~/emacs/ririn")
  (let ((dir (or (getenv "INITDIR") "~/emacs/init.d/"))
        (initfile (or (getenv "INITFILE") "__NOT_EXIST__")))
    (package-initialize)                ;needed?
    (cond ((file-readable-p initfile)
           (load initfile t))
          ((file-directory-p dir)
           (require 'init-loader-x "~/.emacs.d/ext/init-loader/init-loader-x")
           (init-loader-load dir)))))

init.el:1  0.000sec   0%
(when (member "--load-el" command-line-args)
  (setq load-suffixes '(".el"))
  (setq command-line-args (remove "--load-el" command-line-args)))

init-loader自体、各ファイルの読み込みにかかった時間は計測しているので、
おおまかなことは M-x init-loader-show-log でわかります。

しかし、S式単位でのプロファイリングはできないですね。

(require 'esup)
(require 'init-loader)
(require 'noflet)
(defun esup-init-loader ()
  (interactive)
  (let ((files)
        (esup-user-init-file "/tmp/esup-init.el"))
    (noflet ((load (file &rest _) (push (locate-library file) files)))
      (init-loader-load "~/.emacs.d/inits/"))
    (with-current-buffer (find-file-noselect esup-user-init-file)
      (erase-buffer)
      (dolist (file (reverse files))
        (insert-file-contents file)
        (goto-char (point-max)))
      (save-buffer))
    (esup)))

このようにinit-loaderが読み込むファイルの内容を
/tmp/esup-init.elにまとめて、それをプロファイル対象にします。

深追い不要

ただ、プロファイルの観点からすると
Emacsの使用時間全体における起動時間は微々たるものなので、
起動時間の短縮は所詮自己満足に過ぎないと言っておきます。

一度立ち上げてしまえばずっと使うのがEmacsであり、
M-x server-start 後に emacsclient を使ってしまえば
シェルから一瞬で立ち上がります。

せいぜい gc-cons-threshold をでかくする程度で十分です。

起動時間短縮には autoload 化とか
eval-after-load (Emacs 24.4では with-eval-after-load も)とか
それらを使っているuse-package(レビュー) を使う必要がありますが、
init.el全体が長い人は書き換えにかかる時間コストが大きすぎます。

たかが数秒起動時間を短縮するのに、
何時間何日もかけてinit.elをこねくり回す必要性は皆無です。

そんなことする暇があったら、
より快適な環境を構築することに
時間をかけるべきです。

本サイト内の関連パッケージ


本日もお読みいただき、ありがとうございました。参考になれば嬉しいです。