我一直在尝试使用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
这表明效果不仅限于单独运行。我想这意味着机器或操作系统存在问题。
答案 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频率缩小了。
答案 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上),但存在相关性。频率锁定为低电平时,不再发生这种情况,也不会减速。
我认为这个问题可以归结为“我的计算机老了,不可靠”,问题应该关闭,因为它显然不是一般的编程问题。
感谢您的帮助。