19.5 性能剖析

如果程序运行正确但速度不够快,你希望让它运行得更快、更高效, 首先要做的就是对你的代码进行性能剖析(profile), 从而知道代码在哪些地方消耗了最多执行时间。 如果你发现某个特定函数占用了很大比例的执行时间, 就可以开始寻找优化该部分的方法。

Emacs 内置了对此的支持。 要开始剖析,输入 M-x profiler-start。 你可以选择定期采样 CPU 使用情况(cpu)、 内存分配时采样(memory),或两者同时进行。 然后运行你想要优化的代码。 之后,输入 M-x profiler-report, 为你选择剖析的每种类型(CPU 和内存)显示一个汇总缓冲区。 报告缓冲区的名称包含报告生成的时间, 因此你可以稍后生成另一份报告而不会覆盖之前的结果。 剖析完成后,输入 M-x profiler-stop (剖析会带来少量开销,因此不建议在不实际运行待分析代码时保持开启)。

性能剖析报告缓冲区的每一行显示一个被调用的函数, 前面是自剖析开始以来该函数使用的 CPU 资源的绝对值和百分比。 如果某一行函数名左侧有 ‘+’ 符号, 你可以按 RET 展开该行,查看上层函数调用的子函数。 使用前缀参数(C-u RET)可以查看该函数下的完整调用树。 再次按 RET 会折叠回原来的状态。

jprofiler-report-find-entry) 或 mouse-2 跳转到光标处函数的定义。 按 dprofiler-report-describe-entry)查看函数的文档。 你可以用 C-x C-wprofiler-report-write-profile) 将剖析结果保存到文件,并用 M-x profiler-find-profileM-x profiler-find-profile-other-window 读取已保存的剖析结果。 使用 =profiler-report-compare-profile)可以对比两份剖析结果。

elp 库提供了另一种方式, 适用于你预先知道要剖析哪些 Lisp 函数的场景。 使用该库时,首先将 elp-function-list 设置为你要剖析的函数符号列表。 然后输入 M-x elp-instrument-list RET nil RET 开始对这些函数进行剖析。 运行待剖析代码后,调用 M-x elp-results 显示当前结果。 更详细的说明见文件 elp.el。 该方式仅限于剖析用 Lisp 编写的函数,不能剖析 Emacs 原语函数。

你可以使用 benchmark 库对单个 Emacs Lisp 表达式的求值耗时进行测量。 参见 benchmark.el 中的函数 benchmark-call 以及宏 benchmark-runbenchmark-run-compiledbenchmark-progn。 你也可以交互式使用 benchmark 命令对表达式计时。

要在 C 代码层面剖析 Emacs,可以在构建时使用 configure--enable-profiling 选项。 当 Emacs 退出时,会生成文件 gmon.out, 你可以用 gprof 工具分析它。 该功能主要用于调试 Emacs 本身。 它会使上面介绍的 Lisp 层面 M-x profiler-… 命令失效。


emacs

Emacs

org-mode

Orgmode

Donations

打赏

Copyright

© 2025 Jasper Hsu

Creative Commons

Creative Commons

Attribute

Attribute

Noncommercial

Noncommercial

Share Alike

Share Alike