diff options
Diffstat (limited to 'indra/llcommon/lltracerecording.h')
-rw-r--r-- | indra/llcommon/lltracerecording.h | 249 |
1 files changed, 239 insertions, 10 deletions
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h index d0c2e754f5..0a1a02fa02 100644 --- a/indra/llcommon/lltracerecording.h +++ b/indra/llcommon/lltracerecording.h @@ -34,6 +34,147 @@ #include "lltimer.h" #include "lltrace.h" +template<typename DERIVED> +class LL_COMMON_API LLVCRControlsMixinInterface +{ +public: + virtual ~LLVCRControlsMixinInterface() {} + // trigger data accumulation (without reset) + virtual void handleStart() = 0; + // stop data accumulation, should put object in queryable state + virtual void handleStop() = 0; + // clear accumulated values, can be called while started + virtual void handleReset() = 0; + // atomically stop this object while starting the other + // no data can be missed in between stop and start + virtual void handleSplitTo(DERIVED& other) = 0; +}; + +template<typename DERIVED> +class LL_COMMON_API LLVCRControlsMixin +: private LLVCRControlsMixinInterface<DERIVED> +{ +public: + enum EPlayState + { + STOPPED, + PAUSED, + STARTED + }; + + void start() + { + switch (mPlayState) + { + case STOPPED: + handleReset(); + handleStart(); + break; + case PAUSED: + handleStart(); + break; + case STARTED: + handleReset(); + break; + } + mPlayState = STARTED; + } + + void stop() + { + switch (mPlayState) + { + case STOPPED: + break; + case PAUSED: + handleStop(); + break; + case STARTED: + break; + } + mPlayState = STOPPED; + } + + void pause() + { + switch (mPlayState) + { + case STOPPED: + break; + case PAUSED: + break; + case STARTED: + handleStop(); + break; + } + mPlayState = PAUSED; + } + + void resume() + { + switch (mPlayState) + { + case STOPPED: + handleStart(); + break; + case PAUSED: + handleStart(); + break; + case STARTED: + break; + } + mPlayState = STARTED; + } + + void restart() + { + switch (mPlayState) + { + case STOPPED: + handleReset(); + handleStart(); + break; + case PAUSED: + handleReset(); + handleStart(); + break; + case STARTED: + handleReset(); + break; + } + mPlayState = STARTED; + } + + void reset() + { + handleReset(); + } + + void splitTo(DERIVED& other) + { + onSplitTo(other); + } + + void splitFrom(DERIVED& other) + { + other.onSplitTo(*this); + } + + bool isStarted() { return mPlayState == STARTED; } + bool isPaused() { return mPlayState == PAUSED; } + bool isStopped() { return mPlayState == STOPPED; } + EPlayState getPlayState() { return mPlayState; } + +protected: + + LLVCRControlsMixin() + : mPlayState(STOPPED) + {} + +private: + EPlayState mPlayState; +}; + namespace LLTrace { //template<typename T, typename IS_UNIT> class Rate; @@ -44,7 +185,7 @@ namespace LLTrace //template<typename T> class MeasurementAccumulator; //class TimerAccumulator; - class LL_COMMON_API Recording + class LL_COMMON_API Recording : public LLVCRControlsMixin<Recording> { public: Recording(); @@ -54,15 +195,10 @@ namespace LLTrace void makePrimary(); bool isPrimary() const; - void start(); - void stop(); - void resume(); - void reset(); - void update(); - bool isStarted() const { return mIsStarted; } + void mergeRecording(const Recording& other); + void mergeRecordingDelta(const Recording& baseline, const Recording& target); - void addSamples(const Recording& other); - void addDeltas(const Recording& baseline, const Recording& target); + void update(); // Rate accessors template <typename T, typename IS_UNIT> @@ -173,6 +309,14 @@ namespace LLTrace F64 getSampleTime() const { return mElapsedSeconds; } private: + friend class PeriodicRecording; + // implementation for LLVCRControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(Recording& other); + + friend class ThreadRecorder; // returns data for current thread class ThreadRecorder* getThreadRecorder(); @@ -181,14 +325,99 @@ namespace LLTrace LLCopyOnWritePointer<AccumulatorBuffer<MeasurementAccumulator<F32> > > mMeasurements; LLCopyOnWritePointer<AccumulatorBuffer<TimerAccumulator> > mStackTimers; - bool mIsStarted; LLTimer mSamplingTimer; F64 mElapsedSeconds; }; class LL_COMMON_API PeriodicRecording + : public LLVCRControlsMixin<PeriodicRecording> { + public: + PeriodicRecording(S32 num_periods) + : mNumPeriods(num_periods), + mCurPeriod(0), + mTotalValid(false), + mRecordingPeriods(new Recording[num_periods]) + { + llassert(mNumPeriods > 0); + } + + ~PeriodicRecording() + { + delete[] mRecordingPeriods; + } + + void nextPeriod() + { + EPlayState play_state = getPlayState(); + getCurRecordingPeriod().stop(); + mCurPeriod = (mCurPeriod + 1) % mNumPeriods; + switch(play_state) + { + case STOPPED: + break; + case PAUSED: + getCurRecordingPeriod().pause(); + break; + case STARTED: + getCurRecordingPeriod().start(); + break; + } + // new period, need to recalculate total + mTotalValid = false; + } + + Recording& getCurRecordingPeriod() + { + return mRecordingPeriods[mCurPeriod]; + } + + const Recording& getCurRecordingPeriod() const + { + return mRecordingPeriods[mCurPeriod]; + } + + Recording& getTotalRecording() + { + if (!mTotalValid) + { + mTotalRecording.reset(); + for (S32 i = (mCurPeriod + 1) % mNumPeriods; i < mCurPeriod; i++) + { + mTotalRecording.mergeRecording(mRecordingPeriods[i]); + } + } + mTotalValid = true; + return mTotalRecording; + } + + private: + // implementation for LLVCRControlsMixin + /*virtual*/ void handleStart() + { + getCurRecordingPeriod().handleStart(); + } + + /*virtual*/ void handleStop() + { + getCurRecordingPeriod().handleStop(); + } + + /*virtual*/ void handleReset() + { + getCurRecordingPeriod().handleReset(); + } + + /*virtual*/ void handleSplitTo(PeriodicRecording& other) + { + getCurRecordingPeriod().handleSplitTo(other.getCurRecordingPeriod()); + } + Recording* mRecordingPeriods; + Recording mTotalRecording; + bool mTotalValid; + S32 mNumPeriods, + mCurPeriod; }; } |