Hi,
I’d like to bring up an issue I’m encountering with threading through task_chains in Panda.
I have an Panda C++ app that is intensively using video, sounds, actor animation, network (UDP) and Bullet physical modelling.
In order to increase substantially the FPS (ie from roughly 8fps to more than 50fps), I’ve been using task_chains.
Digging into some unexpected behaviour in Bullet (ie some lag issue in objects movement,…), I investigated a little bit more the cycle time of each task_chains.
Here is a sketch of the code:
load_prc_file_data("", "lock-to-one-cpu 0"); // unlocks threading possiblity
load_prc_file_data("", "support-threads 1");
// we'll use 3 task chains
// -----------------------
// use task 1 for various house keeping (effects,...)
// set up a new task chain to be used in thread mode for audio & video processing:
task_chain_2 = taskMgr->make_task_chain("task_chain_2");
task_chain_2->set_num_threads(1);
task_chain_2->set_frame_sync(true);
// set up a new task chain to be used for collisions and actor update:
task_chain_3 = taskMgr->make_task_chain("task_chain_3");
task_chain_3->set_num_threads(1);
task_chain_3->set_frame_sync(true);
// assign to do asynchonous tasks and dispatch them among the 3 task chains
// tasks to be performed under task_chain_1
update_clouds_task = new GenericAsyncTask("UpdateClouds", &UpdateClouds, NULL);
taskMgr->add(update_clouds_task);
... + add others tasks
// tasks to be performed under task_chain_2
audio_task = new GenericAsyncTask("AudioUpdate", &AudioTask, (void*) AM);
audio_task->set_task_chain("task_chain_2");
taskMgr->add(audio_task);
... + add others tasks
// tasks to be performed under task_chain_3 (including BULLET processing)
coll_task = new GenericAsyncTask("Collisions_update", &CollisionsUpdate, NULL);
coll_task->set_task_chain("task_chain_3");
taskMgr->add(coll_task);
... + add others tasks
Let’s now try to monitor the ordering and the cycle time of each chain
// add 3 spy task to each task chain (just to check)
AsyncTask::DoneStatus SPY_1(GenericAsyncTask* task, void* data){
double LastTimeExerciced = 0.0L;
double CurrTime = globalClock->get_real_time();
double dt = CurrTime - LastTimeExerciced;
LastTimeExerciced = CurrTime;
std::cout << "## TASK 1 re-exerciced after " << dt << " seconds\n";
return AsyncTask::DS_cont;
}
PT(GenericAsyncTask) spy1_task = new GenericAsyncTask("spy1_ck", &SPY_1, NULL);
taskMgr->add(spy1_task);
PT(GenericAsyncTask) spy2_task = new GenericAsyncTask("spy2_ck", &SPY_2, NULL);
spy1_task->set_task_chain("task_chain_2");
taskMgr->add(spy2_task);
PT(GenericAsyncTask) spy3_task = new GenericAsyncTask("spy3_ck", &SPY_3, NULL);
spy3_task->set_task_chain("task_chain_3");
taskMgr->add(spy3_task);
This gives (notice the ordering of the tasks):
## TASK 1 re-exerciced after 0.00924089 seconds
## TASK 2 re-exerciced after 0.00923157 seconds
## TASK 1 re-exerciced after 0.00816875 seconds
## TASK 2 re-exerciced after 0.00819397 seconds
## TASK 1 re-exerciced after 0.0102592 seconds
## TASK 2 re-exerciced after 0.0102539 seconds
## TASK 2 re-exerciced after 0.00984192 seconds
## TASK 1 re-exerciced after 0.0111123 seconds
## TASK 2 re-exerciced after 0.00886536 seconds
## TASK 1 re-exerciced after 0.0194617 seconds
## TASK 2 re-exerciced after 0.0118713 seconds
## TASK 1 re-exerciced after 0.00945009 seconds
## TASK 2 re-exerciced after 0.00939941 seconds
## TASK 3 re-exerciced after 0.239088 seconds
## TASK 1 re-exerciced after 0.0108739 seconds
## TASK 2 re-exerciced after 0.0109558 seconds
## TASK 1 re-exerciced after 0.0103214 seconds
## TASK 2 re-exerciced after 0.0102692 seconds
Now, not using threading kills the performance in a unacceptable way
So the issues are:
(1) how to insure data coherence between these panda threads?
(2) how to force sync? (maybe based on the slower panda thread?)
(3) overall how to take advantage of Panda threading and use it properly?