如何衡量elisp代码的性能?


26

如何衡量我的elisp代码的性能?我可以使用哪些工具/外部软件包来衡量花费的时间?

除了总时间外,我还可以查看显示每个功能花费时间的配置文件吗?我也可以分析内存使用情况吗?


1
这个问题太广泛了。什么样的表现?哪里?什么时候?“ Emacs性能 ”可以代表一切。
2014年

@Drew许多其他编程语言都有一组基准(例如Python:speed.pypy.org,JS:Sunspider等),我希望elisp解释器具有相同的标准。
Wilfred Hughes 2014年

诸如功能benchmark和事件探查器提供的基准测试无法衡量Emacs的性能。它评估评估特定表达式的性能。这是比较有帮助的表演 Emacs的。要评估Emacs本身的性能,您需要将其与Emacs之外的其他产品的性能进行比较。这就是Emacs广度发挥作用的地方。您可以为此评估Emacs与XYZ,但是要整体评估Emacs性能,则需要进行多次这样的比较。
2014年

也许您的意思是“ 我如何衡量Emacs中的性能 ”?
2014年

2
好的,我已经打开emacs.stackexchange.com/q/655/304来对基准Emacs进行基准测试,并改写了有关对基准/概要分析elisp程序进行基准测试的问题。
2014年

Answers:


31

基准测试

最直接的选项是内置benchmark软件包。它的用法非常简单:

(benchmark 100 (form (to be evaluated)))

它是自动加载的,因此您甚至不需要它。

分析

基准测试可以很好地进行总体测试,但是如果您遇到性能问题,则不会告诉您是哪个函数导致了问题。为此,您具有(也是内置的)事件探查器

  1. 从开始M-x profiler-start
  2. 做一些耗时的操作。
  3. 使用获取报告M-x profiler-report

您应该被带到带有可导航函数调用树的缓冲区中。
Profiler屏幕截图


benchmark函数似乎不起作用:当我在打开的.c文件中进行操作时(benchmark 100 (c-font-lock-fontify-region 0 17355)),我一直在获取void-function jit-lock-bounds
Hi-Angel

1
FTR:作为替代,benchmark还有函数benchmark-runbenchmark-run-compiled。对我来说,主要的区别是,这两种功能的实际工作(见前页评论。):Ь
高新天使

14

除了@Malabara的答案外,我还倾向于使用定制的with-timer宏来永久检测代码的各个部分(例如,init.el文件)。

区别在于,尽管benchmark可以研究所检测代码的特定位的性能,但with-timer始终可以为您花费在代码的每个已检测部分上的时间(对于足够大的部分,无需太多开销),这使您可以了解输入哪一部分应该进一步研究。

(defmacro with-timer (title &rest forms)
  "Run the given FORMS, counting the elapsed time.
A message including the given TITLE and the corresponding elapsed
time is displayed."
  (declare (indent 1))
  (let ((nowvar (make-symbol "now"))
        (body   `(progn ,@forms)))
    `(let ((,nowvar (current-time)))
       (message "%s..." ,title)
       (prog1 ,body
         (let ((elapsed
                (float-time (time-subtract (current-time) ,nowvar))))
           (message "%s... done (%.3fs)" ,title elapsed))))))

使用示例:

(with-timer "Doing things"
  (form (to (be evaluated))))

*Messages*缓冲区中产生以下输出:

Doing things... done (0.047s)

我应该提到的是,乔恩·韦格利(Jon Wiegley)use-package-with-elapsed-timer出色的演绎极大地激发了他的灵感use-package


如果要测量init.el,您可能会对emacs启动分析器感兴趣。
Wilfred Hughes 2014年

宏很棒。这值得更多的选票。
马拉巴巴

2
Emacs记录总的初始化时间。您可以使用命令显示它emacs-init-time
2014年

1
@WilfredHughes是的,我确实使用,esup而且我喜欢它。但是再一次,这样的事情的兴趣with-timer并没有太多地勾勒出一些东西。真正的兴趣是您始终拥有概要信息。每当我启动emacs时,我的*Messages*缓冲区中都有很多行,告诉我哪一部分花费了多长时间。如果我发现任何异常,则可以使用任何更适当的工具来分析和优化情况。
ffevotte 2014年

@JoeS是的,emacs-init-time确实会产生有趣的信息。但是,它仅提供一个包含时间的经过时间,而无法分解初始化的各个部分。
ffevotte 2014年

3

除了@Malabarba的答案外,请注意,您可以使用来测量代码的编译执行时间benchmark-run-compiled。该指标通常比为您提供的解释执行时间更重要M-x benchmark

ELISP> (benchmark-run (cl-loop for i below (* 1000 1000) sum i))
(0.79330082 6 0.2081620540000002)

ELISP> (benchmark-run-compiled (cl-loop for i below (* 1000 1000) sum i))
(0.047896284 0 0.0)

这三个数字是总经过时间,GC运行次数以及在GC中花费的时间。


1

基准测试不仅与获取数字有关,还与基于结果分析做出决策有关。

MELPA上有Benchstat.el软件包,可用于获取Benchstat程序提供的功能。

它实现了基于比较的基准测试,您可以在其中检查X性能属性Y

Benchstat函数可以看作是benchmark-run-compiled包装器,不仅可以收集信息,还可以以易于阅读的解释格式将其返回。这包括:

  • X和之间的经过时间差Y
  • 平均平均时间
  • 分配金额

非常简单的用法示例:

(require 'benchstat)

;; Decide how much repetitions is needed.
;; This is the same as `benchmark-run-compiled` REPETITIONS argument.
(defconst repetitions 1000000)

;; Collect old code profile.
(benchstat-run :old repetitions (list 1 2))
;; Collect new code profile.
(benchstat-run :new repetitions (cons 1 2))

;; Display the results.
;; Can be run interactively by `M-x benchstat-compare'.
(benchstat-compare)

benchstat-compare会呈现在临时缓冲区的结果:

name   old time/op    new time/op    delta
Emacs    44.2ms ± 6%    25.0ms ±15%  -43.38%  (p=0.000 n=10+10)

name   old allocs/op  new allocs/op  delta
Emacs      23.0 ± 0%      11.4 ± 5%  -50.43%  (p=0.000 n=10+10)

您将需要benchstat二进制程序。如果您使用Go编程语言,则很可能您的系统中已经有一种。否则,可以选择从源代码进行编译。

可在github发布页面上找到针对Linux / amd64的预编译二进制文件。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.