I have been trying to take some microbenchmarks of Lua code, but have run into an incredibly annoying problem: I can't seem to get consistent results.
Example: here's a dead simple Lua program that's supposed to time a naive Fibonacci function:
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)
When I try to run it several times in a row, something like this happens:
$ 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
(this is just an example, snipped for brevity, but representative of the sort of slowdown curve I'm seeing)
Times that start around 1.1 seconds end up well above two seconds. All I've been doing is sitting here pressing up-enter repeatedly. The same sort of thing happens if I wrap the test in a call to time
instead of using the Lua clock, or if I make it loop a few times to take a couple more seconds; it seems to slow down proportionally. If I leave it for a while, sometimes the times go back down. Sometimes not (probably because I don't know how long to leave it).
This is on Windows+MSYS. Trying this on Ubuntu (same machine) lead to a different pattern but still wildly inconsistent and unusable results (e.g. a test would take 2 seconds, then 3.5 seconds, then 4 seconds, then 2.5 seconds...). Task Manager/top indicate nothing chewing up CPU in the background in either case. CPU speed switching is disabled.
What am I doing wrong? My machine is old, but it can't be that broken (surely I'd notice it being unusable if it were the machine's fault and every program got that much slower every second...).
What I Am Actually Trying To Do:
What I wanted to do was learn about interpreter implementation, by starting with vanilla Lua and tweaking it to see what effect changes had on interpreter performance. As you can see I have yet to get past "establishing a control", so I haven't actually done any of that bit yet - with benchmark variance as high as the above, any changes I make are going to be utterly lost in the noise. I chose Lua because although it's a real-world program, its also tiny and easy to read and modify. If there is a better base interpreter to do this with, or an established best way to benchmark interpreter performance, please feel free to add suggestions on that to answers.
Edit: Adding the C
tag because the same thing is occurring in C programs using conventional C timing utilities as well, e.g.:
#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;
}
...prints the following:
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
This indicates the effect is not limited to separate runs. I guess this means there's a problem with the machine or OS.