My app is comprised of two threads:
- GUI Thread (using Qt)
- Simulation Thread
My reason for using two threads is to keep the GUI responsive, while letting the Sim thread spin as fast as possible.
In my GUI thread I'm rendering the entities in the sim at an FPS of 30-60; however, I want my sim to "crunch ahead" - so to speak - and queue up game state to be drawn eventually (think streaming video, you've got a buffer).
Now for each frame of the sim I render I need the corresponding simulation "State". So my sim thread looks something like:
while(1) {
simulation.update();
SimState* s = new SimState;
simulation.getAgents( s->agents ); // store agents
// store other things to SimState here..
stateStore.enqueue(s); // stateStore is a QQueue<SimState*>
if( /* some threshold reached */ )
// push stateStore
}
SimState
looks like:
struct SimState {
std::vector<Agent> agents;
//other stuff here
};
And Simulation::getAgents looks like:
void Simulation::getAgents(std::vector<Agent> &a) const
{
// mAgents is a std::vector<Agent>
std::vector<Agent> a_tmp(mAgents);
a.swap(a_tmp);
}
The Agent
s themselves are somewhat complex classes. The members are a bunch of int
s and float
s and two std::vector<float>
s.
With this current setup the sim can't crunch must faster than the GUI thread is drawing. I've verified that the current bottleneck is simulation.getAgents( s->agents )
, because even if I leave out the push the updates-per-second are slow. If I comment out that line I see several orders of magnitude improvement in updates/second.
So, what sorts of containers should I be using to store the simulation's state? I know there is a bunch of copying going on atm, but some of it is unavoidable. Should I store Agent*
in the vector instead of Agent
?
Note: In reality the simulation isn't in a loop, but uses Qt's QMetaObject::invokeMethod(this, "doSimUpdate", Qt::QueuedConnection);
so I can use signals/slots to communicate between the threads; however, I've verified a simpler version using while(1){}
and the issue persists.