How is a table slower than an if statement?

from my understanding when using switch() in c it makes an array of jump instructions instead of comparing the values for each case which increases performance
I tried to do the same in luau with this code

code
local value = 0
local functions_table = {
	[1] = function() value  = value + 1 end,
	[2] = function() value = value +2 end,
	[3] = function() value = value +3  end
}
local start = os.clock()
for i = 0,1000000,1 do
	functions_table[math.random(1,3)]()
end
local finish = os.clock()
local time_taken = finish-start
print("first test result = ".. tostring(time_taken))

start = os.clock()
for i = 0,1000000,1 do
	local num = math.random(1,3)
	if num == 1 then
		value = value + 1 
	elseif num ==2 then
		value = value +2 
	elseif num==3 then
		value = value +3

	end
end

finish = os.clock()

time_taken = finish-start

print("second test result = ".. tostring(time_taken))```

and for some reason the result was

 03:53:41.807  first test result = 0.057964300038293004  -  Server - Script:14
 03:53:41.853  second test result = 0.0457230000756681  -  Server - Script:33

This is only true for if statements that don’t have a lot of cases like yours. Computers are really good at if statements. And the lookup table has to do more work than the if statement. For example it has to first perform a lookup operation on the table, and then run the function

(sorry not a super technical explanation, but in practice if you have a table with less than like 50 values it’s always better to make it an if statement if you only care about performance)

1 Like

Just for context, in lower-level languages, switch blocks can be compiled into ‘jump tables’ or ‘computed gotos’ that simply set the instruction pointer to somewhere else, so the only cost is a single lookup and a jump.

In Lua(u), you’re storing a closure in a heap-allocated array that you’re dynamically indexing and calling. Doing all that will end up totaling to being worse than a simple if branch.

Generally, you’d want to use LUTs for calculating precomputed values, not determining what calculations to do on the fly like that. Using buffers with native compilation just for that will also give you nice cache locality that’ll really speed things up (but the library call cost in normal interpreted mode might be worse).

3 Likes

I ran the code and realized you were adding the overhead of the function call on the table lookup part so I implemented the same on the if statement and got flipped results where the lookup was faster

luau performance page explanation:
https://luau.org/performance#optimized-table-iteration

benchmarked results:

code:

local N = 100000

return {
	ParameterGenerator = function()
		local functions_table = table.create(3, function(value) value+=1 end)
		return math.random(1, 3), functions_table
	end,

	Functions = {
		["table lookup"] = function(_, randomNumber, functions_table)			
			local value = 0
			for i = 1, N do
				functions_table[randomNumber](value)
			end
		end,

		["if statement"] = function(_, randomNumber, functions_table)
			local value = 0
			for i = 1, N do
				if randomNumber == 1 then
					functions_table[randomNumber](value)
				elseif randomNumber == 2 then
					functions_table[randomNumber](value)
				elseif randomNumber == 3 then
					functions_table[randomNumber](value)
				end
			end
		end,
	},
}
2 Likes

what is that benchmark tool?
i wanna use it

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.