diff options
Diffstat (limited to 'indra/llcommon')
-rw-r--r-- | indra/llcommon/llpointer.h | 3 | ||||
-rw-r--r-- | indra/llcommon/llthread.cpp | 2 | ||||
-rw-r--r-- | indra/llcommon/llthreadlocalstorage.h | 4 | ||||
-rw-r--r-- | indra/llcommon/lltrace.cpp | 14 | ||||
-rw-r--r-- | indra/llcommon/lltrace.h | 236 | ||||
-rw-r--r-- | indra/llcommon/lltracerecording.cpp | 188 | ||||
-rw-r--r-- | indra/llcommon/lltracerecording.h | 244 | ||||
-rw-r--r-- | indra/llcommon/lltracethreadrecorder.cpp | 78 | ||||
-rw-r--r-- | indra/llcommon/lltracethreadrecorder.h | 13 |
9 files changed, 620 insertions, 162 deletions
diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index c83e55577d..e640ffd595 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -196,6 +196,9 @@ public: *(pointer_t*)(this) = new Type(*pointer_t::mPointer); } } + + const Type* operator->() const { return pointer_t::mPointer; } + const Type& operator*() const { return *pointer_t::mPointer; } }; #endif diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 6374b5398b..118568d5ef 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -93,7 +93,7 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap { LLThread *threadp = (LLThread *)datap; - LLTrace::ThreadRecorder* thread_recorder = new LLTrace::SlaveThreadRecorder(); + LLTrace::ThreadRecorder* thread_recorder = new LLTrace::SlaveThreadRecorder(LLTrace::getUIThreadRecorder()); #if !LL_DARWIN sThreadID = threadp->mID; diff --git a/indra/llcommon/llthreadlocalstorage.h b/indra/llcommon/llthreadlocalstorage.h index 4873b2740d..471784749b 100644 --- a/indra/llcommon/llthreadlocalstorage.h +++ b/indra/llcommon/llthreadlocalstorage.h @@ -131,6 +131,10 @@ public: if (!sInitialized) return false; return get() == other; } + + bool isNull() const { return !sInitialized || get() == NULL; } + + bool notNull() const { return sInitialized && get() != NULL; } }; template<typename DERIVED_TYPE> diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp index 463048008f..c831a1548d 100644 --- a/indra/llcommon/lltrace.cpp +++ b/indra/llcommon/lltrace.cpp @@ -35,13 +35,13 @@ static S32 sInitializationCount = 0; namespace LLTrace { -static MasterThreadRecorder* gMasterThreadRecorder = NULL; +static MasterThreadRecorder* gUIThreadRecorder = NULL; void init() { if (sInitializationCount++ == 0) { - gMasterThreadRecorder = new MasterThreadRecorder(); + gUIThreadRecorder = new MasterThreadRecorder(); } } @@ -54,15 +54,15 @@ void cleanup() { if (--sInitializationCount == 0) { - delete gMasterThreadRecorder; - gMasterThreadRecorder = NULL; + delete gUIThreadRecorder; + gUIThreadRecorder = NULL; } } -MasterThreadRecorder& getMasterThreadRecorder() +MasterThreadRecorder& getUIThreadRecorder() { - llassert(gMasterThreadRecorder != NULL); - return *gMasterThreadRecorder; + llassert(gUIThreadRecorder != NULL); + return *gUIThreadRecorder; } LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder_ptr() diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h index d1edaf969b..e950a119d3 100644 --- a/indra/llcommon/lltrace.h +++ b/indra/llcommon/lltrace.h @@ -73,7 +73,7 @@ bool isInitialized(); const LLThreadLocalPointer<class ThreadRecorder>& get_thread_recorder(); void set_thread_recorder(class ThreadRecorder*); -class MasterThreadRecorder& getMasterThreadRecorder(); +class MasterThreadRecorder& getUIThreadRecorder(); // one per thread per type template<typename ACCUMULATOR> @@ -148,6 +148,15 @@ public: } } + void flush() + { + llassert(mStorageSize >= sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i].flush(); + } + } + void makePrimary() { LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(mStorage); @@ -166,10 +175,12 @@ public: // NOTE: this is not thread-safe. We assume that slots are reserved in the main thread before any child threads are spawned size_t reserveSlot() { +#ifndef LL_RELEASE_FOR_DOWNLOAD if (LLTrace::isInitialized()) { llerrs << "Attempting to declare trace object after program initialization. Trace objects should be statically initialized." << llendl; } +#endif size_t next_slot = sNextStorageSlot++; if (next_slot >= mStorageSize) { @@ -260,14 +271,14 @@ protected: }; template<typename T> -class MeasurementAccumulator +class EventAccumulator { public: typedef T value_t; typedef F64 mean_t; - typedef MeasurementAccumulator<T> self_t; + typedef EventAccumulator<T> self_t; - MeasurementAccumulator() + EventAccumulator() : mSum(0), mMin((std::numeric_limits<T>::max)()), mMax((std::numeric_limits<T>::min)()), @@ -277,7 +288,7 @@ public: mLastValue(0) {} - void sample(T value) + void record(T value) { mNumSamples++; mSum += value; @@ -301,17 +312,10 @@ public: if (other.mNumSamples) { mSum += other.mSum; - if (other.mMin < mMin) - { - mMin = other.mMin; - } - if (other.mMax > mMax) - { - mMax = other.mMax; - } - F64 weight = (F64)mNumSamples / (F64)(mNumSamples + other.mNumSamples); - mNumSamples += other.mNumSamples; - mMean = mMean * weight + other.mMean * (1.f - weight); + + // NOTE: both conditions will hold first time through + if (other.mMin < mMin) { mMin = other.mMin; } + if (other.mMax > mMax) { mMax = other.mMax; } // combine variance (and hence standard deviation) of 2 different sized sample groups using // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm @@ -333,12 +337,16 @@ public: else { mVarianceSum = (F64)mNumSamples - * ((((n_1 - 1.f) * v_1) - + ((n_2 - 1.f) * v_2) - + (((n_1 * n_2) / (n_1 + n_2)) - * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) - / (n_1 + n_2 - 1.f)); + * ((((n_1 - 1.f) * v_1) + + ((n_2 - 1.f) * v_2) + + (((n_1 * n_2) / (n_1 + n_2)) + * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) + / (n_1 + n_2 - 1.f)); } + + F64 weight = (F64)mNumSamples / (F64)(mNumSamples + other.mNumSamples); + mNumSamples += other.mNumSamples; + mMean = mMean * weight + other.mMean * (1.f - weight); mLastValue = other.mLastValue; } } @@ -347,13 +355,15 @@ public: { mNumSamples = 0; mSum = 0; - mMin = 0; - mMax = 0; + mMin = std::numeric_limits<T>::max(); + mMax = std::numeric_limits<T>::min(); mMean = 0; mVarianceSum = 0; mLastValue = other ? other->mLastValue : 0; } + void flush() {} + T getSum() const { return (T)mSum; } T getMin() const { return (T)mMin; } T getMax() const { return (T)mMax; } @@ -376,6 +386,150 @@ private: template<typename T> +class SampleAccumulator +{ +public: + typedef T value_t; + typedef F64 mean_t; + typedef SampleAccumulator<T> self_t; + + SampleAccumulator() + : mSum(0), + mMin((std::numeric_limits<T>::max)()), + mMax((std::numeric_limits<T>::min)()), + mMean(0), + mVarianceSum(0), + mLastSampleTimeStamp(LLTimer::getTotalSeconds()), + mTotalSamplingTime(0), + mNumSamples(0), + mLastValue(0), + mHasValue(false) + {} + + void sample(T value) + { + LLUnitImplicit<LLUnits::Seconds, F64> time_stamp = LLTimer::getTotalSeconds(); + LLUnitImplicit<LLUnits::Seconds, F64> delta_time = time_stamp - mLastSampleTimeStamp; + mLastSampleTimeStamp = time_stamp; + + if (mHasValue) + { + mTotalSamplingTime += delta_time; + mSum += (F64)mLastValue * delta_time; + + // NOTE: both conditions will hold first time through + if (value < mMin) { mMin = value; } + if (value > mMax) { mMax = value; } + + F64 old_mean = mMean; + mMean += (delta_time / mTotalSamplingTime) * ((F64)mLastValue - old_mean); + mVarianceSum += delta_time * ((F64)mLastValue - old_mean) * ((F64)mLastValue - mMean); + } + + mLastValue = value; + mNumSamples++; + mHasValue = true; + } + + void addSamples(const self_t& other) + { + if (other.mTotalSamplingTime) + { + mSum += other.mSum; + + // NOTE: both conditions will hold first time through + if (other.mMin < mMin) { mMin = other.mMin; } + if (other.mMax > mMax) { mMax = other.mMax; } + + // combine variance (and hence standard deviation) of 2 different sized sample groups using + // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm + F64 n_1 = mTotalSamplingTime, + n_2 = other.mTotalSamplingTime; + F64 m_1 = mMean, + m_2 = other.mMean; + F64 v_1 = mVarianceSum / mTotalSamplingTime, + v_2 = other.mVarianceSum / other.mTotalSamplingTime; + if (n_1 == 0) + { + mVarianceSum = other.mVarianceSum; + } + else if (n_2 == 0) + { + // variance is unchanged + // mVarianceSum = mVarianceSum; + } + else + { + mVarianceSum = mTotalSamplingTime + * ((((n_1 - 1.f) * v_1) + + ((n_2 - 1.f) * v_2) + + (((n_1 * n_2) / (n_1 + n_2)) + * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) + / (n_1 + n_2 - 1.f)); + } + + llassert(other.mTotalSamplingTime > 0); + F64 weight = mTotalSamplingTime / (mTotalSamplingTime + other.mTotalSamplingTime); + mNumSamples += other.mNumSamples; + mTotalSamplingTime += other.mTotalSamplingTime; + mMean = (mMean * weight) + (other.mMean * (1.0 - weight)); + mLastValue = other.mLastValue; + mLastSampleTimeStamp = other.mLastSampleTimeStamp; + mHasValue |= other.mHasValue; + } + } + + void reset(const self_t* other) + { + mNumSamples = 0; + mSum = 0; + mMin = std::numeric_limits<T>::max(); + mMax = std::numeric_limits<T>::min(); + mMean = other ? other->mLastValue : 0; + mVarianceSum = 0; + mLastSampleTimeStamp = LLTimer::getTotalSeconds(); + mTotalSamplingTime = 0; + mLastValue = other ? other->mLastValue : 0; + mHasValue = other ? other->mHasValue : false; + } + + void flush() + { + LLUnitImplicit<LLUnits::Seconds, F64> time_stamp = LLTimer::getTotalSeconds(); + LLUnitImplicit<LLUnits::Seconds, F64> delta_time = time_stamp - mLastSampleTimeStamp; + + mSum += (F64)mLastValue * delta_time; + + mTotalSamplingTime += delta_time; + mLastSampleTimeStamp = time_stamp; + } + + T getSum() const { return (T)mSum; } + T getMin() const { return (T)mMin; } + T getMax() const { return (T)mMax; } + T getLastValue() const { return (T)mLastValue; } + F64 getMean() const { return mMean; } + F64 getStandardDeviation() const { return sqrtf(mVarianceSum / mTotalSamplingTime); } + U32 getSampleCount() const { return mNumSamples; } + +private: + T mSum, + mMin, + mMax, + mLastValue; + + bool mHasValue; + + F64 mMean, + mVarianceSum; + + LLUnitImplicit<LLUnits::Seconds, F64> mLastSampleTimeStamp, + mTotalSamplingTime; + + U32 mNumSamples; +}; + +template<typename T> class CountAccumulator { public: @@ -406,6 +560,8 @@ public: mSum = 0; } + void flush() {} + T getSum() const { return (T)mSum; } U32 getSampleCount() const { return mNumSamples; } @@ -439,6 +595,7 @@ public: TimeBlockAccumulator(); void addSamples(const self_t& other); void reset(const self_t* other); + void flush() {} // // members @@ -493,25 +650,44 @@ public: template <typename T = F64> -class MeasurementStatHandle -: public TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> > +class EventStatHandle +: public TraceType<EventAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> > { public: typedef typename LLUnits::HighestPrecisionType<T>::type_t storage_t; - typedef TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> > trace_t; + typedef TraceType<EventAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> > trace_t; - MeasurementStatHandle(const char* name, const char* description = NULL) + EventStatHandle(const char* name, const char* description = NULL) : trace_t(name, description) {} }; template<typename T, typename VALUE_T> -void sample(MeasurementStatHandle<T>& measurement, VALUE_T value) +void record(EventStatHandle<T>& measurement, VALUE_T value) { T converted_value(value); - measurement.getPrimaryAccumulator()->sample(LLUnits::rawValue(converted_value)); + measurement.getPrimaryAccumulator()->record(LLUnits::rawValue(converted_value)); } +template <typename T = F64> +class SampleStatHandle +: public TraceType<SampleAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> > +{ +public: + typedef typename LLUnits::HighestPrecisionType<T>::type_t storage_t; + typedef TraceType<SampleAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> > trace_t; + + SampleStatHandle(const char* name, const char* description = NULL) + : trace_t(name, description) + {} +}; + +template<typename T, typename VALUE_T> +void sample(SampleStatHandle<T>& measurement, VALUE_T value) +{ + T converted_value(value); + measurement.getPrimaryAccumulator()->sample(LLUnits::rawValue(converted_value)); +} template <typename T = F64> class CountStatHandle @@ -560,6 +736,8 @@ struct MemStatAccumulator mDeallocatedCount = 0; } + void flush() {} + size_t mSize, mChildSize; int mAllocatedCount, diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp index cced6546ba..5b0b74524f 100644 --- a/indra/llcommon/lltracerecording.cpp +++ b/indra/llcommon/lltracerecording.cpp @@ -45,9 +45,11 @@ RecordingBuffers::RecordingBuffers() void RecordingBuffers::handOffTo(RecordingBuffers& other) { other.mCountsFloat.reset(&mCountsFloat); - other.mMeasurementsFloat.reset(&mMeasurementsFloat); other.mCounts.reset(&mCounts); - other.mMeasurements.reset(&mMeasurements); + other.mSamplesFloat.reset(&mSamplesFloat); + other.mSamples.reset(&mSamples); + other.mEventsFloat.reset(&mEventsFloat); + other.mEvents.reset(&mEvents); other.mStackTimers.reset(&mStackTimers); other.mMemStats.reset(&mMemStats); } @@ -55,9 +57,11 @@ void RecordingBuffers::handOffTo(RecordingBuffers& other) void RecordingBuffers::makePrimary() { mCountsFloat.makePrimary(); - mMeasurementsFloat.makePrimary(); mCounts.makePrimary(); - mMeasurements.makePrimary(); + mSamplesFloat.makePrimary(); + mSamples.makePrimary(); + mEventsFloat.makePrimary(); + mEvents.makePrimary(); mStackTimers.makePrimary(); mMemStats.makePrimary(); @@ -82,9 +86,11 @@ bool RecordingBuffers::isPrimary() const void RecordingBuffers::append( const RecordingBuffers& other ) { mCountsFloat.addSamples(other.mCountsFloat); - mMeasurementsFloat.addSamples(other.mMeasurementsFloat); mCounts.addSamples(other.mCounts); - mMeasurements.addSamples(other.mMeasurements); + mSamplesFloat.addSamples(other.mSamplesFloat); + mSamples.addSamples(other.mSamples); + mEventsFloat.addSamples(other.mEventsFloat); + mEvents.addSamples(other.mEvents); mMemStats.addSamples(other.mMemStats); mStackTimers.addSamples(other.mStackTimers); } @@ -92,22 +98,32 @@ void RecordingBuffers::append( const RecordingBuffers& other ) void RecordingBuffers::merge( const RecordingBuffers& other) { mCountsFloat.addSamples(other.mCountsFloat); - mMeasurementsFloat.addSamples(other.mMeasurementsFloat); mCounts.addSamples(other.mCounts); - mMeasurements.addSamples(other.mMeasurements); + mSamplesFloat.addSamples(other.mSamplesFloat); + mSamples.addSamples(other.mSamples); + mEventsFloat.addSamples(other.mEventsFloat); + mEvents.addSamples(other.mEvents); mMemStats.addSamples(other.mMemStats); } void RecordingBuffers::reset(RecordingBuffers* other) { mCountsFloat.reset(other ? &other->mCountsFloat : NULL); - mMeasurementsFloat.reset(other ? &other->mMeasurementsFloat : NULL); mCounts.reset(other ? &other->mCounts : NULL); - mMeasurements.reset(other ? &other->mMeasurements : NULL); + mSamplesFloat.reset(other ? &other->mSamplesFloat : NULL); + mSamples.reset(other ? &other->mSamples : NULL); + mEventsFloat.reset(other ? &other->mEventsFloat : NULL); + mEvents.reset(other ? &other->mEvents : NULL); mStackTimers.reset(other ? &other->mStackTimers : NULL); mMemStats.reset(other ? &other->mMemStats : NULL); } +void RecordingBuffers::flush() +{ + mSamplesFloat.flush(); + mSamples.flush(); +} + /////////////////////////////////////////////////////////////////////// // Recording /////////////////////////////////////////////////////////////////////// @@ -120,6 +136,9 @@ Recording::Recording() Recording::Recording( const Recording& other ) { + // this will allow us to seamlessly start without affecting any data we've acquired from other + setPlayState(PAUSED); + Recording& mutable_other = const_cast<Recording&>(other); EPlayState other_play_state = other.getPlayState(); mutable_other.pause(); @@ -137,15 +156,18 @@ Recording::Recording( const Recording& other ) Recording::~Recording() { - stop(); - llassert(isStopped()); + if (isStarted() && LLTrace::get_thread_recorder().notNull()) + { + LLTrace::get_thread_recorder()->deactivate(this); + } } void Recording::update() { if (isStarted()) { - LLTrace::get_thread_recorder()->update(this); + mBuffers.write()->flush(); + LLTrace::get_thread_recorder()->bringUpToDate(this); mSamplingTimer.reset(); } } @@ -167,6 +189,7 @@ void Recording::handleStart() void Recording::handleStop() { mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); + mBuffers.write()->flush(); LLTrace::TimeBlock::processTimes(); LLTrace::get_thread_recorder()->deactivate(this); } @@ -178,13 +201,23 @@ void Recording::handleSplitTo(Recording& other) void Recording::appendRecording( const Recording& other ) { - mBuffers.write()->append(*other.mBuffers); - mElapsedSeconds += other.mElapsedSeconds; + EPlayState play_state = getPlayState(); + { + pause(); + mBuffers.write()->append(*other.mBuffers); + mElapsedSeconds += other.mElapsedSeconds; + } + setPlayState(play_state); } void Recording::mergeRecording( const Recording& other) { - mBuffers.write()->merge(*other.mBuffers); + EPlayState play_state = getPlayState(); + { + pause(); + mBuffers.write()->merge(*other.mBuffers); + } + setPlayState(play_state); } LLUnit<LLUnits::Seconds, F64> Recording::getSum(const TraceType<TimeBlockAccumulator>& stat) const @@ -248,14 +281,14 @@ S64 Recording::getSum( const TraceType<CountAccumulator<S64> >& stat ) const return mBuffers->mCounts[stat.getIndex()].getSum(); } -F64 Recording::getSum( const TraceType<MeasurementAccumulator<F64> >& stat ) const +F64 Recording::getSum( const TraceType<EventAccumulator<F64> >& stat ) const { - return (F64)mBuffers->mMeasurementsFloat[stat.getIndex()].getSum(); + return (F64)mBuffers->mEventsFloat[stat.getIndex()].getSum(); } -S64 Recording::getSum( const TraceType<MeasurementAccumulator<S64> >& stat ) const +S64 Recording::getSum( const TraceType<EventAccumulator<S64> >& stat ) const { - return (S64)mBuffers->mMeasurements[stat.getIndex()].getSum(); + return (S64)mBuffers->mEvents[stat.getIndex()].getSum(); } @@ -283,67 +316,127 @@ U32 Recording::getSampleCount( const TraceType<CountAccumulator<F64> >& stat ) c U32 Recording::getSampleCount( const TraceType<CountAccumulator<S64> >& stat ) const { - return mBuffers->mMeasurementsFloat[stat.getIndex()].getSampleCount(); + return mBuffers->mCounts[stat.getIndex()].getSampleCount(); +} + +F64 Recording::getMin( const TraceType<SampleAccumulator<F64> >& stat ) const +{ + return mBuffers->mSamplesFloat[stat.getIndex()].getMin(); +} + +S64 Recording::getMin( const TraceType<SampleAccumulator<S64> >& stat ) const +{ + return mBuffers->mSamples[stat.getIndex()].getMin(); +} + +F64 Recording::getMax( const TraceType<SampleAccumulator<F64> >& stat ) const +{ + return mBuffers->mSamplesFloat[stat.getIndex()].getMax(); +} + +S64 Recording::getMax( const TraceType<SampleAccumulator<S64> >& stat ) const +{ + return mBuffers->mSamples[stat.getIndex()].getMax(); +} + +F64 Recording::getMean( const TraceType<SampleAccumulator<F64> >& stat ) const +{ + return mBuffers->mSamplesFloat[stat.getIndex()].getMean(); +} + +F64 Recording::getMean( const TraceType<SampleAccumulator<S64> >& stat ) const +{ + return mBuffers->mSamples[stat.getIndex()].getMean(); } -F64 Recording::getMin( const TraceType<MeasurementAccumulator<F64> >& stat ) const +F64 Recording::getStandardDeviation( const TraceType<SampleAccumulator<F64> >& stat ) const { - return mBuffers->mMeasurementsFloat[stat.getIndex()].getMin(); + return mBuffers->mSamplesFloat[stat.getIndex()].getStandardDeviation(); } -S64 Recording::getMin( const TraceType<MeasurementAccumulator<S64> >& stat ) const +F64 Recording::getStandardDeviation( const TraceType<SampleAccumulator<S64> >& stat ) const { - return mBuffers->mMeasurements[stat.getIndex()].getMin(); + return mBuffers->mSamples[stat.getIndex()].getStandardDeviation(); } -F64 Recording::getMax( const TraceType<MeasurementAccumulator<F64> >& stat ) const +F64 Recording::getLastValue( const TraceType<SampleAccumulator<F64> >& stat ) const { - return mBuffers->mMeasurementsFloat[stat.getIndex()].getMax(); + return mBuffers->mSamplesFloat[stat.getIndex()].getLastValue(); } -S64 Recording::getMax( const TraceType<MeasurementAccumulator<S64> >& stat ) const +S64 Recording::getLastValue( const TraceType<SampleAccumulator<S64> >& stat ) const { - return mBuffers->mMeasurements[stat.getIndex()].getMax(); + return mBuffers->mSamples[stat.getIndex()].getLastValue(); } -F64 Recording::getMean( const TraceType<MeasurementAccumulator<F64> >& stat ) const +U32 Recording::getSampleCount( const TraceType<SampleAccumulator<F64> >& stat ) const { - return mBuffers->mMeasurementsFloat[stat.getIndex()].getMean(); + return mBuffers->mSamplesFloat[stat.getIndex()].getSampleCount(); } -F64 Recording::getMean( const TraceType<MeasurementAccumulator<S64> >& stat ) const +U32 Recording::getSampleCount( const TraceType<SampleAccumulator<S64> >& stat ) const { - return mBuffers->mMeasurements[stat.getIndex()].getMean(); + return mBuffers->mSamples[stat.getIndex()].getSampleCount(); } -F64 Recording::getStandardDeviation( const TraceType<MeasurementAccumulator<F64> >& stat ) const +F64 Recording::getMin( const TraceType<EventAccumulator<F64> >& stat ) const { - return mBuffers->mMeasurementsFloat[stat.getIndex()].getStandardDeviation(); + return mBuffers->mEventsFloat[stat.getIndex()].getMin(); } -F64 Recording::getStandardDeviation( const TraceType<MeasurementAccumulator<S64> >& stat ) const +S64 Recording::getMin( const TraceType<EventAccumulator<S64> >& stat ) const { - return mBuffers->mMeasurements[stat.getIndex()].getStandardDeviation(); + return mBuffers->mEvents[stat.getIndex()].getMin(); } -F64 Recording::getLastValue( const TraceType<MeasurementAccumulator<F64> >& stat ) const +F64 Recording::getMax( const TraceType<EventAccumulator<F64> >& stat ) const { - return mBuffers->mMeasurementsFloat[stat.getIndex()].getLastValue(); + return mBuffers->mEventsFloat[stat.getIndex()].getMax(); } -S64 Recording::getLastValue( const TraceType<MeasurementAccumulator<S64> >& stat ) const +S64 Recording::getMax( const TraceType<EventAccumulator<S64> >& stat ) const { - return mBuffers->mMeasurements[stat.getIndex()].getLastValue(); + return mBuffers->mEvents[stat.getIndex()].getMax(); } -U32 Recording::getSampleCount( const TraceType<MeasurementAccumulator<F64> >& stat ) const +F64 Recording::getMean( const TraceType<EventAccumulator<F64> >& stat ) const { - return mBuffers->mMeasurementsFloat[stat.getIndex()].getSampleCount(); + return mBuffers->mEventsFloat[stat.getIndex()].getMean(); } -U32 Recording::getSampleCount( const TraceType<MeasurementAccumulator<S64> >& stat ) const +F64 Recording::getMean( const TraceType<EventAccumulator<S64> >& stat ) const { - return mBuffers->mMeasurements[stat.getIndex()].getSampleCount(); + return mBuffers->mEvents[stat.getIndex()].getMean(); +} + +F64 Recording::getStandardDeviation( const TraceType<EventAccumulator<F64> >& stat ) const +{ + return mBuffers->mEventsFloat[stat.getIndex()].getStandardDeviation(); +} + +F64 Recording::getStandardDeviation( const TraceType<EventAccumulator<S64> >& stat ) const +{ + return mBuffers->mEvents[stat.getIndex()].getStandardDeviation(); +} + +F64 Recording::getLastValue( const TraceType<EventAccumulator<F64> >& stat ) const +{ + return mBuffers->mEventsFloat[stat.getIndex()].getLastValue(); +} + +S64 Recording::getLastValue( const TraceType<EventAccumulator<S64> >& stat ) const +{ + return mBuffers->mEvents[stat.getIndex()].getLastValue(); +} + +U32 Recording::getSampleCount( const TraceType<EventAccumulator<F64> >& stat ) const +{ + return mBuffers->mEventsFloat[stat.getIndex()].getSampleCount(); +} + +U32 Recording::getSampleCount( const TraceType<EventAccumulator<S64> >& stat ) const +{ + return mBuffers->mEvents[stat.getIndex()].getSampleCount(); } /////////////////////////////////////////////////////////////////////// @@ -377,7 +470,7 @@ void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other ) if (other.mRecordingPeriods.empty()) return; EPlayState play_state = getPlayState(); - stop(); + pause(); EPlayState other_play_state = other.getPlayState(); other.pause(); @@ -466,8 +559,7 @@ LLTrace::Recording PeriodicRecording::snapshotCurRecording() const Recording& PeriodicRecording::getLastRecording() { - U32 num_periods = mRecordingPeriods.size(); - return mRecordingPeriods[(mCurPeriod + num_periods - 1) % num_periods]; + return getPrevRecording(1); } const Recording& PeriodicRecording::getLastRecording() const diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h index b339e72e5c..19a4fae737 100644 --- a/indra/llcommon/lltracerecording.h +++ b/indra/llcommon/lltracerecording.h @@ -117,11 +117,14 @@ namespace LLTrace void append(const RecordingBuffers& other); void merge(const RecordingBuffers& other); void reset(RecordingBuffers* other = NULL); + void flush(); AccumulatorBuffer<CountAccumulator<F64> > mCountsFloat; - AccumulatorBuffer<MeasurementAccumulator<F64> > mMeasurementsFloat; AccumulatorBuffer<CountAccumulator<S64> > mCounts; - AccumulatorBuffer<MeasurementAccumulator<S64> > mMeasurements; + AccumulatorBuffer<SampleAccumulator<F64> > mSamplesFloat; + AccumulatorBuffer<SampleAccumulator<S64> > mSamples; + AccumulatorBuffer<EventAccumulator<F64> > mEventsFloat; + AccumulatorBuffer<EventAccumulator<S64> > mEvents; AccumulatorBuffer<TimeBlockAccumulator> mStackTimers; AccumulatorBuffer<MemStatAccumulator> mMemStats; }; @@ -181,57 +184,101 @@ namespace LLTrace U32 getSampleCount(const TraceType<CountAccumulator<S64> >& stat) const; - // MeasurementStatHandle accessors - F64 getSum(const TraceType<MeasurementAccumulator<F64> >& stat) const; - S64 getSum(const TraceType<MeasurementAccumulator<S64> >& stat) const; + // SampleStatHandle accessors + F64 getMin(const TraceType<SampleAccumulator<F64> >& stat) const; + S64 getMin(const TraceType<SampleAccumulator<S64> >& stat) const; template <typename T> - T getSum(const MeasurementStatHandle<T>& stat) const + T getMin(const SampleStatHandle<T>& stat) const { - return (T)getSum(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat)); + return (T)getMin(static_cast<const TraceType<SampleAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat)); } - F64 getMin(const TraceType<MeasurementAccumulator<F64> >& stat) const; - S64 getMin(const TraceType<MeasurementAccumulator<S64> >& stat) const; + F64 getMax(const TraceType<SampleAccumulator<F64> >& stat) const; + S64 getMax(const TraceType<SampleAccumulator<S64> >& stat) const; template <typename T> - T getMin(const MeasurementStatHandle<T>& stat) const + T getMax(const SampleStatHandle<T>& stat) const { - return (T)getMin(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat)); + return (T)getMax(static_cast<const TraceType<SampleAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat)); } - F64 getMax(const TraceType<MeasurementAccumulator<F64> >& stat) const; - S64 getMax(const TraceType<MeasurementAccumulator<S64> >& stat) const; + F64 getMean(const TraceType<SampleAccumulator<F64> >& stat) const; + F64 getMean(const TraceType<SampleAccumulator<S64> >& stat) const; template <typename T> - T getMax(const MeasurementStatHandle<T>& stat) const + T getMean(SampleStatHandle<T>& stat) const { - return (T)getMax(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat)); + return (T)getMean(static_cast<const TraceType<SampleAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat)); } - F64 getMean(const TraceType<MeasurementAccumulator<F64> >& stat) const; - F64 getMean(const TraceType<MeasurementAccumulator<S64> >& stat) const; + F64 getStandardDeviation(const TraceType<SampleAccumulator<F64> >& stat) const; + F64 getStandardDeviation(const TraceType<SampleAccumulator<S64> >& stat) const; template <typename T> - T getMean(MeasurementStatHandle<T>& stat) const + T getStandardDeviation(const SampleStatHandle<T>& stat) const { - return (T)getMean(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat)); + return (T)getStandardDeviation(static_cast<const TraceType<SampleAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat)); } - F64 getStandardDeviation(const TraceType<MeasurementAccumulator<F64> >& stat) const; - F64 getStandardDeviation(const TraceType<MeasurementAccumulator<S64> >& stat) const; + F64 getLastValue(const TraceType<SampleAccumulator<F64> >& stat) const; + S64 getLastValue(const TraceType<SampleAccumulator<S64> >& stat) const; template <typename T> - T getStandardDeviation(const MeasurementStatHandle<T>& stat) const + T getLastValue(const SampleStatHandle<T>& stat) const { - return (T)getMean(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat)); + return (T)getLastValue(static_cast<const TraceType<SampleAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat)); } - F64 getLastValue(const TraceType<MeasurementAccumulator<F64> >& stat) const; - S64 getLastValue(const TraceType<MeasurementAccumulator<S64> >& stat) const; + U32 getSampleCount(const TraceType<SampleAccumulator<F64> >& stat) const; + U32 getSampleCount(const TraceType<SampleAccumulator<S64> >& stat) const; + + // EventStatHandle accessors + F64 getSum(const TraceType<EventAccumulator<F64> >& stat) const; + S64 getSum(const TraceType<EventAccumulator<S64> >& stat) const; + template <typename T> + T getSum(const EventStatHandle<T>& stat) const + { + return (T)getSum(static_cast<const TraceType<EventAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat)); + } + + F64 getMin(const TraceType<EventAccumulator<F64> >& stat) const; + S64 getMin(const TraceType<EventAccumulator<S64> >& stat) const; + template <typename T> + T getMin(const EventStatHandle<T>& stat) const + { + return (T)getMin(static_cast<const TraceType<EventAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat)); + } + + F64 getMax(const TraceType<EventAccumulator<F64> >& stat) const; + S64 getMax(const TraceType<EventAccumulator<S64> >& stat) const; + template <typename T> + T getMax(const EventStatHandle<T>& stat) const + { + return (T)getMax(static_cast<const TraceType<EventAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat)); + } + + F64 getMean(const TraceType<EventAccumulator<F64> >& stat) const; + F64 getMean(const TraceType<EventAccumulator<S64> >& stat) const; + template <typename T> + T getMean(EventStatHandle<T>& stat) const + { + return (T)getMean(static_cast<const TraceType<EventAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat)); + } + + F64 getStandardDeviation(const TraceType<EventAccumulator<F64> >& stat) const; + F64 getStandardDeviation(const TraceType<EventAccumulator<S64> >& stat) const; + template <typename T> + T getStandardDeviation(const EventStatHandle<T>& stat) const + { + return (T)getStandardDeviation(static_cast<const TraceType<EventAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat)); + } + + F64 getLastValue(const TraceType<EventAccumulator<F64> >& stat) const; + S64 getLastValue(const TraceType<EventAccumulator<S64> >& stat) const; template <typename T> - T getLastValue(const MeasurementStatHandle<T>& stat) const + T getLastValue(const EventStatHandle<T>& stat) const { - return (T)getLastValue(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat)); + return (T)getLastValue(static_cast<const TraceType<EventAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat)); } - U32 getSampleCount(const TraceType<MeasurementAccumulator<F64> >& stat) const; - U32 getSampleCount(const TraceType<MeasurementAccumulator<S64> >& stat) const; + U32 getSampleCount(const TraceType<EventAccumulator<F64> >& stat) const; + U32 getSampleCount(const TraceType<EventAccumulator<S64> >& stat) const; LLUnit<LLUnits::Seconds, F64> getDuration() const { return LLUnit<LLUnits::Seconds, F64>(mElapsedSeconds); } @@ -272,13 +319,14 @@ namespace LLTrace const Recording& getPrevRecording(U32 offset) const; Recording snapshotCurRecording() const; + // catch all for stats that have a defined sum template <typename T> typename T::value_t getPeriodMin(const TraceType<T>& stat, size_t num_periods = U32_MAX) const { size_t total_periods = mRecordingPeriods.size(); num_periods = llmin(num_periods, total_periods); - typename T::value_t min_val = (std::numeric_limits<typename T::value_t>::max)(); + typename T::value_t min_val = std::numeric_limits<typename T::value_t>::max(); for (S32 i = 1; i <= num_periods; i++) { S32 index = (mCurPeriod + total_periods - i) % total_periods; @@ -288,12 +336,42 @@ namespace LLTrace } template <typename T> + typename T getPeriodMin(const TraceType<SampleAccumulator<T> >& stat, size_t num_periods = U32_MAX) const + { + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, total_periods); + + typename T min_val = std::numeric_limits<T>::max(); + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + min_val = llmin(min_val, mRecordingPeriods[index].getMin(stat)); + } + return min_val; + } + + template <typename T> + typename T getPeriodMin(const TraceType<EventAccumulator<T> >& stat, size_t num_periods = U32_MAX) const + { + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, total_periods); + + typename T min_val = std::numeric_limits<T>::max(); + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + min_val = llmin(min_val, mRecordingPeriods[index].getMin(stat)); + } + return min_val; + } + + template <typename T> F64 getPeriodMinPerSec(const TraceType<T>& stat, size_t num_periods = U32_MAX) const { size_t total_periods = mRecordingPeriods.size(); num_periods = llmin(num_periods, total_periods); - F64 min_val = (std::numeric_limits<F64>::max)(); + F64 min_val = std::numeric_limits<F64>::max(); for (S32 i = 1; i <= num_periods; i++) { S32 index = (mCurPeriod + total_periods - i) % total_periods; @@ -302,13 +380,14 @@ namespace LLTrace return min_val; } + // catch all for stats that have a defined sum template <typename T> typename T::value_t getPeriodMax(const TraceType<T>& stat, size_t num_periods = U32_MAX) const { size_t total_periods = mRecordingPeriods.size(); num_periods = llmin(num_periods, total_periods); - typename T::value_t max_val = (std::numeric_limits<typename T::value_t>::min)(); + typename T::value_t max_val = std::numeric_limits<typename T::value_t>::min(); for (S32 i = 1; i <= num_periods; i++) { S32 index = (mCurPeriod + total_periods - i) % total_periods; @@ -318,12 +397,42 @@ namespace LLTrace } template <typename T> + typename T getPeriodMax(const TraceType<SampleAccumulator<T> >& stat, size_t num_periods = U32_MAX) const + { + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, total_periods); + + typename T max_val = std::numeric_limits<T>::min(); + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + max_val = llmax(max_val, mRecordingPeriods[index].getMax(stat)); + } + return max_val; + } + + template <typename T> + typename T getPeriodMax(const TraceType<EventAccumulator<T> >& stat, size_t num_periods = U32_MAX) const + { + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, total_periods); + + typename T max_val = std::numeric_limits<T>::min(); + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + max_val = llmax(max_val, mRecordingPeriods[index].getMax(stat)); + } + return max_val; + } + + template <typename T> F64 getPeriodMaxPerSec(const TraceType<T>& stat, size_t num_periods = U32_MAX) const { size_t total_periods = mRecordingPeriods.size(); num_periods = llmin(num_periods, total_periods); - F64 max_val = (std::numeric_limits<F64>::min)(); + F64 max_val = std::numeric_limits<F64>::min(); for (S32 i = 1; i <= num_periods; i++) { S32 index = (mCurPeriod + total_periods - i) % total_periods; @@ -332,13 +441,14 @@ namespace LLTrace return max_val; } + // catch all for stats that have a defined sum template <typename T> - typename T::mean_t getPeriodMean(const TraceType<T>& stat, size_t num_periods = U32_MAX) const + typename T::mean_t getPeriodMean(const TraceType<T >& stat, size_t num_periods = U32_MAX) const { size_t total_periods = mRecordingPeriods.size(); num_periods = llmin(num_periods, total_periods); - typename T::mean_t mean = typename T::mean_t(); + typename T::mean_t mean = 0; if (num_periods <= 0) { return mean; } for (S32 i = 1; i <= num_periods; i++) @@ -349,7 +459,65 @@ namespace LLTrace mean += mRecordingPeriods[index].getSum(stat); } } - mean /= num_periods; + mean = mean / num_periods; + return mean; + } + + template <typename T> + typename SampleAccumulator<T>::mean_t getPeriodMean(const TraceType<SampleAccumulator<T> >& stat, size_t num_periods = U32_MAX) const + { + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, total_periods); + + LLUnit<LLUnits::Seconds, F64> total_duration = 0.f; + + typename SampleAccumulator<T>::mean_t mean = 0; + if (num_periods <= 0) { return mean; } + + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + if (mRecordingPeriods[index].getDuration() > 0.f) + { + LLUnit<LLUnits::Seconds, F64> recording_duration = mRecordingPeriods[index].getDuration(); + mean += mRecordingPeriods[index].getMean(stat) * recording_duration.value(); + total_duration += recording_duration; + } + } + + if (total_duration.value()) + { + mean = mean / total_duration; + } + return mean; + } + + template <typename T> + typename EventAccumulator<T>::mean_t getPeriodMean(const TraceType<EventAccumulator<T> >& stat, size_t num_periods = U32_MAX) const + { + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, total_periods); + + typename EventAccumulator<T>::mean_t mean = 0; + if (num_periods <= 0) { return mean; } + + S32 total_sample_count = 0; + + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + if (mRecordingPeriods[index].getDuration() > 0.f) + { + S32 period_sample_count = mRecordingPeriods[index].getSampleCount(stat); + mean += mRecordingPeriods[index].getMean(stat) * period_sample_count; + total_sample_count += period_sample_count; + } + } + + if (total_sample_count) + { + mean = mean / total_sample_count; + } return mean; } @@ -359,7 +527,7 @@ namespace LLTrace size_t total_periods = mRecordingPeriods.size(); num_periods = llmin(num_periods, total_periods); - typename T::mean_t mean = typename T::mean_t(); + typename T::mean_t mean = 0; if (num_periods <= 0) { return mean; } for (S32 i = 1; i <= num_periods; i++) @@ -370,7 +538,7 @@ namespace LLTrace mean += mRecordingPeriods[index].getPerSec(stat); } } - mean /= num_periods; + mean = mean / num_periods; return mean; } diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp index 2001b9cd7f..75c7cb2ff1 100644 --- a/indra/llcommon/lltracethreadrecorder.cpp +++ b/indra/llcommon/lltracethreadrecorder.cpp @@ -74,10 +74,12 @@ ThreadRecorder::~ThreadRecorder() { delete mRootTimer; - while(mActiveRecordings.size()) + if (!mActiveRecordings.empty()) { - mActiveRecordings.front()->mTargetRecording->stop(); + std::for_each(mActiveRecordings.begin(), mActiveRecordings.end(), DeletePointer()); + mActiveRecordings.clear(); } + set_thread_recorder(NULL); delete[] mTimeBlockTreeNodes; } @@ -97,34 +99,40 @@ void ThreadRecorder::activate( Recording* recording ) ActiveRecording* active_recording = new ActiveRecording(recording); if (!mActiveRecordings.empty()) { - mActiveRecordings.front()->mPartialRecording.handOffTo(active_recording->mPartialRecording); + mActiveRecordings.back()->mPartialRecording.handOffTo(active_recording->mPartialRecording); } - mActiveRecordings.push_front(active_recording); + mActiveRecordings.push_back(active_recording); - mActiveRecordings.front()->mPartialRecording.makePrimary(); + mActiveRecordings.back()->mPartialRecording.makePrimary(); } -ThreadRecorder::active_recording_list_t::iterator ThreadRecorder::update( Recording* recording ) +ThreadRecorder::active_recording_list_t::reverse_iterator ThreadRecorder::bringUpToDate( Recording* recording ) { - active_recording_list_t::iterator it, end_it; - for (it = mActiveRecordings.begin(), end_it = mActiveRecordings.end(); + if (mActiveRecordings.empty()) return mActiveRecordings.rend(); + + mActiveRecordings.back()->mPartialRecording.flush(); + + active_recording_list_t::reverse_iterator it, end_it; + for (it = mActiveRecordings.rbegin(), end_it = mActiveRecordings.rend(); it != end_it; ++it) { - active_recording_list_t::iterator next_it = it; + ActiveRecording* cur_recording = *it; + + active_recording_list_t::reverse_iterator next_it = it; ++next_it; // if we have another recording further down in the stack... - if (next_it != mActiveRecordings.end()) + if (next_it != mActiveRecordings.rend()) { // ...push our gathered data down to it - (*next_it)->mPartialRecording.append((*it)->mPartialRecording); + (*next_it)->mPartialRecording.append(cur_recording->mPartialRecording); } // copy accumulated measurements into result buffer and clear accumulator (mPartialRecording) - (*it)->moveBaselineToTarget(); + cur_recording->movePartialToTarget(); - if ((*it)->mTargetRecording == recording) + if (cur_recording->mTargetRecording == recording) { // found the recording, so return it break; @@ -139,28 +147,30 @@ ThreadRecorder::active_recording_list_t::iterator ThreadRecorder::update( Record return it; } -AccumulatorBuffer<CountAccumulator<F64> > gCountsFloat; -AccumulatorBuffer<MeasurementAccumulator<F64> > gMeasurementsFloat; -AccumulatorBuffer<CountAccumulator<S64> > gCounts; -AccumulatorBuffer<MeasurementAccumulator<S64> > gMeasurements; -AccumulatorBuffer<TimeBlockAccumulator> gStackTimers; -AccumulatorBuffer<MemStatAccumulator> gMemStats; +AccumulatorBuffer<CountAccumulator<F64> > gCountsFloat; +AccumulatorBuffer<EventAccumulator<F64> > gMeasurementsFloat; +AccumulatorBuffer<CountAccumulator<S64> > gCounts; +AccumulatorBuffer<EventAccumulator<S64> > gMeasurements; +AccumulatorBuffer<TimeBlockAccumulator> gStackTimers; +AccumulatorBuffer<MemStatAccumulator> gMemStats; void ThreadRecorder::deactivate( Recording* recording ) { - active_recording_list_t::iterator it = update(recording); - if (it != mActiveRecordings.end()) + active_recording_list_t::reverse_iterator it = bringUpToDate(recording); + if (it != mActiveRecordings.rend()) { // and if we've found the recording we wanted to update - active_recording_list_t::iterator next_it = it; + active_recording_list_t::reverse_iterator next_it = it; ++next_it; - if (next_it != mActiveRecordings.end()) + if (next_it != mActiveRecordings.rend()) { - (*next_it)->mTargetRecording->mBuffers.write()->makePrimary(); + (*next_it)->mPartialRecording.makePrimary(); } - delete *it; - mActiveRecordings.erase(it); + active_recording_list_t::iterator recording_to_remove = (++it).base(); + llassert((*recording_to_remove)->mTargetRecording == recording); + delete *recording_to_remove; + mActiveRecordings.erase(recording_to_remove); } } @@ -169,10 +179,11 @@ ThreadRecorder::ActiveRecording::ActiveRecording( Recording* target ) { } -void ThreadRecorder::ActiveRecording::moveBaselineToTarget() +void ThreadRecorder::ActiveRecording::movePartialToTarget() { mTargetRecording->mBuffers.write()->append(mPartialRecording); - mPartialRecording.reset(); + // reset based on self to keep history + mPartialRecording.reset(&mPartialRecording); } @@ -180,21 +191,22 @@ void ThreadRecorder::ActiveRecording::moveBaselineToTarget() // SlaveThreadRecorder /////////////////////////////////////////////////////////////////////// -SlaveThreadRecorder::SlaveThreadRecorder() +SlaveThreadRecorder::SlaveThreadRecorder(MasterThreadRecorder& master) +: mMasterRecorder(master) { - getMasterThreadRecorder().addSlaveThread(this); + mMasterRecorder.addSlaveThread(this); } SlaveThreadRecorder::~SlaveThreadRecorder() { - getMasterThreadRecorder().removeSlaveThread(this); + mMasterRecorder.removeSlaveThread(this); } void SlaveThreadRecorder::pushToMaster() { mThreadRecording.stop(); { - LLMutexLock(getMasterThreadRecorder().getSlaveListMutex()); + LLMutexLock(mMasterRecorder.getSlaveListMutex()); mSharedData.appendFrom(mThreadRecording); } mThreadRecording.start(); @@ -243,7 +255,7 @@ void MasterThreadRecorder::pullFromSlaveThreads() LLMutexLock lock(&mSlaveListMutex); - RecordingBuffers& target_recording_buffers = mActiveRecordings.front()->mPartialRecording; + RecordingBuffers& target_recording_buffers = mActiveRecordings.back()->mPartialRecording; for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end(); it != end_it; ++it) diff --git a/indra/llcommon/lltracethreadrecorder.h b/indra/llcommon/lltracethreadrecorder.h index c44bcbd12d..17a2d4a9a9 100644 --- a/indra/llcommon/lltracethreadrecorder.h +++ b/indra/llcommon/lltracethreadrecorder.h @@ -39,15 +39,15 @@ namespace LLTrace { protected: struct ActiveRecording; - typedef std::list<ActiveRecording*> active_recording_list_t; + typedef std::vector<ActiveRecording*> active_recording_list_t; public: ThreadRecorder(); virtual ~ThreadRecorder(); void activate(Recording* recording); - active_recording_list_t::iterator update(Recording* recording); void deactivate(Recording* recording); + active_recording_list_t::reverse_iterator bringUpToDate(Recording* recording); virtual void pushToMaster() = 0; @@ -58,10 +58,10 @@ namespace LLTrace { ActiveRecording(Recording* target); - Recording* mTargetRecording; + Recording* mTargetRecording; RecordingBuffers mPartialRecording; - void moveBaselineToTarget(); + void movePartialToTarget(); }; Recording mThreadRecording; @@ -98,7 +98,7 @@ namespace LLTrace class LL_COMMON_API SlaveThreadRecorder : public ThreadRecorder { public: - SlaveThreadRecorder(); + SlaveThreadRecorder(MasterThreadRecorder& master); ~SlaveThreadRecorder(); // call this periodically to gather stats data for master thread to consume @@ -117,7 +117,8 @@ namespace LLTrace private: LLMutex mRecordingMutex; }; - SharedData mSharedData; + SharedData mSharedData; + MasterThreadRecorder& mMasterRecorder; }; } |