Yanyg - SAN Software Engineer

Emacs启动时间分析

目录

1 介绍

Emacs启动调优需要先分析时间分布。benchmark-initesup是两个优秀的候选package。 benchmark-init有更好的分析粒度,修改配置文件时调用esup函数可即刻查看启动时间花费。

我的配置]]使用init.el进行最小基本配置,org文学编程维护绝大多数配置项。init.el仅进行proxy、package-archives、use-package配置,其他都位于config.org中,通过 org-babel-load-file 加载。我将benchmark-init和esup都在config.org起始处,忽略 init.el本身启动时间分析。

2 benchmark-init

benchmark-init是require和load函数的基准测试工具:

This is a simple benchmark of calls to Emacs require and load functions. It can be used to keep track of where time is being spent during Emacs startup in order to optimize startup times.

The code was originally based on init-benchmarking.el by Steve Purcell with many additional modifications having gone into it since.

benchmark-init配置如下:

#+BEGIN_SRC emacs-lisp
(use-package benchmark-init
  :init
  (benchmark-init/activate)
  :hook
  (after-init . benchmark-init/deactivate))
#+END_SRC

调用函数 benchmark-init/show-durations-treebenchmark-init/show-durations-tabulated 以树或表格方式显示结果。 benchmark-init/show-durationsbenchmark-init/show-durations-tabulated 别名。如下是一次启动部分内容截取:

Benchmark results

╼►[benchmark-init/root nil 619ms]
  ├─[company-dabbrev require 1ms]
  ├─[company-capf require 0ms]
  ├─[company-cmake require 0ms]
  ├─[company-clang require 1ms]
  ├─[company-eclim require 1ms]
   ╰─[company-template require 1ms]
  ├─[pcase require 2ms]
  ├─[default load 3ms]
  ├─[ivy-overlay require 2ms]
  ├─[ffap require 45ms]
  ├─[auto-complete-c-headers require 0ms]
   ╰─[cl require 2ms]
  ├─[ggtags require 4ms]
   ├─[etags require 3ms]
    ╰─[xref require 5ms]
      ╰─[project require 4ms]
   ╰─[ewoc require 3ms]
...
  Module                                                            Type      ms ^   total ms
  pdf-view                                                          require      78     126
  ffap                                                              require      45      45
  semantic/loaddefs                                                 load         41      41
  semantic/find                                                     require      39      39
  eieio-speedbar                                                    require      37      50
  pdf-info                                                          require      36      38
  cc-vars                                                           require      34      34
  lisp-mnt                                                          require      32      32
  cc-mode                                                           require      10      71
  cus-edit                                                          require       8       8
  ede/base                                                          require       7      10
  cc-engine                                                         require       6       6
...

3 esup

esup对emacs启动时间进行基准分析。esup-0.6版本在emacs-26.0.90版本下有 package format striing错误,参见issues 46描述,此问题已在腌a589005 提交中解决,但截至当前还无法在melpa下安装,git clone esup并替换elpa目录下的 esup-child.el并手动编译:

<cd your directory>
git clone https://github.com/jschaf/esup.git
cp esup/esup-child.el ~/.emacs.d/elpa/esup-0.6/
<start your emacs then call @byte-compile-file file
 ~/.emacs.d/elpa/esup-0.6/esup-child.el>

esup无法对org-babel加载文件的子条目进行析(即使设置分析深度变量 esup-child-profile-require-level 也是如此)。而我的配置绝大多数在 config.org中,因此写了一个wrapper函数协助:

#+BEGIN_SRC emacs-lisp
  ;; evaluate emacs starting time
  (when (getenv "ESUP_PROFILER")
    (progn
      ;; init.el does not evaluated when call y:esup
      ;; then load init.el diretly here
      (message "Import init.el for ESUP_PROFILER.")
      (load-file (expand-file-name "init.el" user-emacs-directory))))
  (defun y:esup()
    "Profiler Emacs Startup Time."
    (interactive)
    (when (fboundp 'esup)
      (progn
        ;; First set env then load init.el to avoid recursive includes.
        (setenv "ESUP_PROFILER" "t")
        (esup (expand-file-name "config.el" user-emacs-directory)))))

  (use-package esup
    :init
    (setq esup-child-profile-require-level 2))
#+END_SRC

调用函数 y:esup 查看结果:

config.el:624  0.176sec   8%
(use-package yasnippet
:diminish yas-minor-mode
:init
(yas-global-mode 1))

config.el:506  0.119sec   5%
(use-package auto-complete-config
:diminish auto-complete-mode
:ensure auto-complete
:init
(ac-config-default))

config.el:103  0.104sec   5%
(when (fboundp 'tool-bar-mode)
(tool-bar-mode -1))

config.el:122  0.088sec   4%
(use-package monokai-theme
:init
(load-theme 'monokai t))
...

也可调用 esup 分析,但只能显示config.org总时间。如果配置全部在init.el文件中,调用esup也可达成分析目的:

init.el:142  1.427sec   73%
(unless (getenv "ESUP_PROFILER")
(org-babel-load-file (expand-file-name "config.org" user-emacs-directory)))

esup默认分析 user-init-file 文件,执行 C-u M-x esup 可指定其他文件名。