diff options
author | Richard Linden <none@none> | 2012-10-01 19:39:04 -0700 |
---|---|---|
committer | Richard Linden <none@none> | 2012-10-01 19:39:04 -0700 |
commit | 14b1b0b2bb6bac5bc688cc4d14c33f1b680dd3b4 (patch) | |
tree | 74942f4fef955b5a55031650146e745bbc4ccd6f /indra/llcommon | |
parent | b1baf982b1bd41a150233d0a28d3601226924c65 (diff) |
SH-3275 WIP Run viewer metrics for object update messages
cleaned up API
samplers are now value types with copy-on-write buffers under the hood
removed coupling with LLThread
Diffstat (limited to 'indra/llcommon')
-rw-r--r-- | indra/llcommon/llapr.cpp | 28 | ||||
-rw-r--r-- | indra/llcommon/llapr.h | 28 | ||||
-rw-r--r-- | indra/llcommon/llpointer.h | 83 | ||||
-rw-r--r-- | indra/llcommon/llqueuedthread.cpp | 2 | ||||
-rw-r--r-- | indra/llcommon/llthread.cpp | 15 | ||||
-rw-r--r-- | indra/llcommon/llthread.h | 9 | ||||
-rw-r--r-- | indra/llcommon/lltrace.cpp | 108 | ||||
-rw-r--r-- | indra/llcommon/lltrace.h | 180 | ||||
-rw-r--r-- | indra/llcommon/lltracesampler.cpp | 98 | ||||
-rw-r--r-- | indra/llcommon/lltracesampler.h | 59 |
10 files changed, 398 insertions, 212 deletions
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index e9930c10f7..d23b70690d 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -55,7 +55,7 @@ void ll_init_apr() LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE); } - LLThreadLocalPtrBase::initAllThreadLocalStorage(); + LLThreadLocalPointerBase::initAllThreadLocalStorage(); } @@ -80,7 +80,7 @@ void ll_cleanup_apr() gCallStacksLogMutexp = NULL; } - LLThreadLocalPtrBase::destroyAllThreadLocalStorage(); + LLThreadLocalPointerBase::destroyAllThreadLocalStorage(); if (gAPRPoolp) { @@ -482,11 +482,11 @@ S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset) } // -//LLThreadLocalPtrBase +//LLThreadLocalPointerBase // -bool LLThreadLocalPtrBase::sInitialized = false; +bool LLThreadLocalPointerBase::sInitialized = false; -LLThreadLocalPtrBase::LLThreadLocalPtrBase() +LLThreadLocalPointerBase::LLThreadLocalPointerBase() : mThreadKey(NULL) { if (sInitialized) @@ -495,7 +495,7 @@ LLThreadLocalPtrBase::LLThreadLocalPtrBase() } } -LLThreadLocalPtrBase::LLThreadLocalPtrBase( const LLThreadLocalPtrBase& other) +LLThreadLocalPointerBase::LLThreadLocalPointerBase( const LLThreadLocalPointerBase& other) : mThreadKey(NULL) { if (sInitialized) @@ -504,12 +504,12 @@ LLThreadLocalPtrBase::LLThreadLocalPtrBase( const LLThreadLocalPtrBase& other) } } -LLThreadLocalPtrBase::~LLThreadLocalPtrBase() +LLThreadLocalPointerBase::~LLThreadLocalPointerBase() { destroyStorage(); } -void LLThreadLocalPtrBase::set( void* value ) +void LLThreadLocalPointerBase::set( void* value ) { llassert(sInitialized && mThreadKey); @@ -521,7 +521,7 @@ void LLThreadLocalPtrBase::set( void* value ) } } -void LLThreadLocalPtrBase::initStorage( ) +void LLThreadLocalPointerBase::initStorage( ) { apr_status_t result = apr_threadkey_private_create(&mThreadKey, NULL, gAPRPoolp); if (result != APR_SUCCESS) @@ -531,7 +531,7 @@ void LLThreadLocalPtrBase::initStorage( ) } } -void LLThreadLocalPtrBase::destroyStorage() +void LLThreadLocalPointerBase::destroyStorage() { if (sInitialized) { @@ -547,11 +547,11 @@ void LLThreadLocalPtrBase::destroyStorage() } } -void LLThreadLocalPtrBase::initAllThreadLocalStorage() +void LLThreadLocalPointerBase::initAllThreadLocalStorage() { if (!sInitialized) { - for (LLInstanceTracker<LLThreadLocalPtrBase>::instance_iter it = beginInstances(), end_it = endInstances(); + for (LLInstanceTracker<LLThreadLocalPointerBase>::instance_iter it = beginInstances(), end_it = endInstances(); it != end_it; ++it) { @@ -561,11 +561,11 @@ void LLThreadLocalPtrBase::initAllThreadLocalStorage() } } -void LLThreadLocalPtrBase::destroyAllThreadLocalStorage() +void LLThreadLocalPointerBase::destroyAllThreadLocalStorage() { if (sInitialized) { - for (LLInstanceTracker<LLThreadLocalPtrBase>::instance_iter it = beginInstances(), end_it = endInstances(); + for (LLInstanceTracker<LLThreadLocalPointerBase>::instance_iter it = beginInstances(), end_it = endInstances(); it != end_it; ++it) { diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 4e704998c2..6efb44a663 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -258,12 +258,12 @@ public: //******************************************************************************************************************************* }; -class LLThreadLocalPtrBase : LLInstanceTracker<LLThreadLocalPtrBase> +class LLThreadLocalPointerBase : LLInstanceTracker<LLThreadLocalPointerBase> { public: - LLThreadLocalPtrBase(); - LLThreadLocalPtrBase(const LLThreadLocalPtrBase& other); - ~LLThreadLocalPtrBase(); + LLThreadLocalPointerBase(); + LLThreadLocalPointerBase(const LLThreadLocalPointerBase& other); + ~LLThreadLocalPointerBase(); static void initAllThreadLocalStorage(); static void destroyAllThreadLocalStorage(); @@ -307,35 +307,35 @@ protected: }; template <typename T> -class LLThreadLocalPtr : public LLThreadLocalPtrBase +class LLThreadLocalPointer : public LLThreadLocalPointerBase { public: - LLThreadLocalPtr() - : LLThreadLocalPtrBase() + LLThreadLocalPointer() + : LLThreadLocalPointerBase() {} - explicit LLThreadLocalPtr(T* value) - : LLThreadLocalPtrBase(&cleanup) + explicit LLThreadLocalPointer(T* value) + : LLThreadLocalPointerBase(&cleanup) { set(value); } - LLThreadLocalPtr(const LLThreadLocalPtr<T>& other) - : LLThreadLocalPtrBase(other, &cleanup) + LLThreadLocalPointer(const LLThreadLocalPointer<T>& other) + : LLThreadLocalPointerBase(other, &cleanup) { set(other.get()); } LL_FORCE_INLINE T* get() { - return (T*)LLThreadLocalPtrBase::get(); + return (T*)LLThreadLocalPointerBase::get(); } const T* get() const { - return (const T*)LLThreadLocalPtrBase::get(); + return (const T*)LLThreadLocalPointerBase::get(); } T* operator -> () @@ -358,7 +358,7 @@ public: return *(T*)get(); } - LLThreadLocalPtr<T>& operator = (T* value) + LLThreadLocalPointer<T>& operator = (T* value) { set((void*)value); return *this; diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index 88c09c8dca..0fee4f0990 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -97,24 +97,13 @@ public: LLPointer<Type>& operator =(Type* ptr) { - if( mPointer != ptr ) - { - unref(); - mPointer = ptr; - ref(); - } - + assign(ptr); return *this; } LLPointer<Type>& operator =(const LLPointer<Type>& ptr) { - if( mPointer != ptr.mPointer ) - { - unref(); - mPointer = ptr.mPointer; - ref(); - } + assign(ptr); return *this; } @@ -122,12 +111,7 @@ public: template<typename Subclass> LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr) { - if( mPointer != ptr.get() ) - { - unref(); - mPointer = ptr.get(); - ref(); - } + assign(ptr.get()); return *this; } @@ -144,6 +128,16 @@ protected: void ref(); void unref(); #else + + void assign(const LLPointer<Type>& ptr) + { + if( mPointer != ptr.mPointer ) + { + unref(); + mPointer = ptr.mPointer; + ref(); + } + } void ref() { if (mPointer) @@ -156,9 +150,9 @@ protected: { if (mPointer) { - Type *tempp = mPointer; + Type *temp = mPointer; mPointer = NULL; - tempp->unref(); + temp->unref(); if (mPointer != NULL) { llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl; @@ -171,4 +165,51 @@ protected: Type* mPointer; }; +template<typename Type> +class LLCopyOnWritePointer : public LLPointer<Type> +{ +public: + typedef LLPointer<Type> ref_pointer_t; + typedef LLCopyOnWritePointer<Type> self_t; + + LLCopyOnWritePointer() + { + } + + LLCopyOnWritePointer(Type* ptr) + : LLPointer(ptr) + { + } + + Type* write() + { + makeUnique(); + return mPointer; + } + + void makeUnique() + { + if (mPointer && mPointer->getNumRefs() > 1) + { + ref_pointer_t::assign(new Type(*mPointer)); + } + } + + using ref_pointer_t::operator BOOL; + using ref_pointer_t::operator bool; + using ref_pointer_t::operator!; + + using ref_pointer_t::operator !=; + using ref_pointer_t::operator ==; + using LLPointer<Type>::operator =; + + using LLPointer<Type>::operator <; + using LLPointer<Type>::operator >; + + + operator const Type*() const { return mPointer; } + const Type* operator->() const { return mPointer; } + +}; + #endif diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index 0a35474b7f..9aa449d037 100644 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -112,7 +112,7 @@ void LLQueuedThread::shutdown() // virtual S32 LLQueuedThread::update(F32 max_time_ms) { - LLThread::getTraceData()->pushToMaster(); + LLTrace::get_thread_trace()->pushToMaster(); if (!mStarted) { diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 7384842627..c705e5103b 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -67,7 +67,6 @@ U32 __thread LLThread::sThreadID = 0; #endif U32 LLThread::sIDIter = 0; -LLThreadLocalPtr<LLTrace::ThreadTrace> LLThread::sTraceData; LL_COMMON_API void assert_main_thread() @@ -86,7 +85,7 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap { LLThread *threadp = (LLThread *)datap; - setTraceData(new LLTrace::SlaveThreadTrace()); + LLTrace::ThreadTrace* thread_trace = new LLTrace::SlaveThreadTrace(); #if !LL_DARWIN sThreadIndex = threadp->mID; @@ -100,8 +99,7 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap // We're done with the run function, this thread is done executing now. threadp->mStatus = STOPPED; - delete sTraceData.get(); - sTraceData = NULL; + delete thread_trace; return NULL; } @@ -314,12 +312,3 @@ void LLThread::wakeLocked() } } -LLTrace::ThreadTrace* LLThread::getTraceData() -{ - return sTraceData.get(); -} - -void LLThread::setTraceData( LLTrace::ThreadTrace* data ) -{ - sTraceData = data; -} diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 334ea2f0da..82ab5f47d2 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -32,10 +32,6 @@ #include "apr_thread_cond.h" #include "llmutex.h" -namespace LLTrace -{ - class ThreadTrace; -} class LL_COMMON_API LLThread { private: @@ -91,9 +87,6 @@ public: U32 getID() const { return mID; } - static LLTrace::ThreadTrace* getTraceData(); - static void setTraceData(LLTrace::ThreadTrace* data); - private: BOOL mPaused; @@ -110,8 +103,6 @@ protected: EThreadStatus mStatus; U32 mID; - static LLThreadLocalPtr<LLTrace::ThreadTrace> sTraceData; - //a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used. //Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes. // otherwise it will cause severe memory leaking!!! --bao diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp index e487e450a9..04817fd4f4 100644 --- a/indra/llcommon/lltrace.cpp +++ b/indra/llcommon/lltrace.cpp @@ -27,7 +27,6 @@ #include "lltrace.h" #include "lltracesampler.h" -#include "llthread.h" namespace LLTrace { @@ -45,6 +44,12 @@ void cleanup() gMasterThreadTrace = NULL; } +LLThreadLocalPointer<ThreadTrace>& get_thread_trace() +{ + static LLThreadLocalPointer<ThreadTrace> s_trace_data; + return s_trace_data; + +} BlockTimer::Recorder::StackEntry BlockTimer::sCurRecorder; @@ -62,36 +67,52 @@ MasterThreadTrace& getMasterThreadTrace() ThreadTrace::ThreadTrace() { - mPrimarySampler = createSampler(); - mPrimarySampler->makePrimary(); - mPrimarySampler->start(); + get_thread_trace() = this; + mPrimarySampler.makePrimary(); + mTotalSampler.start(); } ThreadTrace::ThreadTrace( const ThreadTrace& other ) -: mPrimarySampler(new Sampler(*(other.mPrimarySampler))) +: mPrimarySampler(other.mPrimarySampler), + mTotalSampler(other.mTotalSampler) { - mPrimarySampler->makePrimary(); + get_thread_trace() = this; + mPrimarySampler.makePrimary(); + mTotalSampler.start(); } ThreadTrace::~ThreadTrace() { - delete mPrimarySampler; + get_thread_trace() = NULL; } +//TODO: remove this and use llviewerstats sampler Sampler* ThreadTrace::getPrimarySampler() { - return mPrimarySampler; + return &mPrimarySampler; } void ThreadTrace::activate( Sampler* sampler ) { - flushPrimary(); - mActiveSamplers.push_back(sampler); + for (std::list<Sampler*>::iterator it = mActiveSamplers.begin(), end_it = mActiveSamplers.end(); + it != end_it; + ++it) + { + (*it)->mMeasurements.write()->mergeSamples(*mPrimarySampler.mMeasurements); + } + mPrimarySampler.mMeasurements.write()->reset(); + + sampler->initDeltas(mPrimarySampler); + + mActiveSamplers.push_front(sampler); } +//TODO: consider merging results down the list to one past the buffered item. +// this would require 2 buffers per sampler, to separate current total from running total + void ThreadTrace::deactivate( Sampler* sampler ) { - sampler->mergeFrom(mPrimarySampler); + sampler->mergeDeltas(mPrimarySampler); // TODO: replace with intrusive list std::list<Sampler*>::iterator found_it = std::find(mActiveSamplers.begin(), mActiveSamplers.end(), sampler); @@ -101,31 +122,12 @@ void ThreadTrace::deactivate( Sampler* sampler ) } } -void ThreadTrace::flushPrimary() -{ - for (std::list<Sampler*>::iterator it = mActiveSamplers.begin(), end_it = mActiveSamplers.end(); - it != end_it; - ++it) - { - (*it)->mergeFrom(mPrimarySampler); - } - mPrimarySampler->reset(); -} - -Sampler* ThreadTrace::createSampler() -{ - return new Sampler(this); -} - - - /////////////////////////////////////////////////////////////////////// // SlaveThreadTrace /////////////////////////////////////////////////////////////////////// SlaveThreadTrace::SlaveThreadTrace() -: ThreadTrace(getMasterThreadTrace()), - mSharedData(createSampler()) +: ThreadTrace(getMasterThreadTrace()) { getMasterThreadTrace().addSlaveThread(this); } @@ -137,34 +139,26 @@ SlaveThreadTrace::~SlaveThreadTrace() void SlaveThreadTrace::pushToMaster() { - mSharedData.copyFrom(mPrimarySampler); -} - -void SlaveThreadTrace::SharedData::copyFrom( Sampler* source ) -{ - LLMutexLock lock(&mSamplerMutex); - { - mSampler->mergeFrom(source); + mTotalSampler.stop(); + { + LLMutexLock(getMasterThreadTrace().getSlaveListMutex()); + mSharedData.copyFrom(mTotalSampler); } + mTotalSampler.start(); } -void SlaveThreadTrace::SharedData::copyTo( Sampler* sink ) +void SlaveThreadTrace::SharedData::copyFrom( const Sampler& source ) { LLMutexLock lock(&mSamplerMutex); - { - sink->mergeFrom(mSampler); - } + mSampler.mergeSamples(source); } -SlaveThreadTrace::SharedData::~SharedData() +void SlaveThreadTrace::SharedData::copyTo( Sampler& sink ) { - delete mSampler; + LLMutexLock lock(&mSamplerMutex); + sink.mergeSamples(mSampler); } -SlaveThreadTrace::SharedData::SharedData( Sampler* sampler ) : mSampler(sampler) -{} - - @@ -188,7 +182,7 @@ void MasterThreadTrace::addSlaveThread( class SlaveThreadTrace* child ) { LLMutexLock lock(&mSlaveListMutex); - mSlaveThreadTraces.push_back(new SlaveThreadTraceProxy(child, createSampler())); + mSlaveThreadTraces.push_back(new SlaveThreadTraceProxy(child)); } void MasterThreadTrace::removeSlaveThread( class SlaveThreadTrace* child ) @@ -211,22 +205,14 @@ void MasterThreadTrace::pushToMaster() {} MasterThreadTrace::MasterThreadTrace() -{ - LLThread::setTraceData(this); -} +{} /////////////////////////////////////////////////////////////////////// // MasterThreadTrace::SlaveThreadTraceProxy /////////////////////////////////////////////////////////////////////// -MasterThreadTrace::SlaveThreadTraceProxy::SlaveThreadTraceProxy( class SlaveThreadTrace* trace, Sampler* storage ) -: mSlaveTrace(trace), - mSamplerStorage(storage) +MasterThreadTrace::SlaveThreadTraceProxy::SlaveThreadTraceProxy( class SlaveThreadTrace* trace) +: mSlaveTrace(trace) {} -MasterThreadTrace::SlaveThreadTraceProxy::~SlaveThreadTraceProxy() -{ - delete mSamplerStorage; -} - } diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h index c6f920b5e4..5ec1c821c3 100644 --- a/indra/llcommon/lltrace.h +++ b/indra/llcommon/lltrace.h @@ -33,6 +33,8 @@ #include "llmutex.h" #include "llmemory.h" #include "lltimer.h" +#include "llrefcount.h" +#include "lltracesampler.h" #include <list> @@ -48,11 +50,13 @@ namespace LLTrace void init(); void cleanup(); + LLThreadLocalPointer<class ThreadTrace>& get_thread_trace(); + class LL_COMMON_API MasterThreadTrace& getMasterThreadTrace(); // one per thread per type template<typename ACCUMULATOR> - class LL_COMMON_API AccumulatorBuffer + class LL_COMMON_API AccumulatorBuffer : public LLRefCount { static const U32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 64; private: @@ -88,13 +92,23 @@ namespace LLTrace return mStorage[index]; } - void mergeFrom(const AccumulatorBuffer<ACCUMULATOR>& other) + void mergeSamples(const AccumulatorBuffer<ACCUMULATOR>& other) { llassert(mNextStorageSlot == other.mNextStorageSlot); for (size_t i = 0; i < mNextStorageSlot; i++) { - mStorage[i].mergeFrom(other.mStorage[i]); + mStorage[i].mergeSamples(other.mStorage[i]); + } + } + + void mergeDeltas(const AccumulatorBuffer<ACCUMULATOR>& start, const AccumulatorBuffer<ACCUMULATOR>& finish) + { + llassert(mNextStorageSlot == start.mNextStorageSlot && mNextStorageSlot == finish.mNextStorageSlot); + + for (size_t i = 0; i < mNextStorageSlot; i++) + { + mStorage[i].mergeDeltas(start.mStorage[i], finish.mStorage[i]); } } @@ -119,6 +133,11 @@ namespace LLTrace sPrimaryStorage = mStorage; } + bool isPrimary() const + { + return sPrimaryStorage == mStorage; + } + LL_FORCE_INLINE static ACCUMULATOR* getPrimaryStorage() { return sPrimaryStorage.get(); @@ -149,9 +168,9 @@ namespace LLTrace ACCUMULATOR* mStorage; size_t mStorageSize; size_t mNextStorageSlot; - static LLThreadLocalPtr<ACCUMULATOR> sPrimaryStorage; + static LLThreadLocalPointer<ACCUMULATOR> sPrimaryStorage; }; - template<typename ACCUMULATOR> LLThreadLocalPtr<ACCUMULATOR> AccumulatorBuffer<ACCUMULATOR>::sPrimaryStorage; + template<typename ACCUMULATOR> LLThreadLocalPointer<ACCUMULATOR> AccumulatorBuffer<ACCUMULATOR>::sPrimaryStorage; template<typename ACCUMULATOR> class LL_COMMON_API TraceType @@ -168,7 +187,7 @@ namespace LLTrace return AccumulatorBuffer<ACCUMULATOR>::getPrimaryStorage()[mAccumulatorIndex]; } - ACCUMULATOR& getAccumulator(AccumulatorBuffer<ACCUMULATOR>& buffer) { return buffer[mAccumulatorIndex]; } + ACCUMULATOR& getAccumulator(AccumulatorBuffer<ACCUMULATOR>* buffer) { return (*buffer)[mAccumulatorIndex]; } protected: std::string mName; @@ -177,10 +196,10 @@ namespace LLTrace template<typename T> - class LL_COMMON_API StatAccumulator + class LL_COMMON_API MeasurementAccumulator { public: - StatAccumulator() + MeasurementAccumulator() : mSum(0), mMin(0), mMax(0), @@ -199,9 +218,12 @@ namespace LLTrace { mMax = value; } + F32 old_mean = mMean; + mMean += ((F32)value - old_mean) / (F32)mNumSamples; + mStandardDeviation += ((F32)value - old_mean) * ((F32)value - mMean); } - void mergeFrom(const StatAccumulator<T>& other) + void mergeSamples(const MeasurementAccumulator<T>& other) { mSum += other.mSum; if (other.mMin < mMin) @@ -213,6 +235,28 @@ namespace LLTrace mMax = other.mMax; } mNumSamples += other.mNumSamples; + F32 weight = (F32)mNumSamples / (F32)(mNumSamples + other.mNumSamples); + mMean = mMean * weight + other.mMean * (1.f - weight); + + F32 n_1 = (F32)mNumSamples, + n_2 = (F32)other.mNumSamples; + F32 m_1 = mMean, + m_2 = other.mMean; + F32 sd_1 = mStandardDeviation, + sd_2 = other.mStandardDeviation; + // 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 + F32 variance = ((((n_1 - 1.f) * sd_1 * sd_1) + + ((n_2 - 1.f) * sd_2 * sd_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)); + mStandardDeviation = sqrtf(variance); + } + + void mergeDeltas(const MeasurementAccumulator<T>& start, const MeasurementAccumulator<T>& finish) + { + llerrs << "Delta merge invalid for measurement accumulators" << llendl; } void reset() @@ -226,23 +270,68 @@ namespace LLTrace T getSum() { return mSum; } T getMin() { return mMin; } T getMax() { return mMax; } - T getMean() { return mSum / (T)mNumSamples; } + F32 getMean() { return mMean; } + F32 getStandardDeviation() { return mStandardDeviation; } private: T mSum, mMin, mMax; + F32 mMean, + mStandardDeviation; + + U32 mNumSamples; + }; + + template<typename T> + class LL_COMMON_API RateAccumulator + { + public: + RateAccumulator() + : mSum(0), + mNumSamples(0) + {} + + LL_FORCE_INLINE void add(T value) + { + mNumSamples++; + mSum += value; + } + + void mergeSamples(const RateAccumulator<T>& other) + { + mSum += other.mSum; + mNumSamples += other.mNumSamples; + } + + void mergeDeltas(const RateAccumulator<T>& start, const RateAccumulator<T>& finish) + { + mSum += finish.mSum - start.mSum; + mNumSamples += finish.mNumSamples - start.mNumSamples; + } + + void reset() + { + mNumSamples = 0; + mSum = 0; + } + + T getSum() { return mSum; } + + private: + T mSum; + U32 mNumSamples; }; template <typename T> - class LL_COMMON_API Stat - : public TraceType<StatAccumulator<T> >, - public LLInstanceTracker<Stat<T>, std::string> + class LL_COMMON_API Measurement + : public TraceType<MeasurementAccumulator<T> >, + public LLInstanceTracker<Measurement<T>, std::string> { public: - Stat(const std::string& name) + Measurement(const std::string& name) : TraceType(name), LLInstanceTracker(name) {} @@ -253,11 +342,30 @@ namespace LLTrace } }; - struct LL_COMMON_API TimerAccumulator + template <typename T> + class LL_COMMON_API Rate + : public TraceType<RateAccumulator<T> >, + public LLInstanceTracker<Rate<T>, std::string> { + public: + Rate(const std::string& name) + : TraceType(name), + LLInstanceTracker(name) + {} + + void add(T value) + { + getPrimaryAccumulator().add(value); + } + }; + + class LL_COMMON_API TimerAccumulator + { + public: U32 mTotalTimeCounter, mChildTimeCounter, mCalls; + TimerAccumulator* mParent; // info for caller timer TimerAccumulator* mLastCaller; // used to bootstrap tree construction const class BlockTimer* mTimer; // points to block timer associated with this storage @@ -265,13 +373,20 @@ namespace LLTrace bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame std::vector<TimerAccumulator*> mChildren; // currently assumed child timers - void mergeFrom(const TimerAccumulator& other) + void mergeSamples(const TimerAccumulator& other) { mTotalTimeCounter += other.mTotalTimeCounter; mChildTimeCounter += other.mChildTimeCounter; mCalls += other.mCalls; } + void mergeDeltas(const TimerAccumulator& start, const TimerAccumulator& finish) + { + mTotalTimeCounter += finish.mTotalTimeCounter - start.mTotalTimeCounter; + mChildTimeCounter += finish.mChildTimeCounter - start.mChildTimeCounter; + mCalls += finish.mCalls - start.mCalls; + } + void reset() { mTotalTimeCounter = 0; @@ -377,15 +492,13 @@ namespace LLTrace void activate(Sampler* sampler); void deactivate(Sampler* sampler); - void flushPrimary(); - - Sampler* createSampler(); virtual void pushToMaster() = 0; Sampler* getPrimarySampler(); protected: - Sampler* mPrimarySampler; + Sampler mPrimarySampler; + Sampler mTotalSampler; std::list<Sampler*> mActiveSamplers; }; @@ -402,14 +515,15 @@ namespace LLTrace // call this periodically to gather stats data from slave threads void pullFromSlaveThreads(); + LLMutex* getSlaveListMutex() { return &mSlaveListMutex; } + private: struct SlaveThreadTraceProxy { - SlaveThreadTraceProxy(class SlaveThreadTrace* trace, Sampler* storage); + SlaveThreadTraceProxy(class SlaveThreadTrace* trace); - ~SlaveThreadTraceProxy(); class SlaveThreadTrace* mSlaveTrace; - Sampler* mSamplerStorage; + Sampler mSamplerStorage; private: //no need to copy these and then have to duplicate the storage SlaveThreadTraceProxy(const SlaveThreadTraceProxy& other) {} @@ -431,24 +545,16 @@ namespace LLTrace MasterThreadTrace* mMaster; - // this data is accessed by other threads, so give it a 64 byte alignment - // to avoid false sharing on most x86 processors - LL_ALIGNED(64) class SharedData + class SharedData { public: - explicit - SharedData(Sampler* sampler); - - ~SharedData(); - - void copyFrom(Sampler* source); - void copyTo(Sampler* sink); + void copyFrom(const Sampler& source); + void copyTo(Sampler& sink); private: - // add a cache line's worth of unused space to avoid any potential of false sharing - LLMutex mSamplerMutex; - Sampler* mSampler; + LLMutex mSamplerMutex; + Sampler mSampler; }; - SharedData mSharedData; + SharedData mSharedData; }; } diff --git a/indra/llcommon/lltracesampler.cpp b/indra/llcommon/lltracesampler.cpp index 0cf01d7a3a..17e58b96e2 100644 --- a/indra/llcommon/lltracesampler.cpp +++ b/indra/llcommon/lltracesampler.cpp @@ -26,6 +26,8 @@ #include "linden_common.h" #include "lltracesampler.h" +#include "lltrace.h" +#include "llthread.h" namespace LLTrace { @@ -34,10 +36,14 @@ namespace LLTrace // Sampler /////////////////////////////////////////////////////////////////////// -Sampler::Sampler(ThreadTrace* thread_trace) +Sampler::Sampler() : mElapsedSeconds(0), mIsStarted(false), - mThreadTrace(thread_trace) + mRatesStart(new AccumulatorBuffer<RateAccumulator<F32> >()), + mRates(new AccumulatorBuffer<RateAccumulator<F32> >()), + mMeasurements(new AccumulatorBuffer<MeasurementAccumulator<F32> >()), + mStackTimers(new AccumulatorBuffer<TimerAccumulator>()), + mStackTimersStart(new AccumulatorBuffer<TimerAccumulator>()) { } @@ -53,9 +59,9 @@ void Sampler::start() void Sampler::reset() { - mF32Stats.reset(); - mS32Stats.reset(); - mStackTimers.reset(); + mRates.write()->reset(); + mMeasurements.write()->reset(); + mStackTimers.write()->reset(); mElapsedSeconds = 0.0; mSamplingTimer.reset(); @@ -66,7 +72,7 @@ void Sampler::resume() if (!mIsStarted) { mSamplingTimer.reset(); - getThreadTrace()->activate(this); + LLTrace::get_thread_trace()->activate(this); mIsStarted = true; } } @@ -76,28 +82,86 @@ void Sampler::stop() if (mIsStarted) { mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); - getThreadTrace()->deactivate(this); + LLTrace::get_thread_trace()->deactivate(this); mIsStarted = false; } } -ThreadTrace* Sampler::getThreadTrace() + +void Sampler::makePrimary() { - return mThreadTrace; + mRates.write()->makePrimary(); + mMeasurements.write()->makePrimary(); + mStackTimers.write()->makePrimary(); } -void Sampler::makePrimary() +bool Sampler::isPrimary() +{ + return mRates->isPrimary(); +} + +void Sampler::mergeSamples( const Sampler& other ) +{ + mRates.write()->mergeSamples(*other.mRates); + mMeasurements.write()->mergeSamples(*other.mMeasurements); + mStackTimers.write()->mergeSamples(*other.mStackTimers); +} + +void Sampler::initDeltas( const Sampler& other ) +{ + mRatesStart.write()->copyFrom(*other.mRates); + mStackTimersStart.write()->copyFrom(*other.mStackTimers); +} + + +void Sampler::mergeDeltas( const Sampler& other ) +{ + mRates.write()->mergeDeltas(*mRatesStart, *other.mRates); + mStackTimers.write()->mergeDeltas(*mStackTimersStart, *other.mStackTimers); + mMeasurements.write()->mergeSamples(*other.mMeasurements); +} + + +F32 Sampler::getSum( Rate<F32>& stat ) { - mF32Stats.makePrimary(); - mS32Stats.makePrimary(); - mStackTimers.makePrimary(); + return stat.getAccumulator(mRates).getSum(); } -void Sampler::mergeFrom( const Sampler* other ) +F32 Sampler::getSum( Measurement<F32>& stat ) { - mF32Stats.mergeFrom(other->mF32Stats); - mS32Stats.mergeFrom(other->mS32Stats); - mStackTimers.mergeFrom(other->mStackTimers); + return stat.getAccumulator(mMeasurements).getSum(); } + +F32 Sampler::getPerSec( Rate<F32>& stat ) +{ + return stat.getAccumulator(mRates).getSum() / mElapsedSeconds; +} + +F32 Sampler::getMin( Measurement<F32>& stat ) +{ + return stat.getAccumulator(mMeasurements).getMin(); +} + +F32 Sampler::getMax( Measurement<F32>& stat ) +{ + return stat.getAccumulator(mMeasurements).getMax(); +} + +F32 Sampler::getMean( Measurement<F32>& stat ) +{ + return stat.getAccumulator(mMeasurements).getMean(); +} + +F32 Sampler::getStandardDeviation( Measurement<F32>& stat ) +{ + return stat.getAccumulator(mMeasurements).getStandardDeviation(); +} + + + + + + + } diff --git a/indra/llcommon/lltracesampler.h b/indra/llcommon/lltracesampler.h index d1ca7fc9bb..e3498fb39f 100644 --- a/indra/llcommon/lltracesampler.h +++ b/indra/llcommon/lltracesampler.h @@ -30,61 +30,70 @@ #include "stdtypes.h" #include "llpreprocessor.h" -#include "lltrace.h" +#include "llpointer.h" +#include "lltimer.h" namespace LLTrace { + template<typename T> class Rate; + template<typename T> class Measurement; + template<typename T> class AccumulatorBuffer; + template<typename T> class RateAccumulator; + template<typename T> class MeasurementAccumulator; + class TimerAccumulator; + class LL_COMMON_API Sampler { public: + Sampler(); + ~Sampler(); void makePrimary(); + bool isPrimary(); void start(); void stop(); void resume(); - void mergeFrom(const Sampler* other); + void mergeSamples(const Sampler& other); + void initDeltas(const Sampler& other); + void mergeDeltas(const Sampler& other); void reset(); bool isStarted() { return mIsStarted; } - F32 getSum(Stat<F32>& stat) { return stat.getAccumulator(mF32Stats).getSum(); } - F32 getMin(Stat<F32>& stat) { return stat.getAccumulator(mF32Stats).getMin(); } - F32 getMax(Stat<F32>& stat) { return stat.getAccumulator(mF32Stats).getMax(); } - F32 getMean(Stat<F32>& stat) { return stat.getAccumulator(mF32Stats).getMean(); } + F32 getSum(Rate<F32>& stat); + F32 getPerSec(Rate<F32>& stat); - S32 getSum(Stat<S32>& stat) { return stat.getAccumulator(mS32Stats).getSum(); } - S32 getMin(Stat<S32>& stat) { return stat.getAccumulator(mS32Stats).getMin(); } - S32 getMax(Stat<S32>& stat) { return stat.getAccumulator(mS32Stats).getMax(); } - S32 getMean(Stat<S32>& stat) { return stat.getAccumulator(mS32Stats).getMean(); } + F32 getSum(Measurement<F32>& stat); + F32 getMin(Measurement<F32>& stat); + F32 getMax(Measurement<F32>& stat); + F32 getMean(Measurement<F32>& stat); + F32 getStandardDeviation(Measurement<F32>& stat); F64 getSampleTime() { return mElapsedSeconds; } private: friend class ThreadTrace; - Sampler(class ThreadTrace* thread_trace); - - // no copy - Sampler(const Sampler& other) {} // returns data for current thread class ThreadTrace* getThreadTrace(); - //TODO: take snapshot at sampler start so we can simplify updates - //AccumulatorBuffer<StatAccumulator<F32> > mF32StatsStart; - //AccumulatorBuffer<StatAccumulator<S32> > mS32StatsStart; - //AccumulatorBuffer<TimerAccumulator> mStackTimersStart; + LLCopyOnWritePointer<AccumulatorBuffer<RateAccumulator<F32> > > mRatesStart; + LLCopyOnWritePointer<AccumulatorBuffer<RateAccumulator<F32> > > mRates; + LLCopyOnWritePointer<AccumulatorBuffer<MeasurementAccumulator<F32> > > mMeasurements; + LLCopyOnWritePointer<AccumulatorBuffer<TimerAccumulator> > mStackTimersStart; + LLCopyOnWritePointer<AccumulatorBuffer<TimerAccumulator> > mStackTimers; - AccumulatorBuffer<StatAccumulator<F32> > mF32Stats; - AccumulatorBuffer<StatAccumulator<S32> > mS32Stats; - AccumulatorBuffer<TimerAccumulator> mStackTimers; + bool mIsStarted; + LLTimer mSamplingTimer; + F64 mElapsedSeconds; + }; + + class LL_COMMON_API PeriodicSampler + { - bool mIsStarted; - LLTimer mSamplingTimer; - F64 mElapsedSeconds; - ThreadTrace* mThreadTrace; }; } |