<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://olddev.minetest.org/index.php?action=history&amp;feed=atom&amp;title=Lua_Optimization_Tips</id>
	<title>Lua Optimization Tips - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://olddev.minetest.org/index.php?action=history&amp;feed=atom&amp;title=Lua_Optimization_Tips"/>
	<link rel="alternate" type="text/html" href="https://olddev.minetest.org/index.php?title=Lua_Optimization_Tips&amp;action=history"/>
	<updated>2026-04-15T14:10:13Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.38.7</generator>
	<entry>
		<id>https://olddev.minetest.org/index.php?title=Lua_Optimization_Tips&amp;diff=99&amp;oldid=prev</id>
		<title>&gt;ROllerozxa at 19:11, 25 January 2023</title>
		<link rel="alternate" type="text/html" href="https://olddev.minetest.org/index.php?title=Lua_Optimization_Tips&amp;diff=99&amp;oldid=prev"/>
		<updated>2023-01-25T19:11:20Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{LuaTips}}&lt;br /&gt;
Remember, every second you spend in Lua is a second that the Server thread, Connection thread, and possibly one or more Emerge threads stay at a complete standstill!  For this reason, intensive mods should designed with speed in mind.&lt;br /&gt;
&lt;br /&gt;
'''Note''': Many of these tips are specific to neither Lua nor Minetest.&lt;br /&gt;
&lt;br /&gt;
= Using Script API =&lt;br /&gt;
=== Profiling ===&lt;br /&gt;
Very simple; no reason not to do so:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
local t1 = minetest.get_us_time()&lt;br /&gt;
--... work here ...&lt;br /&gt;
print(string.format(&amp;quot;elapsed time: %g ms&amp;quot;, (minetest.get_us_time() - t1) / 1000))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* Compare results often to identify bottlenecks before they become harder to find&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Loop ordering ===&lt;br /&gt;
Always use z, y, x ordering unless there's a good reason not to.&lt;br /&gt;
* Keeps cache coherency&lt;br /&gt;
* Opens opportunity to use simple arithmetic to calculate indicies&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
=== Prefer local variables ===&lt;br /&gt;
* Should usually recompute variable contents instead of computing once and storing in a global variable&lt;br /&gt;
* For most minor computations, the benefit of local access outweighs the cost of re-computing their contents.&lt;br /&gt;
* Of course, the code in concern should be profiled instead of blindly following this general rule of thumb.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
=== Use separate variables when possible instead of tables ===&lt;br /&gt;
* Even though putting associated variables inside of tables may keep things more orderly, the cost associated with performing a key lookup on access is high compared to a local variable reference.&lt;br /&gt;
* Some benchmarks have shown the opposite to be true when using LuaJIT, this must be verified.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
=== Avoid having to re-enter the C++ side by calling API when not needed ===&lt;br /&gt;
* Although Lua is quite slow compared to native code, the amount of time spent in switching could be much greater.&lt;br /&gt;
* Again, the developer's discretion and profiling is needed to determine what the best course of action is.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
=== Array index calculation ===&lt;br /&gt;
&amp;quot;Convenience&amp;quot; functions such as VoxelArea:index() are very attractive for simplicity's sake, but should not be used if maximizing speed is desired.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Try to use simple arithmetic like addition and subtraction for calculating array indices.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
To deal with gaps in between multi-dimensional arrays:&lt;br /&gt;
# Keep a 'base' index variable that has the 0th sub-index of the current outer loop's index&lt;br /&gt;
# Add the stride length added to it per iteration of the outer loop&lt;br /&gt;
# Increment a copy of that variable within the inner loop&lt;br /&gt;
# Repeat for each dimension&lt;br /&gt;
This way, costly multiplications in the innermost loop can be eliminated.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Sample of a very fast loop done in this manner:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
local idx_z_base = initial_index_offset&lt;br /&gt;
for z = z0, z1 do&lt;br /&gt;
	local idx_y_base = idx_z_base&lt;br /&gt;
	for y = y0, y1 do&lt;br /&gt;
		local i = idx_y_base&lt;br /&gt;
		for x = x0, x1 do&lt;br /&gt;
			-- ... work here ...&lt;br /&gt;
			i = i + 1&lt;br /&gt;
		end&lt;br /&gt;
		idx_y_base = idx_y_base + y_stride&lt;br /&gt;
	end&lt;br /&gt;
	idx_z_base = idx_z_base + z_stride&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
See also: [[vmanip#Tips_for_handling_indices]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Benchmarking ===&lt;br /&gt;
To test how often some function is executed in a second you can use something with a syntax similar to the one of [[minetest.after]]:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
local TIME = 3&lt;br /&gt;
&lt;br /&gt;
local clock = minetest.get_us_time&lt;br /&gt;
local us = TIME * 1000000&lt;br /&gt;
local function benchmark_function(fct, ...)&lt;br /&gt;
	local start = clock()&lt;br /&gt;
	local fin = start&lt;br /&gt;
	local total = 0&lt;br /&gt;
	while fin - start &amp;lt; us do&lt;br /&gt;
		fct(...)&lt;br /&gt;
&lt;br /&gt;
		total = total + 1&lt;br /&gt;
		fin = clock()&lt;br /&gt;
	end&lt;br /&gt;
	return total * 1000000 / (fin - start)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;hello got printed &amp;quot; .. benchmark_function(print, &amp;quot;hello&amp;quot;) .. &amp;quot; times a second&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
--[[ result:&lt;br /&gt;
[…]&lt;br /&gt;
hello&lt;br /&gt;
hello&lt;br /&gt;
hello&lt;br /&gt;
hello got printed 65592.333333333 times a second&lt;br /&gt;
]]&amp;lt;/source&amp;gt;&lt;br /&gt;
you could also use &amp;lt;code&amp;gt;os.clock&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;minetest.get_us_time&amp;lt;/code&amp;gt; (of course you then also need to remove that multiplying with 10⁶)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Writing Script API =&lt;br /&gt;
=== When working with arrays, use lua_rawgeti()/lua_rawseti() ===&lt;br /&gt;
* These work on plain integer indexes rather than field names and perform faster.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
=== Prefer lua_newtable() to lua_createtable() ===&lt;br /&gt;
It has been observed that lua_newtable() is generally faster than lua_createtable() by a rather wide margin.&lt;br /&gt;
* This might seem counterintuitive, as lua_createtable() preallocates a known amount of memory in bulk to save steps, but it has a very negative effect on the cache for situations where the performance improvement would have otherwise made a difference.&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua]]&lt;/div&gt;</summary>
		<author><name>&gt;ROllerozxa</name></author>
	</entry>
</feed>