// Called from AIStateMachine::mainloop, but put here because we don't want to include llurlrequest.h there of course.
void print_statemachine_diagnostics(U64 total_clocks, U64 max_delta, AIEngine::queued_type::const_reference slowest_element)
{
  AIStateMachine const& slowest_state_machine = slowest_element.statemachine();
  LLURLRequest const* request = dynamic_cast<LLURLRequest const*>(&slowest_state_machine);
  F64 const tfactor = 1000 / calc_clock_frequency();
  std::ostringstream msg;
  if (total_clocks > max_delta)
  {
	  msg << "AIStateMachine::mainloop did run for " << (total_clocks * tfactor) << " ms. The slowest ";
  }
  else
  {
	  msg << "AIStateMachine::mainloop: A ";
  }
  msg << "state machine ";
  if (request)
  {
	  msg << "(" << request->getResponderName() << ") ";
  }
  msg << "ran for " << (max_delta * tfactor) << " ms";
  if (slowest_state_machine.getRuntime() > max_delta)
  {
	  msg << " (" << (slowest_state_machine.getRuntime() * tfactor) << " ms in total now)";
  }
  msg << ".";
  llwarns << msg.str() << llendl;
}
Пример #2
0
// Called from AIStateMachine::mainloop
void print_statemachine_diagnostics(U64 total_clocks, AIStateMachine::StateTimerBase::TimeData& slowest_timer, AIEngine::queued_type::const_reference slowest_element)
{
	AIStateMachine const& slowest_state_machine = slowest_element.statemachine();
	F64 const tfactor = 1000 / calc_clock_frequency();
	std::ostringstream msg;

	U64 max_delta = slowest_timer.GetDuration();

	if (total_clocks > max_delta)
	{
		msg << "AIStateMachine::mainloop did run for " << (total_clocks * tfactor) << " ms. The slowest ";
	}
	else
	{
		msg << "AIStateMachine::mainloop: A ";
	}
	msg << "state machine " << "(" << slowest_state_machine.getName() << ") " << "ran for " << (max_delta * tfactor) << " ms";
	if (slowest_state_machine.getRuntime() > max_delta)
	{
		msg << " (" << (slowest_state_machine.getRuntime() * tfactor) << " ms in total now)";
	}
	msg << ".\n";

	AIStateMachine::StateTimerBase::DumpTimers(msg);

	llwarns << msg.str() << llendl;
}
Пример #3
0
void AIStateMachine::yield_ms(unsigned int ms)
{
  DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::yield_ms(" << ms << ") [" << (void*)this << "]");
  mSleep = get_clock_count() + calc_clock_frequency() * ms / 1000;
  // Sleeping is always done from the main thread.
  yield(&gMainThreadEngine);
}
Пример #4
0
void AIStateMachine::StateTimer::TimeData::DumpTimer(std::ostringstream& msg, std::string prefix)
{
	F64 const tfactor = 1000 / calc_clock_frequency();
	msg << prefix << mName << " " << (mEnd - mStart)*tfactor << "ms" << std::endl;
	prefix.push_back(' ');
	std::vector<TimeData>::iterator it;
	for (it = mChildren.begin(); it != mChildren.end(); ++it)
	{
		it->DumpTimer(msg, prefix);
	}
}
// static
void AIStateMachine::setMaxCount(F32 StateMachineMaxTime)
{
  llassert(is_main_thread());
  Dout(dc::statemachine, "(Re)calculating AIStateMachine::sMaxCount");
  sMaxCount = calc_clock_frequency() * StateMachineMaxTime / 1000;
}
// static
void AIStateMachine::dowork(void)
{
  llassert(!active_statemachines.empty());
  // Run one or more state machines.
  U64 total_clocks = 0;
  for (active_statemachines_type::iterator iter = active_statemachines.begin(); iter != active_statemachines.end(); ++iter)
  {
	AIStateMachine& statemachine(iter->statemachine());
	if (!statemachine.mIdle)
	{
	  U64 start = get_clock_count();
	  // This might call idle() and then pass the statemachine to another thread who then may call cont().
	  // Hence, after this isn't not sure what mIdle is, and it can change from true to false at any moment,
	  // if it is true after this function returns.
	  statemachine.multiplex(start);
	  U64 delta = get_clock_count() - start;
	  iter->add(delta);
	  total_clocks += delta;
	  if (total_clocks >= sMaxCount)
	  {
#ifndef LL_RELEASE_FOR_DOWNLOAD
		llwarns << "AIStateMachine::mainloop did run for " << (total_clocks * 1000 / calc_clock_frequency()) << " ms." << llendl;
#endif
		std::sort(active_statemachines.begin(), active_statemachines.end(), QueueElementComp());
		break;
	  }
	}
  }
  // Remove idle state machines from the loop.
  active_statemachines_type::iterator iter = active_statemachines.begin();
  while (iter != active_statemachines.end())
  {
	AIStateMachine& statemachine(iter->statemachine());
	// Atomic test mIdle and change mActive.
	bool locked = statemachine.mIdleActive.tryLock();
	// If the lock failed, then another thread is in the middle of calling cont(),
	// thus mIdle will end up false. So, there is no reason to block here; just
	// treat mIdle as false already.
	if (locked && statemachine.mIdle)
	{
	  // Without the lock, it would be possible that another thread called cont() right here,
	  // changing mIdle to false again but NOT adding the statemachine to continued_statemachines,
	  // thinking it is in active_statemachines (and it is), while immediately below it is
	  // erased from active_statemachines.
	  statemachine.mActive = as_idle;
	  // Now, calling cont() is ok -- as that will cause the statemachine to be added to
	  // continued_statemachines, so it's fine in that case-- even necessary-- to remove it from
	  // active_statemachines regardless, and we can release the lock here.
	  statemachine.mIdleActive.unlock();
	  Dout(dc::statemachine, "Erasing " << (void*)&statemachine << " from active_statemachines");
	  iter = active_statemachines.erase(iter);
	  if (statemachine.mState == bs_killed)
	  {
	  	Dout(dc::statemachine, "Deleting " << (void*)&statemachine);
		delete &statemachine;
	  }
	}
	else
	{
	  if (locked)
	  {
		statemachine.mIdleActive.unlock();
	  }
	  llassert(statemachine.mActive == as_active);	// It should not be possible that another thread called cont() and changed this when we are we are not idle.
	  llassert(statemachine.mState == bs_run || statemachine.mState == bs_initialize);
	  ++iter;
	}
  }
  if (active_statemachines.empty())
  {
	// If this was the last state machine, remove mainloop from the IdleCallbacks.
	AIReadAccess<csme_type> csme_r(sContinuedStateMachinesAndMainloopEnabled, true);
	if (csme_r->continued_statemachines.empty() && csme_r->mainloop_enabled)
	{
	  Dout(dc::statemachine, "Deactivating AIStateMachine::mainloop: no active state machines left.");
	  AIWriteAccess<csme_type>(csme_r)->mainloop_enabled = false;
	}
  }
}