common-lisp - Common Lisp SBCL 中函数调用的性能

标签 common-lisp benchmarking dead-code

我是 Common Lisp 的新手,遇到了一个让我觉得很奇怪的性能问题。我在循环中使用 rem 检查一个数字是否可以被 10 整除。如果我将支票移动到一个函数中,它的运行速度会慢 5 倍。什么会导致这种情况?

我在 64 位 Ubuntu 18.04 上运行 sbcl 1.4.5。

(defun fn (x)
  (= 0 (rem x 10))
  )

(defun walk-loop-local (n)
  (loop for i from 1 to n do
       (= 0 (rem i 10))
       ))

(defun walk-loop-func (n)
  (loop for i from 1 to n do
       (fn i)
       ))

(time (walk-loop-local 232792560))
(time (walk-loop-func 232792560))

我希望时间是相同的(而且要快得多,但这是一个单独的问题)。相反,这是输出,
CL-USER> (load "loops.lisp")
Evaluation took:
  0.931 seconds of real time
  0.931389 seconds of total run time (0.931389 user, 0.000000 system)
  100.00% CPU
  2,414,050,454 processor cycles
  0 bytes consed

Evaluation took:
  4.949 seconds of real time
  4.948967 seconds of total run time (4.948967 user, 0.000000 system)
  100.00% CPU
  12,826,853,706 processor cycles
  0 bytes consed

最佳答案

您正在使用 SBCL 编译器:

(defun walk-loop-local (n)
  (loop for i from 1 to n do
       (= 0 (rem i 10))))

我认为您的代码在循环迭代中什么都不做。它被优化掉了,因为 = 的值form 不会在任何地方使用,也没有副作用。

因此没有开销,因为没有代码。

使用 (disassemble #'walk-local-form)检查编译代码。

If I move the check into a function, it runs 5x slower. What would cause that?



不是什么都不做,而是在每次迭代中调用该函数并执行您的代码。

实际测量调用开销
(defparameter *i* nil)

(defun walk-loop-local (n)
  (loop for i from 1 to n do
        (setf *i* (= 0 (rem i 10)))))

(defun fn (x)
  (setf *i* (= 0 (rem x 10))))

(defun walk-loop-func (n)
  (loop for i from 1 to n do
       (fn i)))

在上述情况下,代码不会被删除。
CL-USER> (time (walk-loop-local 232792560))
Evaluation took:
  5.420 seconds of real time
  5.412637 seconds of total run time (5.399134 user, 0.013503 system)
  99.87% CPU
  6,505,078,020 processor cycles
  0 bytes consed

NIL
CL-USER> (time (walk-loop-func 232792560))
Evaluation took:
  6.235 seconds of real time
  6.228447 seconds of total run time (6.215409 user, 0.013038 system)
  99.89% CPU
  7,481,974,847 processor cycles
  0 bytes consed

您可以看到函数调用开销并没有那么大。

关于common-lisp - Common Lisp SBCL 中函数调用的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56624200/

相关文章:

lisp 从另一个列表中删除一个列表的内容

common-lisp - 如何构建 Common Lisp 项目?

c++ - 如何在多核机器上解释 boost::timer::cpu_timer 的输出?

algorithm - 自定义算法所需的基准周期/字节

Javascript : Event listener defined inside function of object literal making the code dead

json - 在 lisp 中输入/输出 json 文件

lisp - 请批评我的 Lisp

java - 通过方法推送对象时是否会创建对象的副本?

css - 如何真正找到网站上所有未使用的 css 样式

java - if(false) 与 while(false) : unreachable code vs. 死代码