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

having problems with flow graph

foxtoxer
Beginner
399 Views
Hello,
I recently converted the main path of my code to use TBB flow graph, previously I was using combinations of parallel_for and serial code. In addition to this my codebase contains longer running tasks in a seperate task_group which are not waited on, they finish when they finish.
Unfortunatly I am seeing a big problem with performance, each call to graph.wait_for_all() is taking much longer than it should.
My first guess is that somehow wait_for_all() is waiting on my long running tasks, this essentially brings my program to a crawl(it is a video game).
Assuming that this is the case, is there any way to make flow graph only work on the tasks I've given it?
Or is there some other explanation for why flow graph causes such horrible slow down?
Is flow graph suited for a real time application?
Thanks
PS. This forum is really bad at formating text, it removes all line spaces :(
0 Kudos
6 Replies
RafSchietekat
Valued Contributor III
398 Views
Flow graph is based on enqueued tasks (not spawned tasks like parallel_for), and perhaps these are now intermingled with the longer-running tasks on a first-come first-served basis. Try to enqueue the latter on a lower-priority basis, using tbb::priority_low. Does that make a difference?
0 Kudos
foxtoxer
Beginner
399 Views
Hi Raf,
I switched my long running tasks to using enque + low priority, like this..
tbb::task::enqueue(*t,tbb::priority_low);
But this does not appear to help, pausing the program shows that the main thread which called graph.wait_for_all() is indeed running a long running task.
Is there anything else I can do with TBB itself to prevent this?
Thanks
0 Kudos
foxtoxer
Beginner
399 Views
I thought I might be able to use affinity to mask out the main thread from running long running tasks, but it seems enque does not work with set_affinity(), as it said asserted with"affinity is ignored for enqueued tasks".
So I tried switching the long running tasks to spawn() + set_affinity(0xFFFE) but this informs me that the mask is out of range, looking at the code it appears that affinity can only be used to set the specific thread, and not as a thread mask.
0 Kudos
RafSchietekat
Valued Contributor III
399 Views
Sorry, it seemed worth trying. If you don't get the right answer soon, I may have another look at it later.
0 Kudos
foxtoxer
Beginner
399 Views
I tried making it so that if the main thread picked up a long running task it would resubmit it and return.. ( i did have to make a slight change to a TBB header so that I could get the thread ID).

auto id =tbb::this_tbb_thread::get_id().yes_i_want_the_id();
if(id== g_MainThreadID)
{
TBB_Job* t = new( tbb::task::allocate_root() ) TBB_Job
tbb::task::enqueue(*t,tbb::priority_low);
}
else
{
_Job();
}
return nullptr;

Since I had to modify a TBB header I'm not sure if this qualifies as a fix, but it does work...
0 Kudos
Alexey-Kukanov
Employee
399 Views
Quoting foxtoxer
...pausing the program shows that the main thread which called graph.wait_for_all() is indeed running a long running task.
Is there anything else I can do with TBB itself to prevent this?

Sorry for quite late reply. Currently, the only way to isolate some tasks from a thread that calls wait_for_all is to start these tasks from a separate application thread.

This problmeaffects not only graph by the way; each TBB algorithms eventually waits for tasks that it starts. Therefore, you better avoid long running tasks with TBB. I believe long-running jobs can almost always besplit into some stages done by different tasks. E.g. if a job contains a serial loop, each iteration of the loop can start as a task; at the end, it will produce (or recycle itselfinto) a task for the next iteration. The only case where a long job cannot be split is long waiting (e.g. for I/O); and waiting is better done with special threads, not with(in) TBB tasks.
0 Kudos
Reply