summaryrefslogtreecommitdiff
path: root/indra/llcommon/llfasttimer.h
diff options
context:
space:
mode:
authorRichard Linden <none@none>2013-03-22 00:44:59 -0700
committerRichard Linden <none@none>2013-03-22 00:44:59 -0700
commit68f9f656cd22332e46959a90347e38f79c19a66c (patch)
tree531d87287b69f500c5901f785e60483555b415f9 /indra/llcommon/llfasttimer.h
parente87000ba0750e55d9d6b55feccc4124f5d2b4b74 (diff)
parent368dd542bec7c31e14673b83d3342c35717d2920 (diff)
merge with viewer-release
Diffstat (limited to 'indra/llcommon/llfasttimer.h')
-rw-r--r--indra/llcommon/llfasttimer.h317
1 files changed, 127 insertions, 190 deletions
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index e42e549df5..32a0629a87 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -28,214 +28,98 @@
#define LL_FASTTIMER_H
#include "llinstancetracker.h"
+#include "lltrace.h"
#define FAST_TIMER_ON 1
-#define DEBUG_FAST_TIMER_THREADS 1
+#define LL_FASTTIMER_USE_RDTSC 1
class LLMutex;
-#include <queue>
-#include "llsd.h"
-
-#define LL_FASTTIMER_USE_RDTSC 1
-
+namespace LLTrace
+{
-LL_COMMON_API void assert_main_thread();
+struct BlockTimerStackRecord
+{
+ class BlockTimer* mActiveTimer;
+ class TimeBlock* mTimeBlock;
+ U64 mChildTime;
+};
-class LL_COMMON_API LLFastTimer
+class ThreadTimerStack
+: public BlockTimerStackRecord,
+ public LLThreadLocalSingleton<ThreadTimerStack>
{
-public:
- class NamedTimer;
+ friend class LLThreadLocalSingleton<ThreadTimerStack>;
+ ThreadTimerStack()
+ {}
- struct LL_COMMON_API FrameState
- {
- FrameState();
- void setNamedTimer(NamedTimer* timerp) { mTimer = 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
- : public LLInstanceTracker<NamedTimer>
+public:
+ ThreadTimerStack& operator=(const BlockTimerStackRecord& other)
{
- friend class DeclareTimer;
- public:
- ~NamedTimer();
-
- enum { HISTORY_NUM = 300 };
-
- const std::string& getName() const { return mName; }
- NamedTimer* getParent() const { return mParent; }
- void setParent(NamedTimer* parent);
- S32 getDepth();
- std::string getToolTip(S32 history_index = -1);
-
- typedef std::vector<NamedTimer*>::const_iterator child_const_iter;
- child_const_iter beginChildren();
- child_const_iter endChildren();
- std::vector<NamedTimer*>& getChildren();
-
- void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
- bool getCollapsed() const { return mCollapsed; }
-
- U32 getCountAverage() const { return mCountAverage; }
- U32 getCallAverage() const { return mCallAverage; }
-
- U32 getHistoricalCount(S32 history_index = 0) const;
- U32 getHistoricalCalls(S32 history_index = 0) const;
-
- void setFrameState(FrameState* state) { mFrameState = state; state->setNamedTimer(this); }
- FrameState& getFrameState() const;
-
- private:
- friend class LLFastTimer;
- friend class NamedTimerFactory;
-
- //
- // methods
- //
- NamedTimer(const std::string& name);
- // recursive call to gather total time from children
- static void accumulateTimings();
-
- // updates cumulative times and hierarchy,
- // can be called multiple times in a frame, at any point
- static void processTimes();
-
- static void buildHierarchy();
- static void resetFrame();
- static void reset();
-
- //
- // members
- //
- FrameState* mFrameState;
-
- std::string mName;
-
- U32 mTotalTimeCounter;
-
- U32 mCountAverage;
- U32 mCallAverage;
+ BlockTimerStackRecord::operator=(other);
+ return *this;
+ }
+};
- U32* mCountHistory;
- U32* mCallHistory;
+class BlockTimer
+{
+public:
+ friend class TimeBlock;
+ typedef BlockTimer self_t;
+ typedef class TimeBlock DeclareTimer;
- // tree structure
- NamedTimer* mParent; // NamedTimer of caller(parent)
- std::vector<NamedTimer*> mChildren;
- bool mCollapsed; // don't show children
- bool mNeedsSorting; // sort children whenever child added
- };
+ BlockTimer(TimeBlock& timer);
+ ~BlockTimer();
- // 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);
+ LLUnit<LLUnits::Seconds, F64> getElapsedTime();
- NamedTimer& getNamedTimer() { return mTimer; }
+private:
- private:
- FrameState mFrameState;
- NamedTimer& mTimer;
- };
+ U64 mStartTime;
+ U64 mBlockStartTotalTimeCounter;
+ BlockTimerStackRecord mParentTimerData;
+};
+// stores a "named" timer instance to be reused via multiple BlockTimer stack instances
+class TimeBlock
+: public TraceType<TimeBlockAccumulator>,
+ public LLInstanceTracker<TimeBlock>
+{
public:
- LLFastTimer(LLFastTimer::FrameState* state);
-
- LL_FORCE_INLINE LLFastTimer(LLFastTimer::DeclareTimer& timer)
- : mFrameState(&timer.mFrameState)
- {
-#if FAST_TIMER_ON
- LLFastTimer::FrameState* frame_state = mFrameState;
- mStartTime = getCPUClockCount32();
-
- 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);
-
- 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 DEBUG_FAST_TIMER_THREADS
-#if !LL_RELEASE
- assert_main_thread();
-#endif
-#endif
- }
+ TimeBlock(const char* name, bool open = false, TimeBlock* parent = &getRootTimeBlock());
- LL_FORCE_INLINE ~LLFastTimer()
- {
-#if FAST_TIMER_ON
- LLFastTimer::FrameState* frame_state = mFrameState;
- U32 total_time = getCPUClockCount32() - mStartTime;
-
- frame_state->mSelfTimeCounter += total_time - LLFastTimer::sCurTimerData.mChildTime;
- frame_state->mActiveCount--;
+ TimeBlockTreeNode& getTreeNode() const;
+ TimeBlock* getParent() const { return getTreeNode().getParent(); }
+ void setParent(TimeBlock* parent) { getTreeNode().setParent(parent); }
- // 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;
+ typedef std::vector<TimeBlock*>::iterator child_iter;
+ typedef std::vector<TimeBlock*>::const_iterator child_const_iter;
+ child_iter beginChildren();
+ child_iter endChildren();
+ std::vector<TimeBlock*>& getChildren();
- // we are only tracking self time, so subtract our total time delta from parents
- mLastTimerData.mChildTime += total_time;
+ void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
+ bool getCollapsed() const { return mCollapsed; }
- LLFastTimer::sCurTimerData = mLastTimerData;
-#endif
+ TraceType<TimeBlockAccumulator::CallCountAspect>& callCount()
+ {
+ return static_cast<TraceType<TimeBlockAccumulator::CallCountAspect>&>(*(TraceType<TimeBlockAccumulator>*)this);
}
-public:
- static LLMutex* sLogLock;
- static std::queue<LLSD> sLogQueue;
- static BOOL sLog;
- static BOOL sMetricLog;
- static std::string sLogName;
- static bool sPauseHistory;
- static bool sResetHistory;
+ TraceType<TimeBlockAccumulator::SelfTimeAspect>& selfTime()
+ {
+ return static_cast<TraceType<TimeBlockAccumulator::SelfTimeAspect>&>(*(TraceType<TimeBlockAccumulator>*)this);
+ }
- // call this once a frame to reset timers
- static void nextFrame();
+ static TimeBlock& getRootTimeBlock();
+ static void pushLog(LLSD sd);
+ static void setLogLock(LLMutex* mutex);
+ static void writeLog(std::ostream& os);
// dumps current cumulative frame stats to log
// call nextFrame() to reset timers
static void dumpCurTimes();
- // call this to reset timer hierarchy, averages, etc.
- static void reset();
-
- static U64 countsPerSecond();
- static S32 getLastFrameIndex() { return sLastFrameIndex; }
- static S32 getCurFrameIndex() { return sCurFrameIndex; }
-
- static void writeLog(std::ostream& os);
- static const NamedTimer* getTimerByName(const std::string& name);
-
- struct CurTimerData
- {
- LLFastTimer* mCurTimer;
- FrameState* mFrameState;
- U32 mChildTime;
- };
- static CurTimerData sCurTimerData;
-
-private:
-
-
//////////////////////////////////////////////////////////////////////////////
//
// Important note: These implementations must be FAST!
@@ -258,14 +142,14 @@ private:
//#undef _interlockedbittestandset
//#undef _interlockedbittestandreset
- //inline U32 LLFastTimer::getCPUClockCount32()
+ //inline U32 TimeBlock::getCPUClockCount32()
//{
// U64 time_stamp = __rdtsc();
// return (U32)(time_stamp >> 8);
//}
//
//// return full timer value, *not* shifted by 8 bits
- //inline U64 LLFastTimer::getCPUClockCount64()
+ //inline U64 TimeBlock::getCPUClockCount64()
//{
// return __rdtsc();
//}
@@ -305,7 +189,7 @@ private:
}
#else
- //LL_COMMON_API U64 get_clock_count(); // in lltimer.cpp
+ //U64 get_clock_count(); // in lltimer.cpp
// These use QueryPerformanceCounter, which is arguably fine and also works on AMD architectures.
static U32 getCPUClockCount32()
{
@@ -372,18 +256,71 @@ private:
#endif
- static U64 sClockResolution;
+ static U64 countsPerSecond();
+
+ // updates cumulative times and hierarchy,
+ // can be called multiple times in a frame, at any point
+ static void processTimes();
- static S32 sCurFrameIndex;
- static S32 sLastFrameIndex;
- static U64 sLastFrameTime;
+ // call this once a frame to periodically log timers
+ static void logStats();
- U32 mStartTime;
- LLFastTimer::FrameState* mFrameState;
- LLFastTimer::CurTimerData mLastTimerData;
+ bool mCollapsed; // don't show children
+ // statics
+ static std::string sLogName;
+ static bool sMetricLog,
+ sLog;
+ static U64 sClockResolution;
};
-typedef class LLFastTimer LLFastTimer;
+LL_FORCE_INLINE BlockTimer::BlockTimer(TimeBlock& timer)
+{
+#if FAST_TIMER_ON
+ mStartTime = TimeBlock::getCPUClockCount64();
+
+ BlockTimerStackRecord* cur_timer_data = ThreadTimerStack::getIfExists();
+ TimeBlockAccumulator* accumulator = timer.getPrimaryAccumulator();
+ accumulator->mActiveCount++;
+ mBlockStartTotalTimeCounter = accumulator->mTotalTimeCounter;
+ // keep current parent as long as it is active when we are
+ accumulator->mMoveUpTree |= (accumulator->mParent->getPrimaryAccumulator()->mActiveCount == 0);
+
+ // store top of stack
+ mParentTimerData = *cur_timer_data;
+ // push new information
+ cur_timer_data->mActiveTimer = this;
+ cur_timer_data->mTimeBlock = &timer;
+ cur_timer_data->mChildTime = 0;
+#endif
+}
+
+LL_FORCE_INLINE BlockTimer::~BlockTimer()
+{
+#if FAST_TIMER_ON
+ U64 total_time = TimeBlock::getCPUClockCount64() - mStartTime;
+ BlockTimerStackRecord* cur_timer_data = ThreadTimerStack::getIfExists();
+ TimeBlockAccumulator* accumulator = cur_timer_data->mTimeBlock->getPrimaryAccumulator();
+
+ accumulator->mCalls++;
+ accumulator->mTotalTimeCounter += total_time - (accumulator->mTotalTimeCounter - mBlockStartTotalTimeCounter);
+ accumulator->mSelfTimeCounter += total_time - cur_timer_data->mChildTime;
+ accumulator->mActiveCount--;
+
+ // store last caller to bootstrap tree creation
+ // do this in the destructor in case of recursion to get topmost caller
+ accumulator->mLastCaller = mParentTimerData.mTimeBlock;
+
+ // we are only tracking self time, so subtract our total time delta from parents
+ mParentTimerData.mChildTime += total_time;
+
+ //pop stack
+ *cur_timer_data = mParentTimerData;
+#endif
+}
+
+}
+
+typedef LLTrace::BlockTimer LLFastTimer;
#endif // LL_LLFASTTIMER_H