Working on my game, I often find myself wondering how much cpu such or such construct uses.
I do my benchmarks using stat(1).
Issue is, my measures are all over the place according to the number of samples :[
Ex: Let's bench band vs. % and shr vs / @ 100 calcs/update
Good, % is almost free, / is slightly better than shr
Let's try 200:
Hu? shr is now better than /
Push it to 300:
Back to "normal"
400:
WTF?
How come number of samples for a given run is turning results upside down?
Note: if I push number of iterator further, I tend to have stable results - but who's performing 5000% per update cycle?!?
On top of that, @zep, we should be provided with op cost of basic operations (similar to cpu specs).
Reference code:
function bench(name,n,fn) local t0=stat(1) for i=1,n do fn(i) end return {name,(stat(1)-t0)} end function stat2pct(s) return flr(1000*s)/10 end function bench_draw(name1,stat1,name2,stat2,y) print(name1.." vs. "..name2,1,y,7) y+=6 local total=stat1+stat2 local pct1,pct2=stat1/total,stat2/total local c1,c2=8,11 if(stat1<stat2) c1=11 c2=8 local x=flr(128*pct1) rectfill(0,y,x+1,y+6,c1) x+=1 print(stat2pct(stat1),x/2,y+1,0) local x2=128*pct2 local msgx2=x+x2/2 if(x2<1) then x=127 x2=127 msgx2=120 end rectfill(x,y,x+x2,y+6,c2) print(stat2pct(stat2),msgx2,y+1,0) y+=8 return y end local res={} local n=100 function _update60() if(btnp(0)) n-=100 if(btnp(1)) n+=100 n=max(n,100) res={} add(res,bench("band",n,function() j=band(546,127) end)) add(res,bench("%",n,function() j=546%128 end)) add(res,bench("shr",n,function() j=90/8 end)) add(res,bench("/",n,function() j=shr(90,3) end)) end function _draw() cls(0) rectfill(0,0,127,6,1) print(n.." iterations - \139\145 to change",1,1,7) local y=9 for i=1,#res,2 do y=bench_draw(res[i][1],res[i][2],res[i+1][1],res[i+1][2],y) end end |
In 0.1.10c, certain operations have negative cost. See this thread: https://www.lexaloffle.com/bbs/?tid=29318, and in particular this demo cart: https://www.lexaloffle.com/bbs/?pid=40734#p40733
BTW, this is not an artefact of fixed-point precision, but rather the ad-hoc way PICO-8 does accounting, where some operations have positive cost, some have negative cost, and 1024 is added to the stat value every so often (based on the Lua bytecode instruction count, not PICO-8 commands, so it's difficult to predict). I think zep may be planning to clean some of this up in an upcoming release.
Just saw the other thread - framerate can be completely cheated using this single line:
for i=0,32000 do bnot(bnot(bnot(bnot(bnot(bnot(bnot(1))))))) bnot(bnot(bnot(bnot(bnot(bnot(bnot(1))))))) end |
I can now spawn gazillion of scaled sprites at 60fps!!
Question: is this exploit going to be fixed?
Edit: removed strong wording
There's not much admitting necessary. What's necessary is for zep to finish and release the next version, which, uh... doesn't seem to be happening... :/
Feature creep is dangerous, yo. :)
By the way, if you want to time individual operations, I posted a simple test rig here that gives pretty accurate pseudo-cycle counts:
[Please log in to post a comment]