Conflicts:
	indra/llcommon/llfasttimer_class.cpp
	indra/llcommon/llfasttimer_class.h
This commit is contained in:
Shyotl
2012-02-05 05:57:44 -06:00
5 changed files with 224 additions and 106 deletions

View File

@@ -23,6 +23,125 @@
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
//
// LLFastTimer documentation, written by Aleric (Feb 2012).
//
// Disclaimer: this is horrible code and I distantiate myself from it's design.
// It's neither robust nor object oriented. I just document what I find, in
// order to be able to fix the bugs (that logically result from such a design).
//
// Note that the choosen names of the variables are non-intuitive and make
// understanding the code harder. However, I didn't change them in order to
// make merging less of a nightmare in the future -- Aleric.
//
//
// First of all, absolutely nothing in this code is even remotely thread-safe:
// FastTimers should only be used from the main thread and never from another
// thread.
//
// NamedTimerFactory is a singleton, accessed through NamedTimerFactory::instance().
//
// It has four pointer members which are initialized once to point to
// four objects with a life-time equal to the application/singleton:
//
// mTimerRoot --> NamedTimer("root")
// mActiveTimerRoot --> NamedTimer("Frame")
// mRootFrameState --> FrameState(mActiveTimerRoot)
// mAppTimer --> LLFastTimer(mRootFrameState)
//
// A NamedTimer has a name and a life-time of approximately that of the application.
// There is exactly one instance per unique name.
// NamedTimer's are ordered in a hierarchy with each one parent and zero or more
// children (the "root" has parent NULL).
// The parent of mActiveTimerRoot is mTimerRoot, which has one child: mActiveTimerRoot.
// NamedTimer::getDepth() returns the number of parents; mTimerRoot has a depth of 0,
// mActiveTimerRoot has a depth of 1 and so on. NamedTimer::getRootNamedTimer() just
// returns mActiveTimerRoot.
//
// Each NamedTimer is linked to exactly one FrameState object, namely
// LLFastTimer::getFrameStateList()[named_timer.getFrameStateIndex()], where
// getFrameStateList() is a static function returning a global std::vector<FrameState>.
// This vector is ordered "Depth First" (the FrameState objects (belonging to
// NamedTimer objects) with smallest depth first). The vector is resorted a few
// times in the beginning (and indexes in FrameState updated) since timers are added
// whenever they are first used, not in "Depth First" order, but stabilizes after a
// while. This implies that FrameState pointers can't really be used: FrameState
// objects move around in memory whenever something is inserted or removed from the
// std::vector and/or when the vector is resorted. However, FrameState pointers ARE
// being used and code exists that tries to update those pointers in the above
// mentioned cases (this part had bugs, which I now fixed).
//
// FrameState objects point back to their corresponding NamedTimer through mTimer.
// They have also parents: the FrameState object corresponding to the parent of mTimer.
//
// Thus, so far we have (assuming "namedtimerX" was created first):
//
// NamedTimer's: FrameState's:
//
// NULL
// ^
// |
// depth=0: "root" (mTimerRoot) <-------> getFrameStateList()[0]
// ^ ^
// | (parent) | (parent)
// | |
// depth=1: "Frame" (mActiveTimerRoot) <-------> mRootFrameState
// ^ ^ ^ ^
// | | | |
// | (parent) | (parent) | (parent) | (parent)
// | | | |
// depth=2: "namedtimerX" | <-------> getFrameStateList()[2] |
// "namedtimerY" <-------> getFrameStateList()[3]
//
// where the NamedTimer's point to the corresponding FrameState's by means of
// NamedTimer::mFrameStateIndex, and the FrameState's point back through FrameState::mTimer.
//
// Note the missing getFrameStateList()[1], which is ignored and replaced by
// a specific call to 'new FrameState' in initSingleton(). The reason for that is
// probably because otherwise mRootFrameState has to be updated every time the
// frame state list vector is moved in memory. This special case adds some complexity to,
// for instance, getFrameState() which now needs to test if the caller is mActiveTimerRoot.
//
// DeclareTimer objects are NameTimer/FrameState pointer pairs with again a lifetime
// of approximately that of the application. The are usually static, even global,
// and are passed an name as string; the name is looked up and added if not already
// existing, or else the previously created pair is returned. Obviously, "root" and
// "Frame" are the only ones that don't have a corresponding DeclareTimer object.
//
// LLFastTimer objects are short lived objects, created in a scope and destroyed
// at the end in order to measure the time that the application spent in that
// scope. They are passed DeclareTimer objects to know which timer to append to.
// LLFastTimer::mFrameState is a pointer to the corresponding timer.
// The static LLFastTimer::sCurTimerData is a CurTimerData struct that has
// a duplicate of that pointer as well as a pointer to the corresponding NamedTimer,
// of the last LLFastTimer object that was created (and not destroyed again);
// in other words: the running timer with the largest depth.
// When a new LLFastTimer object is created while one is already running,
// then this sCurTimerData is saved in the already running one (as
// LLFastTimer::mLastTimerData) and restored upon destruction of that child timer.
//
// The following FrameState pointers are being used:
//
// FrameState::mParent
// DeclareTimer::mFrameState
// CurTimerData::mFrameState
// LLFastTimer::mFrameState
//
// All of those can be invalidated whenever something is added to the std::vector<FrameState>,
// and when that vector is sorted.
//
// Adding new FrameState objects is done in NamedTimer(std::string const& name), called from
// createNamedTimer(), called whenever a DeclareTimer is constructed. At the end of the
// DeclareTimer constructor update_cached_pointers_if_changed() is called, which calls
// updateCachedPointers() if the std::vector moved in memory since last time it was called.
//
// Sorting is done in NamedTimer::resetFrame(), which theoretically can be called from
// anywhere. Also here updateCachedPointers() is called, directly after sorting the vector.
//
// I fixed updateCachedPointers() to correct all of the above pointers and removed
// another FrameState pointer that was unnecessary.
#include "linden_common.h"
#include "llfasttimer.h"
@@ -57,20 +176,14 @@ S32 LLFastTimer::sLastFrameIndex = -1;
U64 LLFastTimer::sLastFrameTime = LLFastTimer::getCPUClockCount64();
bool LLFastTimer::sPauseHistory = 0;
bool LLFastTimer::sResetHistory = 0;
LLFastTimer::CurTimerData LLFastTimer::sCurTimerData;
BOOL LLFastTimer::sLog = FALSE;
std::string LLFastTimer::sLogName = "";
BOOL LLFastTimer::sMetricLog = FALSE;
LLMutex* LLFastTimer::sLogLock = NULL;
std::queue<LLSD> LLFastTimer::sLogQueue;
#define USE_RDTSC 0
#if LL_LINUX || LL_SOLARIS
U64 LLFastTimer::sClockResolution = 1000000000; // Nanosecond resolution
#else
U64 LLFastTimer::sClockResolution = 1000000; // Microsecond resolution
#endif
std::vector<LLFastTimer::FrameState>* LLFastTimer::sTimerInfos = NULL;
U64 LLFastTimer::sTimerCycles = 0;
U32 LLFastTimer::sTimerCalls = 0;
@@ -132,10 +245,11 @@ public:
// so we have to work around that by using a specialized implementation
// for the special case were mTimerRoot != mActiveTimerRoot -- Aleric
mRootFrameState->mParent = &LLFastTimer::getFrameStateList()[0]; // &mTimerRoot->getFrameState()
mRootFrameState->mParent->mActiveCount = 1;
// And the following four lines are mActiveTimerRoot->setParent(mTimerRoot);
llassert(!mActiveTimerRoot->mParent);
mActiveTimerRoot->mParent = mTimerRoot; // mParent = parent;
mRootFrameState->mParent = mRootFrameState->mParent; // getFrameState().mParent = &parent->getFrameState();
//mRootFrameState->mParent = mRootFrameState->mParent; // getFrameState().mParent = &parent->getFrameState();
mTimerRoot->getChildren().push_back(mActiveTimerRoot); // parent->getChildren().push_back(this);
mTimerRoot->mNeedsSorting = true; // parent->mNeedsSorting = true;
@@ -193,7 +307,7 @@ private:
LLFastTimer::NamedTimer* mActiveTimerRoot;
LLFastTimer::NamedTimer* mTimerRoot;
LLFastTimer* mAppTimer;
LLFastTimer::FrameState* mRootFrameState;
LLFastTimer::FrameState* mRootFrameState; // Points to memory allocated with new, so this pointer is not invalidated.
};
void update_cached_pointers_if_changed()
@@ -202,9 +316,9 @@ void update_cached_pointers_if_changed()
static LLFastTimer::FrameState* sFirstTimerAddress = NULL;
if (&*(LLFastTimer::getFrameStateList().begin()) != sFirstTimerAddress)
{
LLFastTimer::DeclareTimer::updateCachedPointers();
LLFastTimer::updateCachedPointers();
sFirstTimerAddress = &*(LLFastTimer::getFrameStateList().begin());
}
sFirstTimerAddress = &*(LLFastTimer::getFrameStateList().begin());
}
LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name, bool open )
@@ -223,54 +337,69 @@ LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name)
}
// static
void LLFastTimer::DeclareTimer::updateCachedPointers()
void LLFastTimer::updateCachedPointers()
{
// propagate frame state pointers to timer declarations
for (instance_iter it = beginInstances(); it != endInstances(); ++it)
// Update DeclareTimer::mFrameState pointers.
for (DeclareTimer::instance_iter it = DeclareTimer::beginInstances(); it != DeclareTimer::endInstances(); ++it)
{
// update cached pointer
it->mFrameState = &it->mTimer.getFrameState();
}
// also update frame states of timers on stack
static LLFastTimer::CurTimerData& static_cur_data = LLFastTimer::CurTimerData::get();
LLFastTimer* cur_timerp = static_cur_data.mCurTimer;
while(cur_timerp->mLastTimerData.mCurTimer != cur_timerp)
// Update CurTimerData::mFrameState and LLFastTimer::mFrameState of timers on the stack.
FrameState& root_frame_state(NamedTimerFactory::instance().getRootFrameState()); // This one is not invalidated.
CurTimerData* cur_timer_data = &LLFastTimer::sCurTimerData;
// If the the following condition holds then cur_timer_data->mCurTimer == mAppTimer and
// we can stop since mAppTimer->mFrameState is allocated with new and does not invalidate.
while(cur_timer_data->mFrameState != &root_frame_state)
{
cur_timerp->mFrameState = &cur_timerp->mFrameState->mTimer->getFrameState();
cur_timerp = cur_timerp->mLastTimerData.mCurTimer;
cur_timer_data->mFrameState = cur_timer_data->mCurTimer->mFrameState = &cur_timer_data->mNamedTimer->getFrameState();
cur_timer_data = &cur_timer_data->mCurTimer->mLastTimerData;
}
// Update FrameState::mParent
info_list_t& frame_state_list(getFrameStateList());
FrameState* const vector_start = &*frame_state_list.begin();
int const vector_size = frame_state_list.size();
FrameState const* const old_vector_start = root_frame_state.mParent;
if (vector_start != old_vector_start)
{
// Vector was moved; if it was sorted then FrameState::mParent will get fixed after returning from this function (see LLFastTimer::NamedTimer::resetFrame).
root_frame_state.mParent = vector_start;
ptrdiff_t offset = vector_start - old_vector_start;
llassert(frame_state_list[vector_size - 1].mParent == vector_start); // The one that was added at the end is already OK.
for (int i = 2; i < vector_size - 1; ++i)
{
FrameState*& parent(frame_state_list[i].mParent);
if (parent != &root_frame_state)
{
parent += offset;
}
}
}
}
//static
#if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
{
return sClockResolution >> 8;
}
#else // windows or x86-mac or x86-linux or x86-solaris
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
{
#if USE_RDTSC || !LL_WINDOWS
//getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz
static U64 sCPUClockFrequency = U64(LLProcessorInfo().getCPUFrequency()*1000000.0);
// we drop the low-order byte in our timers, so report a lower frequency
// See lltimer.cpp.
#if LL_LINUX || LL_DARWIN || LL_SOLARIS
std::string LLFastTimer::sClockType = "gettimeofday";
#elif LL_WINDOWS
std::string LLFastTimer::sClockType = "QueryPerformanceCounter";
#else
// If we're not using RDTSC, each fasttimer tick is just a performance counter tick.
// Not redefining the clock frequency itself (in llprocessor.cpp/calculate_cpu_frequency())
// since that would change displayed MHz stats for CPUs
#error "Platform not supported"
#endif
//static
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
{
static bool firstcall = true;
static U64 sCPUClockFrequency;
if (firstcall)
{
QueryPerformanceFrequency((LARGE_INTEGER*)&sCPUClockFrequency);
sCPUClockFrequency = calc_clock_frequency();
firstcall = false;
}
#endif
return sCPUClockFrequency >> 8;
}
#endif
LLFastTimer::FrameState::FrameState(LLFastTimer::NamedTimer* timerp)
: mActiveCount(0),
@@ -408,11 +537,12 @@ void LLFastTimer::NamedTimer::buildHierarchy()
// bootstrap tree construction by attaching to last timer to be on stack
// when this timer was called
if (timer.getFrameState().mLastCaller && timer.mParent == NamedTimerFactory::instance().getRootTimer())
FrameState& frame_state(timer.getFrameState());
if (frame_state.mLastCaller && timer.mParent == NamedTimerFactory::instance().getRootTimer())
{
timer.setParent(timer.getFrameState().mLastCaller->mTimer);
timer.setParent(frame_state.mLastCaller);
// no need to push up tree on first use, flag can be set spuriously
timer.getFrameState().mMoveUpTree = false;
frame_state.mMoveUpTree = false;
}
}
}
@@ -461,12 +591,10 @@ void LLFastTimer::NamedTimer::accumulateTimings()
{
U32 cur_time = getCPUClockCount32();
static LLFastTimer::CurTimerData& static_cur_data = LLFastTimer::CurTimerData::get();
// walk up stack of active timers and accumulate current time while leaving timing structures active
LLFastTimer* cur_timer = static_cur_data.mCurTimer;
LLFastTimer* cur_timer = sCurTimerData.mCurTimer;
// root defined by parent pointing to self
CurTimerData* cur_data = &static_cur_data;
CurTimerData* cur_data = &sCurTimerData;
while(cur_timer->mLastTimerData.mCurTimer != cur_timer)
{
U32 cumulative_time_delta = cur_time - cur_timer->mStartTime;
@@ -573,15 +701,14 @@ void LLFastTimer::NamedTimer::resetFrame()
timerp->mFrameStateIndex = index;
index++;
llassert_always(timerp->mFrameStateIndex < (S32)getFrameStateList().size());
}
llassert(index == (S32)getFrameStateList().size());
// sort timers by DFS traversal order to improve cache coherency
std::sort(getFrameStateList().begin(), getFrameStateList().end(), SortTimersDFS());
// update pointers into framestatelist now that we've sorted it
DeclareTimer::updateCachedPointers();
updateCachedPointers();
// reset for next frame
{
@@ -615,10 +742,8 @@ void LLFastTimer::NamedTimer::reset()
// effectively zeroing out any accumulated time
U32 cur_time = getCPUClockCount32();
static LLFastTimer::CurTimerData& static_cur_data = LLFastTimer::CurTimerData::get();
// root defined by parent pointing to self
CurTimerData* cur_data = &static_cur_data;
CurTimerData* cur_data = &sCurTimerData;
LLFastTimer* cur_timer = cur_data->mCurTimer;
while(cur_timer->mLastTimerData.mCurTimer != cur_timer)
{
@@ -652,13 +777,16 @@ void LLFastTimer::NamedTimer::reset()
//static
LLFastTimer::info_list_t& LLFastTimer::getFrameStateList()
{
//Static local varaible to avoid static initialization order fiasco.
//NamedTimerFactory ctor uses this object, and is called during static initialization...
//often before llfasttimer_class.cpp's translation unit.
//'leak' is harmless and intended to ensure it out-scopes NamedTimerFactory.
static info_list_t* timer_infos = new info_list_t();
return *timer_infos;
{
if (!sTimerInfos)
{
sTimerInfos = new info_list_t;
#if 0
// Avoid the vector being moved in memory by reserving enough memory right away.
sTimerInfos->reserve(1024);
#endif
}
return *sTimerInfos;
}
@@ -788,23 +916,27 @@ const LLFastTimer::NamedTimer* LLFastTimer::getTimerByName(const std::string& na
LLFastTimer::LLFastTimer(LLFastTimer::FrameState* state)
: mFrameState(state)
{
// Only called for mAppTimer with mRootFrameState, which never invalidates.
llassert(state == &NamedTimerFactory::instance().getRootFrameState());
U32 start_time = getCPUClockCount32();
mStartTime = start_time;
mFrameState->mActiveCount++;
static LLFastTimer::CurTimerData& static_cur_data = LLFastTimer::CurTimerData::get();
static_cur_data.mCurTimer = this;
static_cur_data.mFrameState = mFrameState;
static_cur_data.mChildTime = 0;
mLastTimerData = static_cur_data;
LLFastTimer::sCurTimerData.mCurTimer = this;
LLFastTimer::sCurTimerData.mNamedTimer = mFrameState->mTimer;
LLFastTimer::sCurTimerData.mFrameState = mFrameState;
LLFastTimer::sCurTimerData.mChildTime = 0;
// This is the root FastTimer (mAppTimer), mark it as such by having
// mLastTimerData be equal to sCurTimerData (which is a rather arbitrary
// and not very logical way to do that --Aleric).
mLastTimerData = LLFastTimer::sCurTimerData;
}
//////////////////////////////////////////////////////////////////////////////
//
// Important note: These implementations must be FAST!
//
//LL_COMMON_API U64 get_clock_count(); // in lltimer.cpp
// These use QueryPerformanceCounter, which is arguably fine and also works on AMD architectures.
U32 LLFastTimer::getCPUClockCount32()
@@ -817,9 +949,3 @@ U64 LLFastTimer::getCPUClockCount64()
return get_clock_count();
}
#if LL_WINDOWS
std::string LLFastTimer::sClockType = "QueryPerformanceCounter";
#else
std::string LLFastTimer::sClockType = "gettimeofday";
#endif

View File

@@ -52,7 +52,7 @@ public:
U32 mSelfTimeCounter;
U32 mCalls;
FrameState* mParent; // info for caller timer
FrameState* mLastCaller; // used to bootstrap tree construction
NamedTimer* mLastCaller; // used to bootstrap tree construction
NamedTimer* mTimer;
U16 mActiveCount; // number of timers with this ID active on stack
bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame
@@ -144,8 +144,6 @@ public:
DeclareTimer(const std::string& name, bool open);
DeclareTimer(const std::string& name);
static void updateCachedPointers();
private:
NamedTimer& mTimer;
FrameState* mFrameState;
@@ -169,11 +167,12 @@ public:
// keep current parent as long as it is active when we are
frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0);
static LLFastTimer::CurTimerData& static_cur_data = LLFastTimer::CurTimerData::get();
mLastTimerData = static_cur_data;
static_cur_data.mCurTimer = this;
static_cur_data.mFrameState = frame_state;
static_cur_data.mChildTime = 0;
LLFastTimer::CurTimerData* cur_timer_data = &LLFastTimer::sCurTimerData;
mLastTimerData = *cur_timer_data;
cur_timer_data->mCurTimer = this;
cur_timer_data->mNamedTimer = &timer.mTimer;
cur_timer_data->mFrameState = frame_state;
cur_timer_data->mChildTime = 0;
#endif
#if TIME_FAST_TIMERS
U64 timer_end = getCPUClockCount64();
@@ -195,19 +194,17 @@ public:
LLFastTimer::FrameState* frame_state = mFrameState;
U32 total_time = getCPUClockCount32() - mStartTime;
static LLFastTimer::CurTimerData& static_cur_data = LLFastTimer::CurTimerData::get();
frame_state->mSelfTimeCounter += total_time - static_cur_data.mChildTime;
frame_state->mSelfTimeCounter += total_time - LLFastTimer::sCurTimerData.mChildTime;
frame_state->mActiveCount--;
// store last caller to bootstrap tree creation
// do this in the destructor in case of recursion to get topmost caller
frame_state->mLastCaller = mLastTimerData.mFrameState;
frame_state->mLastCaller = mLastTimerData.mNamedTimer;
// we are only tracking self time, so subtract our total time delta from parents
mLastTimerData.mChildTime += total_time;
static_cur_data = mLastTimerData;
LLFastTimer::sCurTimerData = mLastTimerData;
#endif
#if TIME_FAST_TIMERS
U64 timer_end = getCPUClockCount64();
@@ -241,6 +238,9 @@ public:
// call this to reset timer hierarchy, averages, etc.
static void reset();
// called to update all FrameState pointers.
static void updateCachedPointers();
static U64 countsPerSecond();
static S32 getLastFrameIndex() { return sLastFrameIndex; }
static S32 getCurFrameIndex() { return sCurFrameIndex; }
@@ -250,31 +250,23 @@ public:
struct CurTimerData
{
CurTimerData() : mCurTimer(NULL),mFrameState(NULL),mChildTime(0) {}
LLFastTimer* mCurTimer;
NamedTimer* mNamedTimer;
FrameState* mFrameState;
U32 mChildTime;
static CurTimerData& get()
{
//Static local varaible to avoid static initialization order fiasco.
//NamedTimerFactory ctor uses this object, and is called during static initialization...
//often before llfasttimer_class.cpp's translation unit.
//'leak' is harmless and intended to ensure it out-scopes NamedTimerFactory.
static CurTimerData* timer_data = new CurTimerData();
return *timer_data;
}
};
static CurTimerData sCurTimerData;
static std::string sClockType;
public:
static U32 getCPUClockCount32();
static U64 getCPUClockCount64();
static U64 sClockResolution;
private:
static S32 sCurFrameIndex;
static S32 sLastFrameIndex;
static U64 sLastFrameTime;
static info_list_t* sTimerInfos;
U32 mStartTime;
LLFastTimer::FrameState* mFrameState;
@@ -282,6 +274,4 @@ private:
};
typedef class LLFastTimer LLFastTimer;
#endif // LL_LLFASTTIMER_H

View File

@@ -198,7 +198,7 @@ U64 get_clock_count()
return clock_count.QuadPart - offset;
}
F64 calc_clock_frequency(U32 uiMeasureMSecs)
F64 calc_clock_frequency(void)
{
__int64 freq;
QueryPerformanceFrequency((LARGE_INTEGER *) &freq);
@@ -209,7 +209,7 @@ F64 calc_clock_frequency(U32 uiMeasureMSecs)
#if LL_LINUX || LL_DARWIN || LL_SOLARIS
// Both Linux and Mac use gettimeofday for accurate time
F64 calc_clock_frequency(unsigned int uiMeasureMSecs)
F64 calc_clock_frequency(void)
{
return 1000000.0; // microseconds, so 1 Mhz.
}
@@ -226,7 +226,7 @@ U64 get_clock_count()
void update_clock_frequencies()
{
gClockFrequency = calc_clock_frequency(50U);
gClockFrequency = calc_clock_frequency();
gClockFrequencyInv = 1.0/gClockFrequency;
gClocksToMicroseconds = gClockFrequencyInv * SEC_TO_MICROSEC;
}

View File

@@ -113,7 +113,7 @@ public:
// Various functions for initializing/accessing clock and timing stuff. Don't use these without REALLY knowing how they work.
//
LL_COMMON_API U64 get_clock_count();
LL_COMMON_API F64 calc_clock_frequency(U32 msecs);
LL_COMMON_API F64 calc_clock_frequency();
LL_COMMON_API void update_clock_frequencies();
// Sleep for milliseconds

View File

@@ -38,6 +38,8 @@
#include "aithreadsafe.h"
#include "aistatemachine.h"
extern F64 calc_clock_frequency(void);
extern LLControlGroup gSavedSettings;
// Local variables.
@@ -79,7 +81,7 @@ AITHREADSAFESIMPLE(U64, AIStateMachine::sMaxCount, );
void AIStateMachine::updateSettings(void)
{
Dout(dc::statemachine, "Initializing AIStateMachine::sMaxCount");
*AIAccess<U64>(sMaxCount) = LLFastTimer::sClockResolution * gSavedSettings.getU32("StateMachineMaxTime") / 1000;
*AIAccess<U64>(sMaxCount) = calc_clock_frequency() * gSavedSettings.getU32("StateMachineMaxTime") / 1000;
}
//----------------------------------------------------------------------------
@@ -320,7 +322,7 @@ void AIStateMachine::mainloop(void*)
if (total_clocks >= max_count)
{
#ifndef LL_RELEASE_FOR_DOWNLOAD
llwarns << "AIStateMachine::mainloop did run for " << (total_clocks * 1000 / LLFastTimer::sClockResolution) << " ms." << llendl;
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;