Reputation:
If I put a function in another function to call it in the function that we added inside the function like in the following example:
local function readInputFromUser()
local doSum()
print("Give me a number")
return io.read("n")
end
num1 = doSum()
num2 = doSum()
print("The sum of " num1 .. " and " .. num2 .. " is equaling " num1 + num2)
end
Would it give my program an performance boost compared to calling to a function initiated like the following example:
local doSum()
print("Give me a number")
return io.read("n")
end
local function readInputFromUser()
num1 = doSum()
num2 = doSum()
print("The sum of " num1 .. " and " .. num2 .. " is " num1 + num2)
end
Would it also beneficial to put the doSum() function in the second example as a global function for performence?
Upvotes: 1
Views: 542
Reputation: 1762
When you put a function inside another function the compiled code doesn't create it once and re-use it each time.
Take a look at LuaJIT bytecode of the first code:
This is bytecode of doSum
function:
0001 GGET 0 0 ; "print"
0002 KSTR 1 1 ; "Give me a number"
0003 CALL 0 1 2
0004 GGET 0 2 ; "io"
0005 TGETS 0 0 3 ; "read"
0006 KSTR 1 4 ; "n"
0007 CALLT 0 2
This is the start of readInputFromUser
function:
0001 FNEW 0 0
0002 MOV 1 0
0003 CALL 1 2 1
...
...
...
Take a look at the first instruction:
0001 FNEW 0 0
FNEW
means Create new closure from prototype D and store it in A
.
This instruction will create a new closure each time you run readInputFromUser
(Closure is a function inside a function).
The creation of a closure contains several procedures.
It allocates the space for the new function, adds to GC list, adds upvalues, locals and many more things.
This costs CPU time, also this breaks JIT compilation. (In plain Lua the CPU time for closures is bigger)
Your function doSum
doesn't use any values from readInputFromUser
, so what you can do instead is create doSum
outside readInputFromUser
and use it as upvalue (Upvalue is a local variable outside (and above) the function).
Upvalues cost more that locals, but closure creation costs much more than upvalue, so that's ok to use upvalue here.
You can avoid this upvalue by making doSum
global, but globals cost a little bit more (locals > upvalues > globals > closures
).
Sum: Creating a closure is expensive, if your function doesn't use upvalues, you can create it once outside and re-use.
Btw, you have syntax errors in the last print
and in doSum
definition.
Also, this is approximate benchmark test between first code and the second:
doSum inside readInputFromUser: 0.29265 (Min: 0.27215, Max: 0.35823, Average: 0.29573) second(s) (81816.93%) (818 times slower)
doSum as upvalue: 0.00036 (Min: 0.0003, Max: 0.00108, Average: 0.00042) second(s) (100%)
Upvotes: 1