Reputation: 6152
I'm new to Lua, figuring out how to embed/use it from a C++ program. I have the basic mechanism working but interested in code being executed as fast as possible. So I am loading/compiling lua code (containing multiple functions) that I can use later.
Now suppose I have a lua function called 'add' that I want to call from C++. As far as I can tell, I have to use the lua_getglobal() function which seems to find and push the bytecode for 'add' on to the Lua stack. Can I eliminate the finding part, i.e. can I keep a reference to the bytecode for the function 'add' so that I can simply push it on to the stack when I need to use it? I don't know how efficient lua_getglobal() is when there are thousands of lua functions, nor am I a fan of premature optimization but I am trying to build a hard real-time system (yes, actual physical deadlines, not just fast) and if I have to call 'add' hundreds of thousands of times in a hurry, having to look for the function every time seems like a real waste.
Also, for curiosity, does the actual bytecode get pushed (i.e, copied) on to the stack or just a reference to it? I'm hoping the latter.
Thanks in advance
Upvotes: 1
Views: 1116
Reputation: 473312
lua_getglobal
, at its core, is just doing a table lookup, functionally no different from doing lua_getfield
. Lua tables are hashtables, so lookup is amortized constant time regardless of the number of entries.
That doesn't mean that such fetches are super-fast. But the performance of fetching more-or-less does not depend on how many different items are in the table.
As for being able to store the function somewhere for faster access... no. Well, not reasonably.
Lua values cannot be stored in C code. While you can get numbers or strings from Lua values, you cannot get a Lua function in any meaningful way. You could call lua_topointer
, but there's no way to undo that conversion.
However, what you could do is create a subsidiary lua_State
from the main one. You would then load up its stack with functions. Using a stack index is faster than doing a hash-table lookup. When it comes time to call this function, you would use lua_xmove
to move the function from the subsidiary lua_State
into your main state to be executed.
Of course, doing this makes your code more difficult to read. A simple lua_getglobal(L, "add")
is much more meaningful than lua_pushvalue(Funcs, some_int)/lua_xmove(L, Funcs)
calls. Using the global table also permits you to change that value, causing all accesses to it to produce a new function.
Also, it's not clear how big a lua_State
's stack is allowed to be. So you may not have enough space to make that work.
Lastly, accessing a function does not copy actual memory. But putting a garbage collected object on the stack means that its GC data has to be updated to note that it is being referenced by the stack. So it's not just a pointer copy.
Upvotes: 3
Reputation: 1156
Can I eliminate the finding part, i.e. can I keep a reference to the bytecode for the function 'add' so that I can simply push it on to the stack when I need to use it?
One thing you can try is to use luaL_Ref to create a reference to the function. This reference should be faster to access - seems it uses a number indexed table so it could possibly be faster than a hash table with string keys.
In C, use lua_ref() wherever possible. lua_ref() behaves similarly to a local variable in terms of speed. - Lua, pre v4.0
I tried to do some tests and with 1000000000 iterations of tonumber pushed to stack and the results were that lua_getglobal took 24 seconds, rawgeti with the ref took 12 seconds, 2 stacks and lua_pushvalue + lua_xmove took 11 seconds and using lua_pushvalue with the same state and the actual function being at stack top took 6 seconds. See code here: http://pastebin.com/n8Q0uVx1
http://www.lua.org/manual/5.3/manual.html#luaL_ref http://www.lua.org/manual/5.3/manual.html#luaL_unref
Upvotes: 5