为什么对于不同的调用,TIME报告的已允许字节数不同?

ex *_*ilo 3 lisp sbcl common-lisp

使用SBCL 1.4.12,我正在看Stuart Shapiro的Common Lisp:一种交互式方法中的练习17.9 ,并对一个reverse函数应用到10,000个元素的列表进行计时。当我使用相同的列表为该函数计时时,该time函数每次报告的字节数将有所不同。

这是该reverse函数的代码:

(defun reverse2 (l1 l2)
  "Returns a list consisting of the members of L1 in reverse order
   followed by the members of L2 in original order."
  (check-type l1 list)
  (check-type l2 list)
  (if (endp l1) l2
      (reverse2 (rest l1)
                (cons (first l1) l2))))

(defun reverse1 (l)
  "Returns a copy of the list L1
   with the order of members reversed."
  (check-type l list)
  (reverse2 l '()))
Run Code Online (Sandbox Code Playgroud)

我在REPL中使用以下命令生成了该列表:

(defvar *test-list* '())
(dotimes (x 10000)
  (setf *test-list* (cons x *test-list*)))
Run Code Online (Sandbox Code Playgroud)

以下是四个测试运行的结果:

CL-USER> (time (ch17:reverse1 *test-list*))
Evaluation took:
  0.000 seconds of real time
  0.000000 seconds of total run time (0.000000 user, 0.000000 system)
  100.00% CPU
  520,386 processor cycles
  145,696 bytes consed

CL-USER> (time (ch17:reverse1 *test-list*))
Evaluation took:
  0.000 seconds of real time
  0.000000 seconds of total run time (0.000000 user, 0.000000 system)
  100.00% CPU
  260,640 processor cycles
  178,416 bytes consed

CL-USER> (time (ch17:reverse1 *test-list*))
Evaluation took:
  0.000 seconds of real time
  0.000000 seconds of total run time (0.000000 user, 0.000000 system)
  100.00% CPU
  279,822 processor cycles
  178,416 bytes consed

CL-USER> (time (ch17:reverse1 *test-list*))
Evaluation took:
  0.000 seconds of real time
  0.000000 seconds of total run time (0.000000 user, 0.000000 system)
  100.00% CPU
  264,700 processor cycles
  161,504 bytes consed
Run Code Online (Sandbox Code Playgroud)

第二次和第三个测试运行(相隔几分钟)显示cons的字节数相同,但是其他两个显示的数字不同。我希望时间会有所不同,但是我没想到字节数会有所不同。我看到HyperSpec谈到以下time功能:

通常,这些时间不能保证足够可靠地用于市场比较。它们的值主要是启发式的,用于调整目的。

但是我希望这适用于计时,而不适用于字节数。字节consed值是否由time不可靠报告?幕后是否存在对此负责的优化?我想念什么?

tfb*_*tfb 5

精简的数量(从“分配的内存字节数”的角度来看)取决于一切:

  • 这取决于您分配多少类型的对象;
  • 它取决于分配器的详细实现细节,例如是否以大块分配,以及是否记录了大块分配之间的“分配”;
  • 这取决于垃圾收集器-是否触发了垃圾收集器?如果是这样的话?GC有多毛?GC本身会分配吗?如何在GC之间计算分配?
  • 它取决于系统是否正在执行其他分配(例如在其他线程中),以及该分配是否在您的线程中进行计数-是否只有一个分配器或每个线程的分配器?
  • 它取决于月球的相位和冥王星是否是行星;
  • 等等。

通常,如果您有一个非常简单的单线程实现,一个非常简单的分配器和一个非常简单的GC,则跟踪分配很容易,并且您将获得可靠的数字。许多Lisp的实现曾经是这样的:它们很容易理解,并且您在做任何事情时都必须喝很多茶(好吧,当时的机器速度较慢,但​​即使按时间标准,它们仍然常常令人印象深刻地缓慢)。现在,Lisps具有多个线程,复杂的分配器和GC,它们的确非常快,但是发生多少分配已成为一个难题,很难回答,而且常常有些不可预测。

  • @DavidBowling:是的,Lisp的人经常使用“ consing”和“ allocation”作为同义词(因为一次,“ cons”几乎是唯一的显式分配原语,而且肯定是使用最多的原语),因此“ bytes Consed”几乎可以肯定表示“为任何事物分配的字节”。 (3认同)