summaryrefslogtreecommitdiff
path: root/indra/llcommon/lltracerecording.h
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon/lltracerecording.h')
-rw-r--r--indra/llcommon/lltracerecording.h249
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;
};
}