尝试微基准测试的结果不一致

时间:2013-05-27 02:35:43

标签: c lua benchmarking microbenchmark

我一直在尝试使用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秒开始的时间最终超过两秒。我一直在做的就是坐在这里反复按下输入。如果我将测试包裹在time的调用中而不是使用Lua时钟,或者如果我将其循环几次以花费几秒钟,则会发生同样的事情;它似乎按比例放缓。如果我离开它一段时间,有时候会再次失败。有时不(可能是因为我不知道要离开多久)。

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

我做错了什么?我的机器已经老了,但它不能坏了(当然我发现它是无法使用的,如果它是机器的故障,每个程序每秒都慢得多......)。 / p>


我实际上在尝试做什么:

想要做的事情是学习解释器实现,从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

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

3 个答案:

答案 0 :(得分: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机器,我建议只需切换到智能机,因为即使CPU频率是固定的,我们的Opteron 8431的lua程序性能仍然不稳定。所以这个问题可能取决于硬件平台但不是Lua解释器本身。

修改

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

C程序的结果有两个明确稳定的阶段。看起来在run19之后发生了一些事情并且cpu频率缩小了。

enter image description here

答案 1 :(得分: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

答案 2 :(得分:0)

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

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

使用CPU-Z,我注意到温度似乎在突然结果放缓的同时出现飙升。它只从60度跳到72度(在a CPU that supposedly goes up to 100 degrees上),但存在相关性。频率锁定为低电平时,不再发生这种情况,也不会减速。

我认为这个问题可以归结为“我的计算机老了,不可靠”,问题应该关闭,因为它显然不是一般的编程问题。

感谢您的帮助。