Optera wrote:According to
this Code: Select all
local jobCount, report = ret[0], ret[1]
should be several times faster than using unpack
Well, your statement made me curious, about if all those performance tests would hold the same result inside Factorio's customized Lua interpreter. So I've made a test harness and
time profiled them inside a real mod.
This is the harness (Sorry, it's quite long):
Code: Select all
require "LOGGER"
----------------------
-- TEST 1: Localize --
----------------------
local min = math.min
local function localMin()
local a = min(1, 10)
end
local function mathMin()
local a = math.min(1, 10)
end
-------------------------------------
-- TEST 2: Localized Class-Methods --
-------------------------------------
local class = {}
function class.test()
return 10
end
local function localTest()
local test = class.test
local x = test()
local y = test()
local z = test()
end
local function classTest()
local x = class.test()
local y = class.test()
local z = class.test()
end
----------------------------
-- TEST 3: Unpack a Table --
----------------------------
local a = {10, 20, 30, 40}
local function directIndex()
local x = min(a[1], a[2], a[3], a[4])
end
local myUnpack = unpack
local function localUnpack()
local x = min(myUnpack(a))
end
local function nativeUnpack()
local x = min(unpack(a))
end
local function unpack4(a)
return a[1], a[2], a[3], a[4]
end
local function rewrittenUnpack()
local x = min(unpack4(a))
end
-------------------------------
-- TEST 4: Determine Maximun --
-------------------------------
local max = math.max
local random = math.random
local x = 0
local function useMax()
x = max(random(), x)
end
local function useIf()
local r = random()
if r > x then x = r end
end
------------------------
-- TEST 5: Nil Checks --
------------------------
local function nilIf()
local y,x
if (random()>0.5) then y=1 end
if (y==nil) then x=1 else x=y end
end
local function nilOr()
local y,x
if (random()>0.5) then y=1 end
x = y or 1
end
----------------------------
-- TEST 6: Exponentiation --
----------------------------
local function exp(v)
local x = v^2
end
local function mult(v)
local x = v*v
end
-------------------------------
-- TEST 7: Modulus - skipped --
-------------------------------
---------------------------------
-- TEST 8: Function parameters --
--------------------------------
local func1 = function(a,b,func)
return func(a+b)
end
local function inline()
local x = func1(1,2,function(a) return a*2 end)
end
local func2 = function(a)
return a*2
end
local function extracted()
local x = func1(1,2,func2)
end
---------------------------------
-- TEST 9: For loops - skipped --
---------------------------------
-------------------------------------------
-- TEST 10: table["name"] vs. table.name --
-------------------------------------------
local function useArray()
local x = global["dummy"]
end
local function useMethod()
local x = global.dummy
end
------------------------------------
-- TEST 11: Buffered Table Access --
------------------------------------
local function nonBuffered()
for n=1,100 do
global.a[n].x = global.a[n].x + 1
end
end
local function buffered()
for n=1,100 do
local y = global.a[n]
y.x = y.x + 1
end
end
-----------------------------------------
-- TEST 12: Table Population - Skipped --
-----------------------------------------
-----------------------------
-- TEST 13: Table Creation --
-----------------------------
local function createDirect()
local a = {1, 2, 3}
end
local function createNonAlloc()
local a = {}
a[1] = 1
a[2] = 2
a[3] = 3
end
local function createAlloc()
local a = {true, true, true}
a[1] = 1
a[2] = 2
a[3] = 3
end
----------
-- Work --
----------
local function doAssorted(f, limit, message)
for tick = 1, limit do
f(tick)
end
LOGGER.log(message)
end
local function setGlobals(v)
global.dummy = 0
global.a = {}
for n = 1, 100 do
global.a[n] = {x = n}
end
end
local function nilGlobals()
global.dummy = nil
end
function runAssorted()
for _, v in ipairs({100, 10000, 100000}) do
LOGGER.log("Testing for v=" .. v)
setGlobals(v)
doAssorted(localMin, v, "Local Min")
doAssorted(mathMin, v, "Math Min")
doAssorted(localTest, v, "Local Test")
doAssorted(classTest, v, "Class Test")
doAssorted(directIndex, v, "Direct Index")
doAssorted(localUnpack, v, "Local Unpack")
doAssorted(nativeUnpack, v, "Native Unpack")
doAssorted(rewrittenUnpack, v, "Rewritten Unpack")
doAssorted(useMax, v, "Find Maximun with max")
doAssorted(useIf, v, "Find Maximun with if")
doAssorted(nilIf, v, "Nil if")
doAssorted(nilOr, v, "Nil or")
doAssorted(exp, v, "Exponentiation")
doAssorted(mult, v, "Multiplication")
doAssorted(inline, v, "Inline function parameters")
doAssorted(extracted, v, "Localized function parameters")
doAssorted(useArray, v, "Array Access")
doAssorted(useMethod, v, "Method Access")
doAssorted(buffered, v, "Buffered Access")
doAssorted(nonBuffered, v, "Non Buffered Access")
doAssorted(createDirect, v, "Direct Table Creation")
doAssorted(createAlloc, v, "Pre Allocated Table Creation")
doAssorted(createNonAlloc, v, "Non Pre Allocated Table Creation")
end
nilGlobals()
end
local done
local function onTick(event)
if not done then
runAssorted()
end
end
script.on_event(defines.events.on_tick, onTick)
These are the results, for v=100k (the lesser values hold the same relation):
Code: Select all
00007.207: 102:43:33.28: Local Min
00011.906: 102:43:33.28: Math Min
00016.782: 102:43:33.28: Local Test
00017.506: 102:43:33.28: Class Test
00014.686: 102:43:33.28: Direct Index
00016.787: 102:43:33.28: Local Unpack
00014.928: 102:43:33.28: Native Unpack
00022.710: 102:43:33.28: Rewritten Unpack
00015.227: 102:43:33.28: Find Maximun with max
00008.113: 102:43:33.28: Find Maximun with if
00009.640: 102:43:33.28: Nil if
00008.982: 102:43:33.28: Nil or
00005.543: 102:43:33.28: Exponentiation
00004.153: 102:43:33.28: Multiplication
00012.036: 102:43:33.28: Inline function parameters
00011.767: 102:43:33.28: Localized function parameters
00008.703: 102:43:33.28: Array Access
00008.734: 102:43:33.28: Method Access
00832.507: 102:43:33.28: Buffered Access
01372.638: 102:43:33.28: Non Buffered Access
00027.763: 102:43:33.28: Direct Table Creation
00031.491: 102:43:33.28: Pre Allocated Table Creation
00059.412: 102:43:33.28: Non Pre Allocated Table Creation
Specifically as to your statement, using native unpack will perform almost exactly the same as using "local jobCount, report = ret[0], ret[1]", while being more readable and maintainable.
Results related to the tests I've skipped here can be found on these threads:
viewtopic.php?f=25&t=39500
viewtopic.php?f=25&t=39025