0

我一直在尝试对 Lua 代码进行一些微基准测试,但遇到了一个非常烦人的问题:我似乎无法获得一致的结果。

示例:这是一个非常简单的 Lua 程序,它应该对一个简单的 Fibonacci 函数进行计时:

function pfibs(n)
  if n ~= math.floor(n) then return 0
  elseif n < 0 then return pfibs(n + 2) - pfibs(n + 1)
  elseif n < 2 then return n
  else return pfibs(n - 1) + pfibs(n - 2)
  end
end
t = os.clock()
pfibs(30)
t = os.clock() - t
print("time: "..t)

当我尝试连续运行几次时,会发生以下情况:

$ lua fib.lua
time: 1.265
$ lua fib.lua
time: 1.281
$ lua fib.lua
time: 1.343
$ lua fib.lua
time: 1.437
$ lua fib.lua
time: 1.562
$ lua fib.lua
time: 1.578
$ lua fib.lua
time: 1.64
$ lua fib.lua
time: 1.703
$ lua fib.lua
time: 1.75
$ lua fib.lua
time: 1.797
$ lua fib.lua
time: 1.796
$ lua fib.lua
time: 1.812
$ lua fib.lua
time: 1.89

(这只是一个例子,为简洁起见,但代表了我所看到的那种减速曲线)

从 1.1 秒左右开始的时间最终远远超过 2 秒。我一直在做的就是坐在这里反复按上进。time如果我将测试包装在调用中而不是使用 Lua 时钟,或者如果我让它循环几次以多花几秒钟,也会发生同样的事情;它似乎按比例减慢。如果我离开它一段时间,有时时间会倒退。有时不会(可能是因为我不知道要离开多久)。

这是在 Windows+MSYS 上。在 Ubuntu(同一台机器)上尝试这个会导致不同的模式,但仍然非常不一致和不可用的结果(例如,测试需要 2 秒,然后是 3.5 秒,然后是 4 秒,然后是 2.5 秒......)。任务管理器/顶部表明在任何一种情况下都不会在后台占用 CPU。CPU 速度切换被禁用。

我究竟做错了什么?我的机器很旧,但它不会那么坏(如果是机器的故障,我肯定会注意到它无法使用,并且每个程序每秒都变得慢得多......)。


我实际上正在尝试做的事情:

想做的是了解解释器的实现,从 vanilla Lua 开始并对其进行调整以查看更改对解释器性能的影响。正如你所看到的,我还没有通过“建立控制”,所以我实际上还没有做过任何事情——基准方差与上面一样高,我所做的任何更改都将完全丢失在噪音。我选择 Lua 是因为虽然它是一个真实世界的程序,但它也很小且易于阅读和修改。如果有更好的基础解释器可以做到这一点,或者有一个既定的最佳方式来衡量解释器的性能,请随时在答案中添加建议。


编辑:添加C标签是因为在使用传统 C 计时实用程序的 C 程序中也会发生同样的事情,例如:

#include <time.h>
#include <stdio.h>

int fib(int n) {
    return n > 2 ? fib(n - 1) + fib(n - 2) : n;
}

int main(void) {
    clock_t t1, t2; const int ITNS = 30;
    for (int i = 0; i < ITNS; i ++) {
        t1 = clock();
        fib(38);
        t2 = clock();
        printf("time: %d\n", (int)((t2 - t1) / (CLOCKS_PER_SEC / 1000)));
    }
    return 0;
}

...打印以下内容:

time: 687
time: 688
time: 687
time: 688
time: 671
time: 688
time: 687
time: 688
time: 672
time: 687
time: 688
time: 687
time: 672
time: 688
time: 687
time: 688
time: 672
time: 796
time: 766
time: 719
time: 969
time: 1000
time: 1015
time: 1000
time: 1016
time: 1000
time: 1000
time: 1015
time: 1000
time: 1000

这表明效果不限于单独运行。我想这意味着机器或操作系统存在问题。

4

3 回答 3

3

你的程序在我的机器上使用 Xeon E7-4850 似乎很稳定

time: 0.97
time: 0.98  
time: 1
time: 0.98
time: 1.01
time: 1
time: 0.98
time: 0.98
time: 1.02
time: 0.98

但是,我建议您在运行基准测试时检查是否启用了cpu-frequency-scaling或类似turbo boost的功能。我们之前遇到过类似的问题,但是当我们关闭 cpu-frequency-scaling 时,基准变得稳定。在 Linux 上,您可以使用 cpufrequtils 将其关闭。

此外,如果您使用的是AMD机器,我建议您直接切换到intel,因为即使cpu频率固定,lua程序的性能对于我们的Opteron 8431仍然不稳定。所以这个问题可能取决于硬件平台而不是Lua 解释器本身。

编辑:

我认为最好在每次迭代后读取和打印当前的 cpu 频率(来自 /proc/cpuinfo 或 /dev/cpu/#/msr),以确保频率稳定。

您使用 C 程序的结果有两个明显的稳定阶段。看起来在 run19 之后发生了一些事情并且 cpu 频率降低了。

在此处输入图像描述

于 2013-05-27T03:37:38.700 回答
0

不确定这在多大程度上是技术上的“解决方案”,但是:

通过关闭频率缩放(如建议的那样),我能够使问题停止明显地表现出来,但将 CPU 速度锁定为“始终低”而不是“始终高”。时间现在始终保持在 1% 以内,就像在其他人的机器上一样。

使用 CPU-Z 时,我注意到温度似乎也在突然下降的同时飙升。它只从 60 度跳到 72 度(在一个据说上升到 100 度的 CPU 上),但存在相关性。随着频率锁定到低,这种情况不再发生,减速也不会发生。

我认为这个问题可以归结为“我的电脑太旧且不可靠”,并且应该关闭这个问题,因为它显然根本不是一个一般的编程问题。

不过感谢您的帮助。

于 2013-05-28T19:44:27.847 回答
0

rdtsc基于时间的测量不受 CPU 频率变化的影响。您可以通过以下方式
在 LuaJIT 中使用重新定义的函数尝试基准测试 (只需设置常量以显示合理的时间值): os.clock
CPU_speed

-- New os.clock() implementation based on rdtsc instruction, LuaJIT required
do 
   local CPU_speed = 3.0 -- Your CPU speed in GHz
   local rdtsc = require'ffi'.cast(
      '__cdecl uint64_t(*)()',   
      '\x0F\x31\xC3'  -- rdtsc, ret 
   )                  -- This trick may not work on modern 64-bit OS
   local rdtsc0 = rdtsc()
   os.clock = function()
      return tonumber(rdtsc() - rdtsc0)/(CPU_speed * 10^9)
   end
end
于 2013-05-27T09:58:21.907 回答