Emacs 启动优化二三事

*/-->

div.org-src-container {
font-size: 85%;
font-family: monospace;
}
p {font-size: 15px}
li {font-size: 15px}

这两天一直在折腾 Emacs 的配置文件以优化启动时间,这里做个简单的总结。

1 启动(加载)时间检测

检测配置文件的加载时间非常简单,开始加载之间加个时间戳,加载结束之后计算一下时间即可:

 ;; Load all configuration and packages.
(let ((ts-init (current-time)))
(setq missing-packages-list nil
package-init-statistic nil)
(try-require '01-rc-generic t)
(try-require '02-rc-functions t)
(try-require '04-rc-other-modes t)
(try-require '05-rc-misc t)
(try-require '03-rc-prog-mode t)
(try-require '06-rc-complete t)
(try-require '09-rc-keybindings t)
(try-require '10-emacs-custome t)
(try-require '99-proj t)
(try-require '100-private t)
;; Report package statistics. (message "\n\nShowing package initialization statistics:\n%s"
(mapconcat (lambda (x)
(format "package %s cost %.2f seconds" (car x) (cdr x)))
(reverse package-init-statistic)
"\n"
))
(message "Finished startup in %.2f seconds, %d packages missing%s\n\n"
(float-time (time-since ts-init)) (length missing-packages-list)
(if missing-packages-list
". Refer to `missing-packages-list` for missing packages."
".")))

上面代码中有个 try-require ,最早取自 这里 , 后来对他加了一些改动:

 ;; Function to collect information of packages.
(defvar missing-packages-list nil
"List of packages that `try-require' can't find.") (defvar package-init-statistic nil "Package loading statistics") ;; attempt to load a feature/library, failing silently
(defun try-require (feature &optional click)
"Attempt to load a library or module. Return true if the
library given as argument is successfully loaded. If not, instead
of an error, just add the package to a list of missing packages."
(condition-case err
;; protected form
(let ((timestamp (current-time))
(package (if (stringp feature) feature (symbol-name feature))))
(if (stringp feature)
(load-library feature)
(require feature))
(if click
(add-to-list 'package-init-statistic
(cons (if (stringp feature) feature (symbol-name feature))
(float-time (time-since timestamp)))))
(message "Checking for library `%s'... Found, cost %.2f seconds"
feature (float-time (time-since timestamp))))
;; error handler
(file-error ; condition
(progn
(message "Checking for library `%s'... Missing" feature)
(add-to-list 'missing-packages-list feature 'append))
nil)))

该函数检查 feature 时候存在,如果在则加载并输出加载所用的时间,如果不在,输出警告信息并记录缺失的文件。 同时,如果可选参数 click 被设置成,则还将加载耗费的时间信息记录到全局的 package-init-statistic 中,以便后续查询。

在我的机器上,上述配置会产生下面的信息:

Showing package initialization statistics:
package 01-rc-generic cost 0.16 seconds
package 02-rc-functions cost 0.15 seconds
package 04-rc-other-modes cost 0.03 seconds
package 05-rc-misc cost 0.53 seconds
package 03-rc-prog-mode cost 1.22 seconds
package 06-rc-complete cost 0.18 seconds
package 09-rc-keybindings cost 0.08 seconds
package 10-emacs-custome cost 0.00 seconds
package 99-proj cost 0.00 seconds
package 100-private cost 0.01 seconds
Finished startup in 2.40 seconds, 0 packages missing.

可见配置信息加载之后总共话费了 2.4 秒,相对于 Emacs 强大的功能来说,加载时间还算不错,尤其是启动之后 server-mdoe 会自动启动,此时再用 emacs-client 来打开文件时,时间消耗会非常小了。

2 autoload and eval-after-load

上述代码中仅简单说明了要通过 try-require 来加载哪些配置文件,单个配置文件中则大量使用了 autoloadeval-after-load 来将 mode 相关的配置时间尽量延后,关于 autoloadeval-after-load这里 有比较详细的解释,简单来说,

  • autoload 可以从让 Emacs 知道去哪个文件中去找指定的函数或者定义,但不用去真正的加载它。
  • eval-after-load 则可以安排 Emacs 在真正加载某个文件或者符号的时候去做一些事情。

有时候我还想知道 eval-after-load 安排的事情在执行时候花费多少时间,为此写了个 Emacs Macro:

(defmacro yc/eval-after-load (name &rest args)
"Macro to set expressions in `arg` to be executed after `name` is loaded."
`(eval-after-load ,name
',(append (list 'progn
`(let ((ts (current-time)))
(message "Loading configuration for: %s..." ,name)
,@args
(message "Configuration for %s finished in %.2f seconds" ,name
(float-time (time-since ts ))))))))

使用实例:

(autoload 'erlang-mode "erlang" "erlang"  t)
(add-to-list 'auto-mode-alist '("\\.erl\\'" . erlang-mode))
(add-to-list 'auto-mode-alist '("\\.escript\\'" . erlang-mode))
(yc/eval-after-load "erlang"
(try-require 'erlang-flymake)
(let ((erl-root
(cond
((string= system-type "windows-nt") nil)
((string= system-type "darwin") nil)
(t "/usr/lib/erlang"))))
(setq erlang-root-dir erl-root)))

上面的代码告诉 Emacs 从 "erlang.el" 这个文件中可以找到 erlang-mode 这个 Mode, 并安排在加载 erlang.el 之后加载 erlang-flymake 并设置一些变量。 当打开一个 erl 文件后,会有如下的输出:

Loading configuration for: erlang...
Checking for library `erlang-flymake'... Found, cost 0.00 seconds
Configuration for erlang finished in 0.00 seconds

3 backtrace

backtrace 当然是用来打印 backtrace 的,它不会帮助解决文件加载速度,但如果我们觉得某些文件不应该加载,但启动时候却自动加载了,那么可以在
eval-after-load 的后面加上这句话,然后看下 backtrace

我遇到的一个问题是,每次 Emacs 启动时候都会自动尝自动加载 magit 的配置,搜索无果后在 magit 的配置里面加上 backtrace , 结果定位到是其他的 package
里用了 (require 'magit) ,对那个 package 稍作修改即可。

4 function and advice

这个 advice 其实和 Emacs 启动加载没什么关系,但懒得单独再写什么东西了,这里简单记上两笔。

  • Emacs 很独特,用户可以为某个 function 给出一些建议,并可以让该建议在函数执行之前,之后,或者之前加上之后来执行。
  • 对于上面的第三种情况 (around-advice),如果 advice 中没有用到 ad-do-it ,则 function 本身无任何作用,相当于覆盖了原有的function。
  • advice 中可以通过变量 ad-return-value 来设置返回值。

更具体的信息可以查看 elisp 的 info ,这里几下一个简单的例子, hideif 中的
hide-ifdefs 总会输出信息来通知用户 hiding 的启动和结束,很讨厌,我们可以通过 advice 来直接覆盖掉原来的函数:

(autoload 'hide-ifdef-mode "hideif" ""  t)

(yc/eval-after-load
"hideif"
(setq hide-ifdef-shadow t)
(setq-default hide-ifdef-env
'((__KERNEL__ . 1)
(DEBUG . 1)
(CONFIG_PCI . 1)
)) (defadvice hide-ifdefs (around yc/hideifdefs (&optional nomsg))
(interactive)
(setq hif-outside-read-only buffer-read-only)
(unless hide-ifdef-mode (hide-ifdef-mode 1)) ; turn on hide-ifdef-mode
(if hide-ifdef-hiding
(show-ifdefs)) ; Otherwise, deep confusion.
(setq hide-ifdef-hiding t)
(hide-ifdef-guts)
(setq buffer-read-only (or hide-ifdef-read-only hif-outside-read-only))
)
(ad-activate 'hide-ifdefs) (defun yc/add-to-ifdef-env (lst)
"Helper function to update ifdef-env."
(let (kvp k v)
(while (setq kvp (pop lst))
(setq k (car kvp)
v (cdr kvp))
(hif-set-var k v)
(when (and (symbolp k) (symbolp v))
(add-to-list 'semantic-lex-c-preprocessor-symbol-map (cons (symbol-name k)
(symbol-name v))))))) (defun yc/toggle-hide-if-def-shadow ()
"Toggle shadow"
(interactive)
(setq hide-ifdef-shadow (not hide-ifdef-shadow))
(hide-ifdefs)) ;; Copied from Ahei:
;; http://code.google.com/p/dea/source/browse/trunk/my-lisps/hide-ifdef-settings.el
(defun hif-goto-endif ()
"Goto #endif."
(interactive)
(unless (or (hif-looking-at-endif)
(save-excursion)
(hif-ifdef-to-endif)))) (defun hif-goto-if ()
"Goto #if."
(interactive)
(hif-endif-to-ifdef)) (defun hif-goto-else ()
"Goto #else."
(interactive)
(hif-find-next-relevant)
(cond ((hif-looking-at-else)
'done)
((hif-ifdef-to-endif) ; find endif of nested if
(hif-goto-endif)) ; find outer endif or else ((hif-looking-at-else)
(hif-goto-endif)) ; find endif following else ((hif-looking-at-endif)
'done) (t
(error "Mismatched #ifdef #endif pair"))))
)

Emacs 启动优化二三事的更多相关文章

  1. fir.im Weekly - APP 性能监测优化 二三事

    每一个成功的 App,都拥有强大的性能体验.本期 fir.im Weekly 整理了微信读书.美团外卖. 天猫.美团点评技术团队的关于性能监测优化方面策略和工具的分享,一起来看看. 微信读书 iOS ...

  2. Java并发编程二三事

    Java并发编程二三事 转自我的Github 近日重新翻了一下<Java Concurrency in Practice>故以此文记之. 我觉得Java的并发可以从下面三个点去理解: * ...

  3. MySQL优化二(连接优化和缓存优化)

    body { font-family: Helvetica, arial, sans-serif; font-size: 14px; line-height: 1.6; padding-top: 10 ...

  4. WinForm二三事(三)Control.Invoke&Control.BeginInvoke

    http://www.cnblogs.com/yuyijq/archive/2010/01/11/1643802.html 这个系列从2009年写到2010年,差点又成太监文.随着WPF/Silver ...

  5. Android 项目优化(五):应用启动优化

    介绍了前面的优化的方案后,这里我们在针对应用的启动优化做一下讲解和说明. 一.App启动概述 一个应用App的启动速度能够影响用户的首次体验,启动速度较慢(感官上)的应用可能导致用户再次开启App的意 ...

  6. apm 应用性能管理(启动优化/ 掉帧卡顿/ 耗电/ 内存泄漏等)

    APM 首先查看各个阶段耗时 : (环境变量设置 dyldPRINTSTATISTICS = 1选项,) 1. 启动优化 关键: 找到耗时的原因 t总 = t1 (premain) + t1(main ...

  7. eclipse启动优化,终于不那么卡了!

    eclipse启动优化,终于不那么卡了! 网上找了好多都是myEclipse的优化的,跟eclipse有点区别,找了很多方法还是不能让这个eclipse(Version: Kepler Release ...

  8. 一触即发 App启动优化最佳实践

    一触即发 App启动优化最佳实践 本文在 DiyCode 和 CSDN个人博客 同时首发,关注作者的 DiyCode帐号 或者 作者微博 可第一时间收到新文章推送. 文中的很多图都是Google性能优 ...

  9. EMW 性能优化二之---并发配置

    EMW 性能优化二之---并发配置 在前一个日志中写到交货的异步更新,对于RFUI RF的前台操作会提升效率,异步更新不用等待更新状态的返回,启用更新队列的方式执行(SM13). 下面再补全性能相关的 ...

随机推荐

  1. 微信开发使用 frp 实现本地测试

    前提条件: 1.有公网服务器(如阿里云) 2.需要独立的 80 端口,也就是说,想要实现这个目标,服务器上不能跑 nginx 之类占用 80 端口的程序 3.有可以测试使用的域名,并解析到上面说的公网 ...

  2. 题解【CF103D Time to Raid Cowavans】

    Description 给一个序列 \(a\) ,\(m\) 次询问,每次询问给出 \(t, k\) .求 \(a_t + a_{t+k}+a_{t+2k}+\cdots+a_{t+pk}\) 其中 ...

  3. Docker应用四:搭建docker镜像仓库(包括自生成https证书、登陆认证)

    利用docker官网提供的registry镜像创建私有仓库 一.首先从docker官网拉取registry镜像: docker pull registry 二.然后运行该镜像: docker run ...

  4. (转)Tomcat配置调优与安全总结

    tomcat配置调优与安全总结 作为运维,避免不了与tomcat打交道,然而作者发现网络上关于tomcat配置和调优安全的文章非常散,通过参考各位大神的相关技术文档,根据作者对tomcat的运维经验, ...

  5. poj 1961 Period

    Period http://poj.org/problem?id=1961 Time Limit: 3000MS   Memory Limit: 30000K       Description Fo ...

  6. HDU 1564 简单博弈 水

    n*n棋盘,初始左上角有一个石头,每次放只能在相邻的四个位置之一,不能操作者输. 如果以初始石头编号为1作为后手,那么对于每次先手胜的情况其最后一步的四周的编号必定是奇数,且此时编号为偶数,而对于一个 ...

  7. python学习笔记2-文件操作

    一.文件操作 #文件操作一定要注意文件指针 f=open('','a+,encoding=utf-8) f.seek(0) #文件指针移到行首 f.tell()#查看文件指针的位置 f.read()# ...

  8. 推荐一些我所用的firefox 附加组件。

    firefox之所以强大,很大程度上是因为它有着超多的扩展组件,来实现许多有趣的功能.这几天把我装的firefox附加组件整理下,个人认为是一般上网常用或者可以说是必备的组件,o(∩_∩)o ,晒晒. ...

  9. [OI]省选前模板整理

    省选前把板子整理一遍,如果发现有脑抽写错的情况,欢迎各位神犇打脸 :) 数学知识 数论: //组合数 //C(n,m) 在n个数中选m个的方案数 ll C[N][N]; void get_C(int ...

  10. 20155236 2016-2017-2 《Java程序设计》第四周学习总结

    20155236 2016-2017-2 <Java程序设计>第四周学习总结 教材学习内容总结 1.继承基本上就是避免多个类间重复定义共同行为. 继承的三个好处:减少代码冗余:维护变得简单 ...