summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorRichard Linden <none@none>2012-10-01 19:39:04 -0700
committerRichard Linden <none@none>2012-10-01 19:39:04 -0700
commit14b1b0b2bb6bac5bc688cc4d14c33f1b680dd3b4 (patch)
tree74942f4fef955b5a55031650146e745bbc4ccd6f /indra/llcommon
parentb1baf982b1bd41a150233d0a28d3601226924c65 (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.cpp28
-rw-r--r--indra/llcommon/llapr.h28
-rw-r--r--indra/llcommon/llpointer.h83
-rw-r--r--indra/llcommon/llqueuedthread.cpp2
-rw-r--r--indra/llcommon/llthread.cpp15
-rw-r--r--indra/llcommon/llthread.h9
-rw-r--r--indra/llcommon/lltrace.cpp108
-rw-r--r--indra/llcommon/lltrace.h180
-rw-r--r--indra/llcommon/lltracesampler.cpp98
-rw-r--r--indra/llcommon/lltracesampler.h59
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;
};
}