Improving Lua performance using baked functions(tasvideos.org)
tasvideos.org
Improving Lua performance using baked functions
http://tasvideos.org/forum/viewtopic.php?t=20672
9 comments
> Wow, now this is deep!
It certainly doesn't help that GitHub renders tabs as 8 spaces wide instead of something more sane.
It certainly doesn't help that GitHub renders tabs as 8 spaces wide instead of something more sane.
Agreed. You can change it by appending `?ts=2' at the end, such as:
https://gist.github.com/realmonster/93090d4ef0b40c1b88d62f88...
https://gist.github.com/realmonster/93090d4ef0b40c1b88d62f88...
> And because indexing by string is more harder task, including hash calculations if it's using hashtables as implementation
FWIW, Lua uses string interning (https://en.wikipedia.org/wiki/String_interning). The hash calculation for looking up _G["print"] occurred at compile time. _G["print"] should be as quick as indexing an array because the hash calculation is memoized and comparing string equality is equivalent to testing pointer equality. (Indeed, in a simple test both _G["print"] and _G[42] take about 1/10th of a second to iterate 4 million times on my circa 2012 Core i7.)
That said, using lexically bound locals (aka upvalues in Lua parlance) is indeed faster as loading the variable becomes a simple pointer dereference through the [anonymous] function object. A simple test suggests about 25% faster.
FWIW, Lua uses string interning (https://en.wikipedia.org/wiki/String_interning). The hash calculation for looking up _G["print"] occurred at compile time. _G["print"] should be as quick as indexing an array because the hash calculation is memoized and comparing string equality is equivalent to testing pointer equality. (Indeed, in a simple test both _G["print"] and _G[42] take about 1/10th of a second to iterate 4 million times on my circa 2012 Core i7.)
That said, using lexically bound locals (aka upvalues in Lua parlance) is indeed faster as loading the variable becomes a simple pointer dereference through the [anonymous] function object. A simple test suggests about 25% faster.
_G[42] is probably still hitting the hash unless you populated it with 1 to 41.
I was getting some spurious runs where the array access was slower, but didn't think it was worthwhile to mention in the post. Immediately after posting my curiosity got the better of me. After filling in _G[1,2048] the times were consistently the same. The code I was playing with:
local n = 16777216
local _G = _G
for i=1,2048 do
_G[i] = i
end
do
local start = os.clock()
for i=1,n do
local f = _G["print"]
end
print(os.clock() - start)
end
do
local start = os.clock()
for i=1,n do
local f = _G[42]
end
print(os.clock() - start)
endI did something like this back in 2010 with javascript when browsers were much slower at executing code. I was experimenting with manual image scaling and rotation without use of built in canvas functions, mostly to get perfect nearest-neighbour rendering and do extra tricks like perspective transforms which were not really available at the time (just affine transformations were built into the canvas API).
I was struggling to hit 60fps so I devised this hacky system where I'd leave various markers in a "template" function, then parse that using Function.toString() and replace certain areas with unrolled loops, removed if conditions etc. Put the generated function code in a new Function() and used that for the remainder of the animation loop until settings changed.
Actually worked pretty well, along with some other optimizations, was able to hit 60fps in chrome and almost that in FF, depending on the scaling mode of course. At the time my manual implementation of bilinear filtering destroyed the frame rate no matter what, but these days browsers can run it without breaking a sweat. They've come a long way performance wise.
I still have it stashed away on my webserver, so here if anyone is curious. Code is a mess though: http://bigmooworld.com/pwings/pilotwings/pilotwings.html
You might recognize it..
I was struggling to hit 60fps so I devised this hacky system where I'd leave various markers in a "template" function, then parse that using Function.toString() and replace certain areas with unrolled loops, removed if conditions etc. Put the generated function code in a new Function() and used that for the remainder of the animation loop until settings changed.
Actually worked pretty well, along with some other optimizations, was able to hit 60fps in chrome and almost that in FF, depending on the scaling mode of course. At the time my manual implementation of bilinear filtering destroyed the frame rate no matter what, but these days browsers can run it without breaking a sweat. They've come a long way performance wise.
I still have it stashed away on my webserver, so here if anyone is curious. Code is a mess though: http://bigmooworld.com/pwings/pilotwings/pilotwings.html
You might recognize it..
This reminds of the kind of metaprogramming found in languages like www.terralang.org
Wow, now this is deep!
Anyways, I liked the post. I also recommend:
http://lua-users.org/wiki/OptimisationTips
http://lua-users.org/wiki/OptimisationCodingTips
https://www.lua.org/gems/sample.pdf
Oh, and luajit! Mike Pall please come back!