Intel® oneAPI Threading Building Blocks
Ask questions and share information about adding parallelism to your applications when using this threading library.

Using TBB with embedded scripting languages

FredP
Beginner
479 Views
Hello there!

I'm using TBB in a simulator, and have a task graph set up nicely to process the updates.
What I'm now trying to do s allow some user customisation of the behaviour in some of the components, which will influence exactly how the update works. To do this, I was looking at Lua (www.lua.org) to allow scripts to be injected.
For me, this poses a few questions, because I'll have an unknown number of objects within the task graph trying to run Luascriptsat unknown times. From a programming perspective, the simplest solution would be to launch a new Lua interpreter/state in each task where it is necessary, run the update and then move on.
However, I'm a bit concerned at 200K a pop that this would mean using a lot of memory and might also not be a good use of processor time, endlessly recreating and destroying interpreters. I could hold an interpreter permanently for each object to reduce the processing time, but there would still be a big memory overhead.
Or I could try a central repository of lua interpreters/states to grab from, but then I'm worried I'll lose performance from excessive locking.
So I wondered if anyone had any thoughts as to the best way to approach this problem, so that I can make the best use of TBB without killing my system. It's not that I don't think my solutions will work, it's just that I'm worried about that I'll end up undoing a lot of the benefit I'm getting from TBB in doing it...
Thanks in advance.

Fred
0 Kudos
7 Replies
RafSchietekat
Valued Contributor III
479 Views
Cache them in thread-local storage.
0 Kudos
jimdempseyatthecove
Honored Contributor III
479 Views
Fred,

To expand on Raf's suggestion...

>>From a programming perspective, the simplest solution would be to launch a new Lua interpreter/state in each task where it is necessary, run the update and then move on

Assuming a single application can launch multiple Lua interpreters (e.g. application receives a handle or pointer to interpreter context .AND. multiple instances of interpreter within same application are thread safe). Then declare a thread local storage variable(s) to hold the interpreter handle/pointer and potential pointer to context (entries initialized to NULL). Then when any TBB task is about to call the Lua interpreter, the thread executing the TBB taskchecks its thread private Lua context variable(s) and if NULL it inits a new Lua context (and updates the thread private variables for the new Lua context for use on subsequent calls). Upon return from the Lua call, the TBB thread (thread executing Task making the Lua call) keeps the Lua context for subsequent calls.

Using this technique, you will create at most one Lua context per software thread, typically one thread per logical processor, rather than one context per object.

The only drawback is if your application shuts down TBB, that these Lua contexts will not automatically be shut down. i.e. applications that loop:(TBB init, run TBB tasks, TBB exit) would exhibit the creation of unnecessary Lua context. A typical application will not be constructed that way. If your app loops in this unusual way, then you will have to add code to resolve this issue.

>>Or I could try a central repository of lua interpreters/states to grab from, but then I'm worried I'll lose performance from excessive locking

The thread local storage of lua context is your "central repository". The overhead is

__declspec(thread) Lua_context_t* myLuaContext = NULL;
...
void YourTaskCallingLua()
{
if(!myLuaContext)
Init_myLuaContext();
...
myLuaContext->interptrt(LuaScript, args);
...
}

(not having Lua here, you will have to rework the Lua_context_t and init function)

Jim Dempsey
0 Kudos
RafSchietekat
Valued Contributor III
479 Views
"The only drawback is if your application shuts down TBB, that these Lua contexts will not automatically be shut down. i.e. applications that loop:(TBB init, run TBB tasks, TBB exit) would exhibit the creation of unnecessary Lua context."
Use TBB's TLS classes for easy control of their lifetimes?
0 Kudos
Alexey-Kukanov
Employee
479 Views
Alternatively you can cache the interpreter objects in concurrent_queue. When you need an interpreter, try_pop() from the queue. If unsuccessful, create one. When done with the interpreter, push() to the queue. Negative sides (comparing to TLS) are: somewhat bigger overhead to get an interpreter, and possibly more cache misses (since interpreters are shared by threads). Positive sides are simpler lifetime management (the app can destroy all interpreters when they become unnecessary), and not using TLS keys (can be important if the app needs a lot of those).
0 Kudos
jimdempseyatthecove
Honored Contributor III
479 Views
Alexey,

Use the concurrent_queue to contain the list of interpreters to shut down. And use TLS pointer/context for thread rememberance. IOW sketch code:

void SomeTask()
{
if(!p_InterpInTLS)
{
p_InterpInTLS = GetNewInterpreterContext();
DeleteMeLater.pushback(p_InterpInTLS);
}
p_InterpInTLS->DoWork(arg);
}

Where the concurrent_queue (DeleteMeLater) is queried upon exit from the TBB session.

Jim
0 Kudos
FredP
Beginner
479 Views
Thank you for this and for all responses. I think Lua uses a single interpreter to process functions, but you can hold as many lua_State variables as you like to describe the current state of the variable. Presumably what I'll need to do is follow some of these ideas, but make sure I return the lua_State to some default state before releasing it back to the store?
Fred
0 Kudos
jimdempseyatthecove
Honored Contributor III
479 Views
Quoting FredP
Thank you for this and for all responses. I think Lua uses a single interpreter to process functions, but you can hold as many lua_State variables as you like to describe the current state of the variable. Presumably what I'll need to do is follow some of these ideas, but make sure I return the lua_State to some default state before releasing it back to the store?
Fred



You will have to assure that the single Lua can run concurrent contexts (i.e. frommultiple threads concurrently within the same process/application). The disscussion to date was from your assertion that it could.

If not, then you will have to serialize the Lua calls. (or run from seperate thread from TBB pool).

There is a distinct difference between saving/restoring different context states and passing what ammounts to be a context pointer to the state. The former will not permit concurrent access, the latter will.

Jim Dempsey
0 Kudos
Reply