diff options
Diffstat (limited to 'indra/llcommon/llfasttimer.h')
-rw-r--r-- | indra/llcommon/llfasttimer.h | 194 |
1 files changed, 112 insertions, 82 deletions
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index f5c90291b8..8af79c90fd 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -1,11 +1,11 @@ -/** +/** * @file llfasttimer.h * @brief Declaration of a fast timer. * * $LicenseInfo:firstyear=2004&license=viewergpl$ - * + * * Copyright (c) 2004-2009, Linden Research, Inc. - * + * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 @@ -13,17 +13,17 @@ * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * + * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * + * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. - * + * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. @@ -39,13 +39,37 @@ #define TIME_FAST_TIMERS 0 #if LL_WINDOWS +#define LL_INLINE __forceinline + +// +// NOTE: put back in when we aren't using platform sdk anymore +// +// because MS has different signatures for these functions in winnt.h +// need to rename them to avoid conflicts +//#define _interlockedbittestandset _renamed_interlockedbittestandset +//#define _interlockedbittestandreset _renamed_interlockedbittestandreset +//#include <intrin.h> +//#undef _interlockedbittestandset +//#undef _interlockedbittestandreset + +//inline U32 get_cpu_clock_count_32() +//{ +// U64 time_stamp = __rdtsc(); +// return (U32)(time_stamp >> 8); +//} +// +//// return full timer value, *not* shifted by 8 bits +//inline U64 get_cpu_clock_count_64() +//{ +// return __rdtsc(); +//} // shift off lower 8 bits for lower resolution but longer term timing // on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing inline U32 get_cpu_clock_count_32() { U32 ret_val; - __asm + __asm { _emit 0x0f _emit 0x31 @@ -61,7 +85,7 @@ inline U32 get_cpu_clock_count_32() inline U64 get_cpu_clock_count_64() { U64 ret_val; - __asm + __asm { _emit 0x0f _emit 0x31 @@ -72,19 +96,20 @@ inline U64 get_cpu_clock_count_64() } return ret_val; } - -#endif // LL_WINDOWS +#else +#define LL_INLINE +#endif #if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__)) inline U32 get_cpu_clock_count_32() -{ - U64 x; - __asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); - return (U32)x >> 8; +{ + U64 x; + __asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); + return (U32)x >> 8; } inline U32 get_cpu_clock_count_64() -{ +{ U64 x; __asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); return x >> 8; @@ -103,7 +128,7 @@ inline U32 get_cpu_clock_count_32() } inline U32 get_cpu_clock_count_64() -{ +{ return get_clock_count(); } #endif @@ -113,12 +138,27 @@ class LLMutex; #include <queue> #include "llsd.h" - class LL_COMMON_API LLFastTimer { public: + + class NamedTimer; + + struct LL_COMMON_API FrameState + { + FrameState(NamedTimer* timerp); + + U32 mSelfTimeCounter; + U32 mCalls; + FrameState* mParent; // info for caller timer + FrameState* 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 + }; + // stores a "named" timer instance to be reused via multiple LLFastTimer stack instances - class LL_COMMON_API NamedTimer + class LL_COMMON_API NamedTimer : public LLInstanceTracker<NamedTimer> { friend class DeclareTimer; @@ -149,25 +189,11 @@ public: static NamedTimer& getRootNamedTimer(); - struct FrameState - { - FrameState(NamedTimer* timerp); - - U32 mSelfTimeCounter; - U32 mCalls; - FrameState* mParent; // info for caller timer - FrameState* 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 - }; - S32 getFrameStateIndex() const { return mFrameStateIndex; } FrameState& getFrameState() const; - - private: + private: friend class LLFastTimer; friend class NamedTimerFactory; @@ -178,7 +204,7 @@ public: // recursive call to gather total time from children static void accumulateTimings(); - // updates cumulative times and hierarchy, + // updates cumulative times and hierarchy, // can be called multiple times in a frame, at any point static void processTimes(); @@ -186,7 +212,6 @@ public: static void resetFrame(); static void reset(); - // // members // @@ -207,58 +232,47 @@ public: std::vector<NamedTimer*> mChildren; bool mCollapsed; // don't show children bool mNeedsSorting; // sort children whenever child added - }; // used to statically declare a new named timer class LL_COMMON_API DeclareTimer : public LLInstanceTracker<DeclareTimer> { + friend class LLFastTimer; public: DeclareTimer(const std::string& name, bool open); DeclareTimer(const std::string& name); static void updateCachedPointers(); - // convertable to NamedTimer::FrameState for convenient usage of LLFastTimer(declared_timer) - operator NamedTimer::FrameState&() { return *mFrameState; } private: - NamedTimer& mTimer; - NamedTimer::FrameState* mFrameState; + NamedTimer& mTimer; + FrameState* mFrameState; }; - public: - static LLMutex* sLogLock; - static std::queue<LLSD> sLogQueue; - static BOOL sLog; - static BOOL sMetricLog; - - typedef std::vector<NamedTimer::FrameState> info_list_t; - static info_list_t& getFrameStateList(); + LLFastTimer(LLFastTimer::FrameState* state); - enum RootTimerMarker { ROOT }; - LLFastTimer(RootTimerMarker); - - LLFastTimer(NamedTimer::FrameState& timer) - : mFrameState(&timer) + LL_INLINE LLFastTimer(LLFastTimer::DeclareTimer& timer) + : mFrameState(timer.mFrameState) { #if TIME_FAST_TIMERS U64 timer_start = get_cpu_clock_count_64(); #endif #if FAST_TIMER_ON - NamedTimer::FrameState* frame_state = &timer; - U32 cur_time = get_cpu_clock_count_32(); - mStartSelfTime = cur_time; - mStartTotalTime = cur_time; + LLFastTimer::FrameState* frame_state = mFrameState; + mStartTime = get_cpu_clock_count_32(); frame_state->mActiveCount++; frame_state->mCalls++; // keep current parent as long as it is active when we are frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0); - - mLastTimer = sCurTimer; - sCurTimer = this; + + LLFastTimer::CurTimerData* cur_timer_data = &LLFastTimer::sCurTimerData; + mLastTimerData = *cur_timer_data; + cur_timer_data->mCurTimer = this; + cur_timer_data->mFrameState = frame_state; + cur_timer_data->mChildTime = 0; #endif #if TIME_FAST_TIMERS U64 timer_end = get_cpu_clock_count_64(); @@ -266,41 +280,54 @@ public: #endif } - ~LLFastTimer() + LL_INLINE ~LLFastTimer() { #if TIME_FAST_TIMERS U64 timer_start = get_cpu_clock_count_64(); #endif #if FAST_TIMER_ON - NamedTimer::FrameState* frame_state = mFrameState; - U32 cur_time = get_cpu_clock_count_32(); - frame_state->mSelfTimeCounter += cur_time - mStartSelfTime; + LLFastTimer::FrameState* frame_state = mFrameState; + U32 total_time = get_cpu_clock_count_32() - mStartTime; + frame_state->mSelfTimeCounter += total_time - LLFastTimer::sCurTimerData.mChildTime; frame_state->mActiveCount--; - LLFastTimer* last_timer = mLastTimer; - sCurTimer = last_timer; // store last caller to bootstrap tree creation - frame_state->mLastCaller = last_timer->mFrameState; + // do this in the destructor in case of recursion to get topmost caller + frame_state->mLastCaller = mLastTimerData.mFrameState; // we are only tracking self time, so subtract our total time delta from parents - U32 total_time = cur_time - mStartTotalTime; - last_timer->mStartSelfTime += total_time; + mLastTimerData.mChildTime += total_time; + + LLFastTimer::sCurTimerData = mLastTimerData; #endif #if TIME_FAST_TIMERS U64 timer_end = get_cpu_clock_count_64(); sTimerCycles += timer_end - timer_start; sTimerCalls++; -#endif +#endif } +public: + static LLMutex* sLogLock; + static std::queue<LLSD> sLogQueue; + static BOOL sLog; + static BOOL sMetricLog; + static bool sPauseHistory; + static bool sResetHistory; + static U64 sTimerCycles; + static U32 sTimerCalls; + + typedef std::vector<FrameState> info_list_t; + static info_list_t& getFrameStateList(); + // call this once a frame to reset timers static void nextFrame(); // dumps current cumulative frame stats to log // call nextFrame() to reset timers - static void dumpCurTimes(); + static void dumpCurTimes(); // call this to reset timer hierarchy, averages, etc. static void reset(); @@ -312,23 +339,26 @@ public: static void writeLog(std::ostream& os); static const NamedTimer* getTimerByName(const std::string& name); -public: - static bool sPauseHistory; - static bool sResetHistory; - static U64 sTimerCycles; - static U32 sTimerCalls; - + struct CurTimerData + { + LLFastTimer* mCurTimer; + FrameState* mFrameState; + U32 mChildTime; + }; + static CurTimerData sCurTimerData; + private: - static LLFastTimer* sCurTimer; static S32 sCurFrameIndex; static S32 sLastFrameIndex; static U64 sLastFrameTime; static info_list_t* sTimerInfos; - U32 mStartSelfTime; // start time + time of all child timers - U32 mStartTotalTime; // start time + time of all child timers - NamedTimer::FrameState* mFrameState; - LLFastTimer* mLastTimer; + U32 mStartTime; + LLFastTimer::FrameState* mFrameState; + LLFastTimer::CurTimerData mLastTimerData; + }; +typedef class LLFastTimer LLFastTimer; + #endif // LL_LLFASTTIMER_H |