First... Please don't take anything I say personally. I have the utmost respect for all of you and if I mention a piece of code you wrote or worked on it is not meant as a personal attack.
sfan5 wrote:These micro-optimizations won't make any noticable different in mod speed.
Additionally most people run Minetest compiled with LuaJIT which these tips most likely do not apply to.
Not necessarily, it depends on where they are being used. For instance, if you are just iterating through a table once before the game actually starts (registering nodes and such) or something that is only done every once in a while then, by all means, use the convenient way of doing it, that is what it is there for. But, if you are inside an on_generated, on_step, abm, lbm or a timer function then small speed tweaks can add up quick. On my system it takes between 30 and 40ms to receive and send VoxelManip data. Every millisecond I can shave off the rest of the code counts and it can be very noticeable especially in a complex on_generated function. I see the effect quite obviously when using my customized TNT mod (unreleased because it is totally incompatible with MineTest_Game), it is smoother and much more responsive compare to the default TNT mod (on my systems). It also uses only one global to function properly, but contain three others for use in other mods, and has more features.
duane wrote:I'd be more concerned about optimizing for luajit's tiny memory capacity.
This is key when dealing with LuaJIT!
Vanilla Lua is slow compared to LuaJIT. For Lua you want to optimize for CPU usage at the expense of memory because there is no memory limit. LuaJIT is fast already, for the most part, so optimizing for memory at the expense of CPU time is key because it has the darned memory limit. Working around using ipairs/pairs helps in both situations because both are relatively slow (compared to manual iteration) and also carry a memory overhead.
A simple fact is globals are very slow compared to locals. Globals are also not handled by the GarbageCollector. Any global function, table, var, object, etc stay in memory even if it will never be used again. Take for instance all the mods that have a global register_something() function. Nobody ever frees that function even though it will never be used in the game past an after(0). This is something that many Lua programmers forget about because they are used to Lua handling the memory for them unlike other languages that require you to remember to free your objects. Lua only manages LOCAL objects, the GarbageCollector does nothing with globals.
Reuse you local objects. Do this...
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- Code: Select all
local somevar
for i = 1,100 do
somevar = something
end
...instead of...
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- Code: Select all
for i = 1,100 do
local somevar = something
end
This will save the time needed to recreate the variable and helps to manage the amount of objects the GarbageCollector has to track. The more things the GC has to track the slower it becomes.
Faster still is using the FFI and CDEF to move large persistent objects outside the LuaJIT memory limit. In my experimentation, this is not helpful inside an on_generated or similar function that gets run many times per second. I have successfully moved VoxelManip data outside of the memory limit with relative ease but because of the nature of the GC and the memory required to call the functions to get the data it makes no difference. But it can be very useful for storing large tables of persistent data.
As far as localizing math.*() functions... Just about any seasoned Lua programmer will tell you to localize your math functions because it does make a difference. But again, it depends on how it is being used. If you only use it once in a while then why bother, save the memory and object count the GC has to deal with. But, if it is being called many times inside of a function that is getting called many times per second the savings can add up quickly.
There is undoubtedly more but within the above is a good start for mod devs to start managing memory better. If you want to see the code that moves the VM data outside the JIT memory limit just ask.