diff --git a/indra/llcommon/llfasttimer_class.cpp b/indra/llcommon/llfasttimer_class.cpp index 240f2c61a..81ccc8a8e 100644 --- a/indra/llcommon/llfasttimer_class.cpp +++ b/indra/llcommon/llfasttimer_class.cpp @@ -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. +// 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, +// 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 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::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 - diff --git a/indra/llcommon/llfasttimer_class.h b/indra/llcommon/llfasttimer_class.h index 9a547dd69..c6a6f59c1 100644 --- a/indra/llcommon/llfasttimer_class.h +++ b/indra/llcommon/llfasttimer_class.h @@ -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 diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index 1762b3b00..2d515c212 100644 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -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; } diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h index 478585e54..2316944f4 100644 --- a/indra/llcommon/lltimer.h +++ b/indra/llcommon/lltimer.h @@ -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 diff --git a/indra/newview/statemachine/aistatemachine.cpp b/indra/newview/statemachine/aistatemachine.cpp index 49f7ee0ba..cbe261cc4 100644 --- a/indra/newview/statemachine/aistatemachine.cpp +++ b/indra/newview/statemachine/aistatemachine.cpp @@ -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(sMaxCount) = LLFastTimer::sClockResolution * gSavedSettings.getU32("StateMachineMaxTime") / 1000; + *AIAccess(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;