summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rwxr-xr-xindra/llcommon/CMakeLists.txt2
-rwxr-xr-xindra/llcommon/llfasttimer.h7
-rwxr-xr-xindra/llcommon/llthread.cpp4
-rw-r--r--indra/llcommon/llthreadlocalstorage.cpp2
-rw-r--r--indra/llcommon/llthreadlocalstorage.h31
-rw-r--r--indra/llcommon/lltrace.cpp24
-rw-r--r--indra/llcommon/lltrace.h594
-rw-r--r--indra/llcommon/lltraceaccumulators.cpp123
-rw-r--r--indra/llcommon/lltraceaccumulators.h661
-rw-r--r--indra/llcommon/lltracerecording.cpp117
-rw-r--r--indra/llcommon/lltracerecording.h35
-rw-r--r--indra/llcommon/lltracethreadrecorder.cpp145
-rw-r--r--indra/llcommon/lltracethreadrecorder.h47
-rwxr-xr-xindra/newview/llappviewer.cpp4
-rw-r--r--indra/newview/llscenemonitor.cpp26
-rwxr-xr-xindra/newview/llstartup.cpp54
-rwxr-xr-xindra/newview/llviewerassetstats.cpp15
-rwxr-xr-xindra/newview/llviewercamera.cpp2
-rwxr-xr-xindra/newview/llviewerdisplay.cpp15
19 files changed, 990 insertions, 918 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index bf99a4c3a0..0c76fd46c0 100755
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -103,6 +103,7 @@ set(llcommon_SOURCE_FILES
llthreadsafequeue.cpp
lltimer.cpp
lltrace.cpp
+ lltraceaccumulators.cpp
lltracerecording.cpp
lltracethreadrecorder.cpp
lluri.cpp
@@ -231,6 +232,7 @@ set(llcommon_HEADER_FILES
llthreadsafequeue.h
lltimer.h
lltrace.h
+ lltraceaccumulators.h
lltracerecording.h
lltracethreadrecorder.h
lltreeiterators.h
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 642c99ccce..ab8612a8ad 100755
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -38,13 +38,6 @@ class LLMutex;
namespace LLTrace
{
-struct BlockTimerStackRecord
-{
- class BlockTimer* mActiveTimer;
- class TimeBlock* mTimeBlock;
- U64 mChildTime;
-};
-
class ThreadTimerStack
: public BlockTimerStackRecord,
public LLThreadLocalSingleton<ThreadTimerStack>
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index 118568d5ef..e8e546e769 100755
--- 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::getUIThreadRecorder());
+ LLTrace::SlaveThreadRecorder thread_recorder(LLTrace::getUIThreadRecorder());
#if !LL_DARWIN
sThreadID = threadp->mID;
@@ -107,8 +107,6 @@ 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 thread_recorder;
-
return NULL;
}
diff --git a/indra/llcommon/llthreadlocalstorage.cpp b/indra/llcommon/llthreadlocalstorage.cpp
index 32d94331a6..03c306cc7f 100644
--- a/indra/llcommon/llthreadlocalstorage.cpp
+++ b/indra/llcommon/llthreadlocalstorage.cpp
@@ -88,6 +88,7 @@ void LLThreadLocalPointerBase::destroyStorage()
}
}
+//static
void LLThreadLocalPointerBase::initAllThreadLocalStorage()
{
if (!sInitialized)
@@ -102,6 +103,7 @@ void LLThreadLocalPointerBase::initAllThreadLocalStorage()
}
}
+//static
void LLThreadLocalPointerBase::destroyAllThreadLocalStorage()
{
if (sInitialized)
diff --git a/indra/llcommon/llthreadlocalstorage.h b/indra/llcommon/llthreadlocalstorage.h
index a15f9185b1..d6399d5131 100644
--- a/indra/llcommon/llthreadlocalstorage.h
+++ b/indra/llcommon/llthreadlocalstorage.h
@@ -145,7 +145,7 @@ public:
#if LL_DARWIN
pthread_setspecific(sInstanceKey, NULL);
#else
- sInstance = NULL;
+ sData.mInstance = NULL;
#endif
setInitState(DELETED);
}
@@ -182,7 +182,7 @@ public:
llerrs << "Could not set thread local storage" << llendl;
}
#else
- sInstance = instancep;
+ sData.mInstance = instancep;
#endif
setInitState(INITIALIZING);
instancep->initSingleton();
@@ -197,7 +197,7 @@ public:
#if LL_DARWIN
return (DERIVED_TYPE*)pthread_getspecific(sInstanceKey);
#else
- return sInstance;
+ return sData.mInstance;
#endif
}
@@ -247,7 +247,7 @@ private:
createTLSInitState();
return (EInitState)(int)pthread_getspecific(sInitStateKey);
#else
- return sInitState;
+ return sData.mInitState;
#endif
}
@@ -257,18 +257,21 @@ private:
createTLSInitState();
pthread_setspecific(sInitStateKey, (void*)state);
#else
- sInitState = state;
+ sData.mInitState = state;
#endif
}
LLThreadLocalSingleton(const LLThreadLocalSingleton& other);
virtual void initSingleton() {}
+ struct SingletonData
+ {
+ DERIVED_TYPE* mInstance;
+ EInitState mInitState;
+ };
#ifdef LL_WINDOWS
- static __declspec(thread) DERIVED_TYPE* sInstance;
- static __declspec(thread) EInitState sInitState;
+ static __declspec(thread) SingletonData sData;
#elif LL_LINUX
- static __thread DERIVED_TYPE* sInstance;
- static __thread EInitState sInitState;
+ static __thread SingletonData sData;
#elif LL_DARWIN
static pthread_key_t sInstanceKey;
static pthread_key_t sInitStateKey;
@@ -277,16 +280,10 @@ private:
#if LL_WINDOWS
template<typename DERIVED_TYPE>
-__declspec(thread) DERIVED_TYPE* LLThreadLocalSingleton<DERIVED_TYPE>::sInstance = NULL;
-
-template<typename DERIVED_TYPE>
-__declspec(thread) typename LLThreadLocalSingleton<DERIVED_TYPE>::EInitState LLThreadLocalSingleton<DERIVED_TYPE>::sInitState = LLThreadLocalSingleton<DERIVED_TYPE>::UNINITIALIZED;
+__declspec(thread) typename LLThreadLocalSingleton<DERIVED_TYPE>::SingletonData LLThreadLocalSingleton<DERIVED_TYPE>::sData = {NULL, LLThreadLocalSingleton<DERIVED_TYPE>::UNINITIALIZED};
#elif LL_LINUX
template<typename DERIVED_TYPE>
-__thread DERIVED_TYPE* LLThreadLocalSingleton<DERIVED_TYPE>::sInstance = NULL;
-
-template<typename DERIVED_TYPE>
-__thread typename LLThreadLocalSingleton<DERIVED_TYPE>::EInitState LLThreadLocalSingleton<DERIVED_TYPE>::sInitState = LLThreadLocalSingleton<DERIVED_TYPE>::UNINITIALIZED;
+__thread typename LLThreadLocalSingleton<DERIVED_TYPE>::SingletonData LLThreadLocalSingleton<DERIVED_TYPE>::sData = {NULL, LLThreadLocalSingleton<DERIVED_TYPE>::UNINITIALIZED};
#elif LL_DARWIN
template<typename DERIVED_TYPE>
pthread_key_t LLThreadLocalSingleton<DERIVED_TYPE>::sInstanceKey;
diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp
index 59a4b42c97..25807c7b2c 100644
--- a/indra/llcommon/lltrace.cpp
+++ b/indra/llcommon/lltrace.cpp
@@ -35,8 +35,6 @@ static S32 sInitializationCount = 0;
namespace LLTrace
{
-static MasterThreadRecorder* gUIThreadRecorder = NULL;
-
void init()
{
if (sInitializationCount++ == 0)
@@ -59,28 +57,6 @@ void cleanup()
}
}
-MasterThreadRecorder& getUIThreadRecorder()
-{
- llassert(gUIThreadRecorder != NULL);
- return *gUIThreadRecorder;
-}
-
-LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder_ptr()
-{
- static LLThreadLocalPointer<ThreadRecorder> s_thread_recorder;
- return s_thread_recorder;
-}
-
-const LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder()
-{
- return get_thread_recorder_ptr();
-}
-
-void set_thread_recorder(ThreadRecorder* recorder)
-{
- get_thread_recorder_ptr() = recorder;
-}
-
TimeBlockTreeNode::TimeBlockTreeNode()
: mBlock(NULL),
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index 884a316a3b..72ef51c232 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -32,7 +32,7 @@
#include "llmemory.h"
#include "llrefcount.h"
-#include "llunit.h"
+#include "lltraceaccumulators.h"
#include "llthreadlocalstorage.h"
#include "lltimer.h"
@@ -57,185 +57,6 @@ void init();
void cleanup();
bool isInitialized();
-const LLThreadLocalPointer<class ThreadRecorder>& get_thread_recorder();
-void set_thread_recorder(class ThreadRecorder*);
-
-class MasterThreadRecorder& getUIThreadRecorder();
-
-template<typename ACCUMULATOR>
-class AccumulatorBuffer : public LLRefCount
-{
- typedef AccumulatorBuffer<ACCUMULATOR> self_t;
- static const U32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 64;
-private:
- struct StaticAllocationMarker { };
-
- AccumulatorBuffer(StaticAllocationMarker m)
- : mStorageSize(0),
- mStorage(NULL)
- {}
-
-public:
-
- AccumulatorBuffer(const AccumulatorBuffer& other = *getDefaultBuffer())
- : mStorageSize(0),
- mStorage(NULL)
- {
- resize(other.mStorageSize);
- for (S32 i = 0; i < sNextStorageSlot; i++)
- {
- mStorage[i] = other.mStorage[i];
- }
- }
-
- ~AccumulatorBuffer()
- {
- if (isPrimary())
- {
- LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
- }
- delete[] mStorage;
- }
-
- LL_FORCE_INLINE ACCUMULATOR& operator[](size_t index)
- {
- return mStorage[index];
- }
-
- LL_FORCE_INLINE const ACCUMULATOR& operator[](size_t index) const
- {
- return mStorage[index];
- }
-
- void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other, bool append = true)
- {
- llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize > sNextStorageSlot);
- for (size_t i = 0; i < sNextStorageSlot; i++)
- {
- mStorage[i].addSamples(other.mStorage[i], append);
- }
- }
-
- void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other)
- {
- llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize > sNextStorageSlot);
- for (size_t i = 0; i < sNextStorageSlot; i++)
- {
- mStorage[i] = other.mStorage[i];
- }
- }
-
- void reset(const AccumulatorBuffer<ACCUMULATOR>* other = NULL)
- {
- llassert(mStorageSize >= sNextStorageSlot);
- for (size_t i = 0; i < sNextStorageSlot; i++)
- {
- mStorage[i].reset(other ? &other->mStorage[i] : NULL);
- }
- }
-
- void flush(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp)
- {
- llassert(mStorageSize >= sNextStorageSlot);
- for (size_t i = 0; i < sNextStorageSlot; i++)
- {
- mStorage[i].flush(time_stamp);
- }
- }
-
- void makePrimary()
- {
- LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(mStorage);
- }
-
- bool isPrimary() const
- {
- return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage;
- }
-
- LL_FORCE_INLINE static ACCUMULATOR* getPrimaryStorage()
- {
- ACCUMULATOR* accumulator = LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance();
- return accumulator ? accumulator : getDefaultBuffer()->mStorage;
- }
-
- // 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)
- {
- resize(mStorageSize + (mStorageSize >> 2));
- }
- llassert(mStorage && next_slot < mStorageSize);
- return next_slot;
- }
-
- void resize(size_t new_size)
- {
- if (new_size <= mStorageSize) return;
-
- ACCUMULATOR* old_storage = mStorage;
- mStorage = new ACCUMULATOR[new_size];
- if (old_storage)
- {
- for (S32 i = 0; i < mStorageSize; i++)
- {
- mStorage[i] = old_storage[i];
- }
- }
- mStorageSize = new_size;
- delete[] old_storage;
-
- self_t* default_buffer = getDefaultBuffer();
- if (this != default_buffer
- && new_size > default_buffer->size())
- {
- //NB: this is not thread safe, but we assume that all resizing occurs during static initialization
- default_buffer->resize(new_size);
- }
- }
-
- size_t size() const
- {
- return getNumIndices();
- }
-
- static size_t getNumIndices()
- {
- return sNextStorageSlot;
- }
-
- static self_t* getDefaultBuffer()
- {
- static bool sInitialized = false;
- if (!sInitialized)
- {
- // this buffer is allowed to leak so that trace calls from global destructors have somewhere to put their data
- // so as not to trigger an access violation
- sDefaultBuffer = new AccumulatorBuffer(StaticAllocationMarker());
- sInitialized = true;
- sDefaultBuffer->resize(DEFAULT_ACCUMULATOR_BUFFER_SIZE);
- }
- return sDefaultBuffer;
- }
-
-private:
- ACCUMULATOR* mStorage;
- size_t mStorageSize;
- static size_t sNextStorageSlot;
- static self_t* sDefaultBuffer;
-};
-
-template<typename ACCUMULATOR> size_t AccumulatorBuffer<ACCUMULATOR>::sNextStorageSlot = 0;
-template<typename ACCUMULATOR> AccumulatorBuffer<ACCUMULATOR>* AccumulatorBuffer<ACCUMULATOR>::sDefaultBuffer = NULL;
-
template<typename ACCUMULATOR>
class TraceType
: public LLInstanceTracker<TraceType<ACCUMULATOR>, std::string>
@@ -267,344 +88,6 @@ protected:
const size_t mAccumulatorIndex;
};
-class EventAccumulator
-{
-public:
- typedef F64 value_t;
- typedef F64 mean_t;
-
- EventAccumulator()
- : mSum(0),
- mMin((std::numeric_limits<F64>::max)()),
- mMax((std::numeric_limits<F64>::min)()),
- mMean(0),
- mVarianceSum(0),
- mNumSamples(0),
- mLastValue(0)
- {}
-
- void record(F64 value)
- {
- mNumSamples++;
- mSum += value;
- // NOTE: both conditions will hold on first pass through
- if (value < mMin)
- {
- mMin = value;
- }
- if (value > mMax)
- {
- mMax = value;
- }
- F64 old_mean = mMean;
- mMean += (value - old_mean) / (F64)mNumSamples;
- mVarianceSum += (value - old_mean) * (value - mMean);
- mLastValue = value;
- }
-
- void addSamples(const EventAccumulator& other, bool append)
- {
- if (other.mNumSamples)
- {
- 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 = (F64)mNumSamples,
- n_2 = (F64)other.mNumSamples;
- F64 m_1 = mMean,
- m_2 = other.mMean;
- F64 v_1 = mVarianceSum / mNumSamples,
- v_2 = other.mVarianceSum / other.mNumSamples;
- if (n_1 == 0)
- {
- mVarianceSum = other.mVarianceSum;
- }
- else if (n_2 == 0)
- {
- // don't touch variance
- // mVarianceSum = mVarianceSum;
- }
- 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));
- }
-
- F64 weight = (F64)mNumSamples / (F64)(mNumSamples + other.mNumSamples);
- mNumSamples += other.mNumSamples;
- mMean = mMean * weight + other.mMean * (1.f - weight);
- if (append) mLastValue = other.mLastValue;
- }
- }
-
- void reset(const EventAccumulator* other)
- {
- mNumSamples = 0;
- mSum = 0;
- mMin = std::numeric_limits<F64>::max();
- mMax = std::numeric_limits<F64>::min();
- mMean = 0;
- mVarianceSum = 0;
- mLastValue = other ? other->mLastValue : 0;
- }
-
- void flush(LLUnitImplicit<F64, LLUnits::Seconds>) {}
-
- F64 getSum() const { return mSum; }
- F64 getMin() const { return mMin; }
- F64 getMax() const { return mMax; }
- F64 getLastValue() const { return mLastValue; }
- F64 getMean() const { return mMean; }
- F64 getStandardDeviation() const { return sqrtf(mVarianceSum / mNumSamples); }
- U32 getSampleCount() const { return mNumSamples; }
-
-private:
- F64 mSum,
- mMin,
- mMax,
- mLastValue;
-
- F64 mMean,
- mVarianceSum;
-
- U32 mNumSamples;
-};
-
-
-class SampleAccumulator
-{
-public:
- typedef F64 value_t;
- typedef F64 mean_t;
-
- SampleAccumulator()
- : mSum(0),
- mMin((std::numeric_limits<F64>::max)()),
- mMax((std::numeric_limits<F64>::min)()),
- mMean(0),
- mVarianceSum(0),
- mLastSampleTimeStamp(LLTimer::getTotalSeconds()),
- mTotalSamplingTime(0),
- mNumSamples(0),
- mLastValue(0),
- mHasValue(false)
- {}
-
- void sample(F64 value)
- {
- LLUnitImplicit<F64, LLUnits::Seconds> time_stamp = LLTimer::getTotalSeconds();
- LLUnitImplicit<F64, LLUnits::Seconds> delta_time = time_stamp - mLastSampleTimeStamp;
- mLastSampleTimeStamp = time_stamp;
-
- if (mHasValue)
- {
- mTotalSamplingTime += delta_time;
- mSum += 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) * (mLastValue - old_mean);
- mVarianceSum += delta_time * (mLastValue - old_mean) * (mLastValue - mMean);
- }
-
- mLastValue = value;
- mNumSamples++;
- mHasValue = true;
- }
-
- void addSamples(const SampleAccumulator& other, bool append)
- {
- 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));
- if (append)
- {
- mLastValue = other.mLastValue;
- mLastSampleTimeStamp = other.mLastSampleTimeStamp;
- mHasValue |= other.mHasValue;
- }
- }
- }
-
- void reset(const SampleAccumulator* other)
- {
- mNumSamples = 0;
- mSum = 0;
- mMin = std::numeric_limits<F64>::max();
- mMax = std::numeric_limits<F64>::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<F64, LLUnits::Seconds> time_stamp)
- {
- LLUnitImplicit<F64, LLUnits::Seconds> delta_time = time_stamp - mLastSampleTimeStamp;
-
- if (mHasValue)
- {
- mSum += mLastValue * delta_time;
- mTotalSamplingTime += delta_time;
- }
- mLastSampleTimeStamp = time_stamp;
- }
-
- F64 getSum() const { return mSum; }
- F64 getMin() const { return mMin; }
- F64 getMax() const { return mMax; }
- F64 getLastValue() const { return mLastValue; }
- F64 getMean() const { return mMean; }
- F64 getStandardDeviation() const { return sqrtf(mVarianceSum / mTotalSamplingTime); }
- U32 getSampleCount() const { return mNumSamples; }
-
-private:
- F64 mSum,
- mMin,
- mMax,
- mLastValue;
-
- bool mHasValue;
-
- F64 mMean,
- mVarianceSum;
-
- LLUnitImplicit<F64, LLUnits::Seconds> mLastSampleTimeStamp,
- mTotalSamplingTime;
-
- U32 mNumSamples;
-};
-
-class CountAccumulator
-{
-public:
- typedef F64 value_t;
- typedef F64 mean_t;
-
- CountAccumulator()
- : mSum(0),
- mNumSamples(0)
- {}
-
- void add(F64 value)
- {
- mNumSamples++;
- mSum += value;
- }
-
- void addSamples(const CountAccumulator& other, bool /*append*/)
- {
- mSum += other.mSum;
- mNumSamples += other.mNumSamples;
- }
-
- void reset(const CountAccumulator* other)
- {
- mNumSamples = 0;
- mSum = 0;
- }
-
- void flush(LLUnitImplicit<F64, LLUnits::Seconds>) {}
-
- F64 getSum() const { return mSum; }
-
- U32 getSampleCount() const { return mNumSamples; }
-
-private:
- F64 mSum;
-
- U32 mNumSamples;
-};
-
-class TimeBlockAccumulator
-{
-public:
- typedef LLUnit<F64, LLUnits::Seconds> value_t;
- typedef LLUnit<F64, LLUnits::Seconds> mean_t;
- typedef TimeBlockAccumulator self_t;
-
- // fake classes that allows us to view different facets of underlying statistic
- struct CallCountFacet
- {
- typedef U32 value_t;
- typedef F32 mean_t;
- };
-
- struct SelfTimeFacet
- {
- typedef LLUnit<F64, LLUnits::Seconds> value_t;
- typedef LLUnit<F64, LLUnits::Seconds> mean_t;
- };
-
- TimeBlockAccumulator();
- void addSamples(const self_t& other, bool /*append*/);
- void reset(const self_t* other);
- void flush(LLUnitImplicit<F64, LLUnits::Seconds>) {}
-
- //
- // members
- //
- U64 mStartTotalTimeCounter,
- mTotalTimeCounter,
- mSelfTimeCounter;
- U32 mCalls;
- class TimeBlock* mParent; // last acknowledged parent of this time block
- class TimeBlock* mLastCaller; // used to bootstrap tree construction
- U16 mActiveCount; // number of timers with this ID active on stack
- bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame
-
-};
template<>
class TraceType<TimeBlockAccumulator::CallCountFacet>
@@ -628,23 +111,6 @@ public:
{}
};
-class TimeBlock;
-class TimeBlockTreeNode
-{
-public:
- TimeBlockTreeNode();
-
- void setParent(TimeBlock* parent);
- TimeBlock* getParent() { return mParent; }
-
- TimeBlock* mBlock;
- TimeBlock* mParent;
- std::vector<TimeBlock*> mChildren;
- bool mCollapsed;
- bool mNeedsSorting;
-};
-
-
template <typename T = F64>
class EventStatHandle
: public TraceType<EventAccumulator>
@@ -712,64 +178,6 @@ void add(CountStatHandle<T>& count, VALUE_T value)
count.getPrimaryAccumulator()->add(storage_value(converted_value));
}
-
-struct MemStatAccumulator
-{
- typedef MemStatAccumulator self_t;
-
- // fake classes that allows us to view different facets of underlying statistic
- struct AllocationCountFacet
- {
- typedef U32 value_t;
- typedef F32 mean_t;
- };
-
- struct DeallocationCountFacet
- {
- typedef U32 value_t;
- typedef F32 mean_t;
- };
-
- struct ChildMemFacet
- {
- typedef LLUnit<F64, LLUnits::Bytes> value_t;
- typedef LLUnit<F64, LLUnits::Bytes> mean_t;
- };
-
- MemStatAccumulator()
- : mAllocatedCount(0),
- mDeallocatedCount(0)
- {}
-
- void addSamples(const MemStatAccumulator& other, bool append)
- {
- mSize.addSamples(other.mSize, append);
- mChildSize.addSamples(other.mChildSize, append);
- mAllocatedCount += other.mAllocatedCount;
- mDeallocatedCount += other.mDeallocatedCount;
- }
-
- void reset(const MemStatAccumulator* other)
- {
- mSize.reset(other ? &other->mSize : NULL);
- mChildSize.reset(other ? &other->mChildSize : NULL);
- mAllocatedCount = 0;
- mDeallocatedCount = 0;
- }
-
- void flush(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp)
- {
- mSize.flush(time_stamp);
- mChildSize.flush(time_stamp);
- }
-
- SampleAccumulator mSize,
- mChildSize;
- int mAllocatedCount,
- mDeallocatedCount;
-};
-
-
template<>
class TraceType<MemStatAccumulator::AllocationCountFacet>
: public TraceType<MemStatAccumulator>
diff --git a/indra/llcommon/lltraceaccumulators.cpp b/indra/llcommon/lltraceaccumulators.cpp
new file mode 100644
index 0000000000..950c1d97d1
--- /dev/null
+++ b/indra/llcommon/lltraceaccumulators.cpp
@@ -0,0 +1,123 @@
+/**
+ * @file lltracesampler.cpp
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "lltraceaccumulators.h"
+#include "lltracethreadrecorder.h"
+
+namespace LLTrace
+{
+
+
+///////////////////////////////////////////////////////////////////////
+// AccumulatorBufferGroup
+///////////////////////////////////////////////////////////////////////
+
+AccumulatorBufferGroup::AccumulatorBufferGroup()
+{}
+
+void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other)
+{
+ other.mCounts.reset(&mCounts);
+ other.mSamples.reset(&mSamples);
+ other.mEvents.reset(&mEvents);
+ other.mStackTimers.reset(&mStackTimers);
+ other.mMemStats.reset(&mMemStats);
+}
+
+void AccumulatorBufferGroup::makePrimary()
+{
+ mCounts.makePrimary();
+ mSamples.makePrimary();
+ mEvents.makePrimary();
+ mStackTimers.makePrimary();
+ mMemStats.makePrimary();
+
+ ThreadRecorder* thread_recorder = get_thread_recorder().get();
+ AccumulatorBuffer<TimeBlockAccumulator>& timer_accumulator_buffer = mStackTimers;
+ // update stacktimer parent pointers
+ for (S32 i = 0, end_i = mStackTimers.size(); i < end_i; i++)
+ {
+ TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(i);
+ if (tree_node)
+ {
+ timer_accumulator_buffer[i].mParent = tree_node->mParent;
+ }
+ }
+}
+
+//static
+void AccumulatorBufferGroup::clearPrimary()
+{
+ AccumulatorBuffer<CountAccumulator>::clearPrimary();
+ AccumulatorBuffer<SampleAccumulator>::clearPrimary();
+ AccumulatorBuffer<EventAccumulator>::clearPrimary();
+ AccumulatorBuffer<TimeBlockAccumulator>::clearPrimary();
+ AccumulatorBuffer<MemStatAccumulator>::clearPrimary();
+}
+
+bool AccumulatorBufferGroup::isPrimary() const
+{
+ return mCounts.isPrimary();
+}
+
+void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other )
+{
+ mCounts.addSamples(other.mCounts);
+ mSamples.addSamples(other.mSamples);
+ mEvents.addSamples(other.mEvents);
+ mMemStats.addSamples(other.mMemStats);
+ mStackTimers.addSamples(other.mStackTimers);
+}
+
+void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other)
+{
+ mCounts.addSamples(other.mCounts, false);
+ mSamples.addSamples(other.mSamples, false);
+ mEvents.addSamples(other.mEvents, false);
+ mMemStats.addSamples(other.mMemStats, false);
+ // for now, hold out timers from merge, need to be displayed per thread
+ //mStackTimers.addSamples(other.mStackTimers, false);
+}
+
+void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other)
+{
+ mCounts.reset(other ? &other->mCounts : NULL);
+ mSamples.reset(other ? &other->mSamples : NULL);
+ mEvents.reset(other ? &other->mEvents : NULL);
+ mStackTimers.reset(other ? &other->mStackTimers : NULL);
+ mMemStats.reset(other ? &other->mMemStats : NULL);
+}
+
+void AccumulatorBufferGroup::sync()
+{
+ LLUnitImplicit<F64, LLUnits::Seconds> time_stamp = LLTimer::getTotalSeconds();
+
+ mSamples.sync(time_stamp);
+ mMemStats.sync(time_stamp);
+}
+
+}
diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h
new file mode 100644
index 0000000000..825cc9e3a8
--- /dev/null
+++ b/indra/llcommon/lltraceaccumulators.h
@@ -0,0 +1,661 @@
+/**
+ * @file lltraceaccumulators.h
+ * @brief Storage for accumulating statistics
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLTRACEACCUMULATORS_H
+#define LL_LLTRACEACCUMULATORS_H
+
+
+#include "stdtypes.h"
+#include "llpreprocessor.h"
+#include "llunit.h"
+#include "lltimer.h"
+#include "llrefcount.h"
+
+namespace LLTrace
+{
+
+ template<typename ACCUMULATOR>
+ class AccumulatorBuffer : public LLRefCount
+ {
+ typedef AccumulatorBuffer<ACCUMULATOR> self_t;
+ static const U32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 64;
+ private:
+ struct StaticAllocationMarker { };
+
+ AccumulatorBuffer(StaticAllocationMarker m)
+ : mStorageSize(0),
+ mStorage(NULL)
+ {}
+
+ public:
+
+ AccumulatorBuffer(const AccumulatorBuffer& other = *getDefaultBuffer())
+ : mStorageSize(0),
+ mStorage(NULL)
+ {
+ resize(other.mStorageSize);
+ for (S32 i = 0; i < sNextStorageSlot; i++)
+ {
+ mStorage[i] = other.mStorage[i];
+ }
+ }
+
+ ~AccumulatorBuffer()
+ {
+ if (isPrimary())
+ {
+ LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
+ }
+ delete[] mStorage;
+ }
+
+ LL_FORCE_INLINE ACCUMULATOR& operator[](size_t index)
+ {
+ return mStorage[index];
+ }
+
+ LL_FORCE_INLINE const ACCUMULATOR& operator[](size_t index) const
+ {
+ return mStorage[index];
+ }
+
+ void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other, bool append = true)
+ {
+ llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize > sNextStorageSlot);
+ for (size_t i = 0; i < sNextStorageSlot; i++)
+ {
+ mStorage[i].addSamples(other.mStorage[i], append);
+ }
+ }
+
+ void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other)
+ {
+ llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize > sNextStorageSlot);
+ for (size_t i = 0; i < sNextStorageSlot; i++)
+ {
+ mStorage[i] = other.mStorage[i];
+ }
+ }
+
+ void reset(const AccumulatorBuffer<ACCUMULATOR>* other = NULL)
+ {
+ llassert(mStorageSize >= sNextStorageSlot);
+ for (size_t i = 0; i < sNextStorageSlot; i++)
+ {
+ mStorage[i].reset(other ? &other->mStorage[i] : NULL);
+ }
+ }
+
+ void sync(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp)
+ {
+ llassert(mStorageSize >= sNextStorageSlot);
+ for (size_t i = 0; i < sNextStorageSlot; i++)
+ {
+ mStorage[i].sync(time_stamp);
+ }
+ }
+
+ void makePrimary()
+ {
+ LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(mStorage);
+ }
+
+ bool isPrimary() const
+ {
+ return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage;
+ }
+
+ static void clearPrimary()
+ {
+ LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
+ }
+
+ LL_FORCE_INLINE static ACCUMULATOR* getPrimaryStorage()
+ {
+ ACCUMULATOR* accumulator = LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance();
+ return accumulator ? accumulator : getDefaultBuffer()->mStorage;
+ }
+
+ // 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)
+ {
+ resize(mStorageSize + (mStorageSize >> 2));
+ }
+ llassert(mStorage && next_slot < mStorageSize);
+ return next_slot;
+ }
+
+ void resize(size_t new_size)
+ {
+ if (new_size <= mStorageSize) return;
+
+ ACCUMULATOR* old_storage = mStorage;
+ mStorage = new ACCUMULATOR[new_size];
+ if (old_storage)
+ {
+ for (S32 i = 0; i < mStorageSize; i++)
+ {
+ mStorage[i] = old_storage[i];
+ }
+ }
+ mStorageSize = new_size;
+ delete[] old_storage;
+
+ self_t* default_buffer = getDefaultBuffer();
+ if (this != default_buffer
+ && new_size > default_buffer->size())
+ {
+ //NB: this is not thread safe, but we assume that all resizing occurs during static initialization
+ default_buffer->resize(new_size);
+ }
+ }
+
+ size_t size() const
+ {
+ return getNumIndices();
+ }
+
+ static size_t getNumIndices()
+ {
+ return sNextStorageSlot;
+ }
+
+ static self_t* getDefaultBuffer()
+ {
+ static bool sInitialized = false;
+ if (!sInitialized)
+ {
+ // this buffer is allowed to leak so that trace calls from global destructors have somewhere to put their data
+ // so as not to trigger an access violation
+ sDefaultBuffer = new AccumulatorBuffer(StaticAllocationMarker());
+ sInitialized = true;
+ sDefaultBuffer->resize(DEFAULT_ACCUMULATOR_BUFFER_SIZE);
+ }
+ return sDefaultBuffer;
+ }
+
+ private:
+ ACCUMULATOR* mStorage;
+ size_t mStorageSize;
+ static size_t sNextStorageSlot;
+ static self_t* sDefaultBuffer;
+ };
+
+ template<typename ACCUMULATOR> size_t AccumulatorBuffer<ACCUMULATOR>::sNextStorageSlot = 0;
+ template<typename ACCUMULATOR> AccumulatorBuffer<ACCUMULATOR>* AccumulatorBuffer<ACCUMULATOR>::sDefaultBuffer = NULL;
+
+
+ class EventAccumulator
+ {
+ public:
+ typedef F64 value_t;
+ typedef F64 mean_t;
+
+ EventAccumulator()
+ : mSum(0),
+ mMin((std::numeric_limits<F64>::max)()),
+ mMax((std::numeric_limits<F64>::min)()),
+ mMean(0),
+ mVarianceSum(0),
+ mNumSamples(0),
+ mLastValue(0)
+ {}
+
+ void record(F64 value)
+ {
+ mNumSamples++;
+ mSum += value;
+ // NOTE: both conditions will hold on first pass through
+ if (value < mMin)
+ {
+ mMin = value;
+ }
+ if (value > mMax)
+ {
+ mMax = value;
+ }
+ F64 old_mean = mMean;
+ mMean += (value - old_mean) / (F64)mNumSamples;
+ mVarianceSum += (value - old_mean) * (value - mMean);
+ mLastValue = value;
+ }
+
+ void addSamples(const EventAccumulator& other, bool append)
+ {
+ if (other.mNumSamples)
+ {
+ 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 = (F64)mNumSamples,
+ n_2 = (F64)other.mNumSamples;
+ F64 m_1 = mMean,
+ m_2 = other.mMean;
+ F64 v_1 = mVarianceSum / mNumSamples,
+ v_2 = other.mVarianceSum / other.mNumSamples;
+ if (n_1 == 0)
+ {
+ mVarianceSum = other.mVarianceSum;
+ }
+ else if (n_2 == 0)
+ {
+ // don't touch variance
+ // mVarianceSum = mVarianceSum;
+ }
+ 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));
+ }
+
+ F64 weight = (F64)mNumSamples / (F64)(mNumSamples + other.mNumSamples);
+ mNumSamples += other.mNumSamples;
+ mMean = mMean * weight + other.mMean * (1.f - weight);
+ if (append) mLastValue = other.mLastValue;
+ }
+ }
+
+ void reset(const EventAccumulator* other)
+ {
+ mNumSamples = 0;
+ mSum = 0;
+ mMin = std::numeric_limits<F64>::max();
+ mMax = std::numeric_limits<F64>::min();
+ mMean = 0;
+ mVarianceSum = 0;
+ mLastValue = other ? other->mLastValue : 0;
+ }
+
+ void sync(LLUnitImplicit<F64, LLUnits::Seconds>) {}
+
+ F64 getSum() const { return mSum; }
+ F64 getMin() const { return mMin; }
+ F64 getMax() const { return mMax; }
+ F64 getLastValue() const { return mLastValue; }
+ F64 getMean() const { return mMean; }
+ F64 getStandardDeviation() const { return sqrtf(mVarianceSum / mNumSamples); }
+ U32 getSampleCount() const { return mNumSamples; }
+
+ private:
+ F64 mSum,
+ mMin,
+ mMax,
+ mLastValue;
+
+ F64 mMean,
+ mVarianceSum;
+
+ U32 mNumSamples;
+ };
+
+
+ class SampleAccumulator
+ {
+ public:
+ typedef F64 value_t;
+ typedef F64 mean_t;
+
+ SampleAccumulator()
+ : mSum(0),
+ mMin((std::numeric_limits<F64>::max)()),
+ mMax((std::numeric_limits<F64>::min)()),
+ mMean(0),
+ mVarianceSum(0),
+ mLastSampleTimeStamp(LLTimer::getTotalSeconds()),
+ mTotalSamplingTime(0),
+ mNumSamples(0),
+ mLastValue(0),
+ mHasValue(false)
+ {}
+
+ void sample(F64 value)
+ {
+ LLUnitImplicit<F64, LLUnits::Seconds> time_stamp = LLTimer::getTotalSeconds();
+ LLUnitImplicit<F64, LLUnits::Seconds> delta_time = time_stamp - mLastSampleTimeStamp;
+ mLastSampleTimeStamp = time_stamp;
+
+ if (mHasValue)
+ {
+ mTotalSamplingTime += delta_time;
+ mSum += 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) * (mLastValue - old_mean);
+ mVarianceSum += delta_time * (mLastValue - old_mean) * (mLastValue - mMean);
+ }
+
+ mLastValue = value;
+ mNumSamples++;
+ mHasValue = true;
+ }
+
+ void addSamples(const SampleAccumulator& other, bool append)
+ {
+ 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));
+ if (append)
+ {
+ mLastValue = other.mLastValue;
+ mLastSampleTimeStamp = other.mLastSampleTimeStamp;
+ mHasValue |= other.mHasValue;
+ }
+ }
+ }
+
+ void reset(const SampleAccumulator* other)
+ {
+ mNumSamples = 0;
+ mSum = 0;
+ mMin = std::numeric_limits<F64>::max();
+ mMax = std::numeric_limits<F64>::min();
+ mMean = other ? other->mLastValue : 0;
+ mVarianceSum = 0;
+ mLastSampleTimeStamp = LLTimer::getTotalSeconds();
+ mTotalSamplingTime = 0;
+ mLastValue = other ? other->mLastValue : 0;
+ mHasValue = other ? other->mHasValue : false;
+ }
+
+ void sync(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp)
+ {
+ LLUnitImplicit<F64, LLUnits::Seconds> delta_time = time_stamp - mLastSampleTimeStamp;
+
+ if (mHasValue)
+ {
+ mSum += mLastValue * delta_time;
+ mTotalSamplingTime += delta_time;
+ }
+ mLastSampleTimeStamp = time_stamp;
+ }
+
+ F64 getSum() const { return mSum; }
+ F64 getMin() const { return mMin; }
+ F64 getMax() const { return mMax; }
+ F64 getLastValue() const { return mLastValue; }
+ F64 getMean() const { return mMean; }
+ F64 getStandardDeviation() const { return sqrtf(mVarianceSum / mTotalSamplingTime); }
+ U32 getSampleCount() const { return mNumSamples; }
+
+ private:
+ F64 mSum,
+ mMin,
+ mMax,
+ mLastValue;
+
+ bool mHasValue;
+
+ F64 mMean,
+ mVarianceSum;
+
+ LLUnitImplicit<F64, LLUnits::Seconds> mLastSampleTimeStamp,
+ mTotalSamplingTime;
+
+ U32 mNumSamples;
+ };
+
+ class CountAccumulator
+ {
+ public:
+ typedef F64 value_t;
+ typedef F64 mean_t;
+
+ CountAccumulator()
+ : mSum(0),
+ mNumSamples(0)
+ {}
+
+ void add(F64 value)
+ {
+ mNumSamples++;
+ mSum += value;
+ }
+
+ void addSamples(const CountAccumulator& other, bool /*append*/)
+ {
+ mSum += other.mSum;
+ mNumSamples += other.mNumSamples;
+ }
+
+ void reset(const CountAccumulator* other)
+ {
+ mNumSamples = 0;
+ mSum = 0;
+ }
+
+ void sync(LLUnitImplicit<F64, LLUnits::Seconds>) {}
+
+ F64 getSum() const { return mSum; }
+
+ U32 getSampleCount() const { return mNumSamples; }
+
+ private:
+ F64 mSum;
+
+ U32 mNumSamples;
+ };
+
+ class TimeBlockAccumulator
+ {
+ public:
+ typedef LLUnit<F64, LLUnits::Seconds> value_t;
+ typedef LLUnit<F64, LLUnits::Seconds> mean_t;
+ typedef TimeBlockAccumulator self_t;
+
+ // fake classes that allows us to view different facets of underlying statistic
+ struct CallCountFacet
+ {
+ typedef U32 value_t;
+ typedef F32 mean_t;
+ };
+
+ struct SelfTimeFacet
+ {
+ typedef LLUnit<F64, LLUnits::Seconds> value_t;
+ typedef LLUnit<F64, LLUnits::Seconds> mean_t;
+ };
+
+ TimeBlockAccumulator();
+ void addSamples(const self_t& other, bool /*append*/);
+ void reset(const self_t* other);
+ void sync(LLUnitImplicit<F64, LLUnits::Seconds>) {}
+
+ //
+ // members
+ //
+ U64 mStartTotalTimeCounter,
+ mTotalTimeCounter,
+ mSelfTimeCounter;
+ U32 mCalls;
+ class TimeBlock* mParent; // last acknowledged parent of this time block
+ class TimeBlock* mLastCaller; // used to bootstrap tree construction
+ U16 mActiveCount; // number of timers with this ID active on stack
+ bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame
+
+ };
+
+ class TimeBlock;
+ class TimeBlockTreeNode
+ {
+ public:
+ TimeBlockTreeNode();
+
+ void setParent(TimeBlock* parent);
+ TimeBlock* getParent() { return mParent; }
+
+ TimeBlock* mBlock;
+ TimeBlock* mParent;
+ std::vector<TimeBlock*> mChildren;
+ bool mCollapsed;
+ bool mNeedsSorting;
+ };
+
+ struct BlockTimerStackRecord
+ {
+ class BlockTimer* mActiveTimer;
+ class TimeBlock* mTimeBlock;
+ U64 mChildTime;
+ };
+
+ struct MemStatAccumulator
+ {
+ typedef MemStatAccumulator self_t;
+
+ // fake classes that allows us to view different facets of underlying statistic
+ struct AllocationCountFacet
+ {
+ typedef U32 value_t;
+ typedef F32 mean_t;
+ };
+
+ struct DeallocationCountFacet
+ {
+ typedef U32 value_t;
+ typedef F32 mean_t;
+ };
+
+ struct ChildMemFacet
+ {
+ typedef LLUnit<F64, LLUnits::Bytes> value_t;
+ typedef LLUnit<F64, LLUnits::Bytes> mean_t;
+ };
+
+ MemStatAccumulator()
+ : mAllocatedCount(0),
+ mDeallocatedCount(0)
+ {}
+
+ void addSamples(const MemStatAccumulator& other, bool append)
+ {
+ mSize.addSamples(other.mSize, append);
+ mChildSize.addSamples(other.mChildSize, append);
+ mAllocatedCount += other.mAllocatedCount;
+ mDeallocatedCount += other.mDeallocatedCount;
+ }
+
+ void reset(const MemStatAccumulator* other)
+ {
+ mSize.reset(other ? &other->mSize : NULL);
+ mChildSize.reset(other ? &other->mChildSize : NULL);
+ mAllocatedCount = 0;
+ mDeallocatedCount = 0;
+ }
+
+ void sync(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp)
+ {
+ mSize.sync(time_stamp);
+ mChildSize.sync(time_stamp);
+ }
+
+ SampleAccumulator mSize,
+ mChildSize;
+ int mAllocatedCount,
+ mDeallocatedCount;
+ };
+
+ struct AccumulatorBufferGroup : public LLRefCount
+ {
+ AccumulatorBufferGroup();
+
+ void handOffTo(AccumulatorBufferGroup& other);
+ void makePrimary();
+ bool isPrimary() const;
+ static void clearPrimary();
+
+ void append(const AccumulatorBufferGroup& other);
+ void merge(const AccumulatorBufferGroup& other);
+ void reset(AccumulatorBufferGroup* other = NULL);
+ void sync();
+
+ AccumulatorBuffer<CountAccumulator> mCounts;
+ AccumulatorBuffer<SampleAccumulator> mSamples;
+ AccumulatorBuffer<EventAccumulator> mEvents;
+ AccumulatorBuffer<TimeBlockAccumulator> mStackTimers;
+ AccumulatorBuffer<MemStatAccumulator> mMemStats;
+ };
+}
+
+#endif // LL_LLTRACEACCUMULATORS_H
+
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
index d34434f161..0938317eaa 100644
--- a/indra/llcommon/lltracerecording.cpp
+++ b/indra/llcommon/lltracerecording.cpp
@@ -33,85 +33,7 @@
namespace LLTrace
{
-
-
-///////////////////////////////////////////////////////////////////////
-// RecordingBuffers
-///////////////////////////////////////////////////////////////////////
-
-RecordingBuffers::RecordingBuffers()
-{}
-
-void RecordingBuffers::handOffTo(RecordingBuffers& other)
-{
- other.mCounts.reset(&mCounts);
- other.mSamples.reset(&mSamples);
- other.mEvents.reset(&mEvents);
- other.mStackTimers.reset(&mStackTimers);
- other.mMemStats.reset(&mMemStats);
-}
-
-void RecordingBuffers::makePrimary()
-{
- mCounts.makePrimary();
- mSamples.makePrimary();
- mEvents.makePrimary();
- mStackTimers.makePrimary();
- mMemStats.makePrimary();
-
- ThreadRecorder* thread_recorder = get_thread_recorder().get();
- AccumulatorBuffer<TimeBlockAccumulator>& timer_accumulator_buffer = mStackTimers;
- // update stacktimer parent pointers
- for (S32 i = 0, end_i = mStackTimers.size(); i < end_i; i++)
- {
- TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(i);
- if (tree_node)
- {
- timer_accumulator_buffer[i].mParent = tree_node->mParent;
- }
- }
-}
-
-bool RecordingBuffers::isPrimary() const
-{
- return mCounts.isPrimary();
-}
-
-void RecordingBuffers::append( const RecordingBuffers& other )
-{
- mCounts.addSamples(other.mCounts);
- mSamples.addSamples(other.mSamples);
- mEvents.addSamples(other.mEvents);
- mMemStats.addSamples(other.mMemStats);
- mStackTimers.addSamples(other.mStackTimers);
-}
-
-void RecordingBuffers::merge( const RecordingBuffers& other)
-{
- mCounts.addSamples(other.mCounts, false);
- mSamples.addSamples(other.mSamples, false);
- mEvents.addSamples(other.mEvents, false);
- mMemStats.addSamples(other.mMemStats, false);
- // for now, hold out timers from merge, need to be displayed per thread
- //mStackTimers.addSamples(other.mStackTimers, false);
-}
-
-void RecordingBuffers::reset(RecordingBuffers* other)
-{
- mCounts.reset(other ? &other->mCounts : NULL);
- mSamples.reset(other ? &other->mSamples : NULL);
- mEvents.reset(other ? &other->mEvents : NULL);
- mStackTimers.reset(other ? &other->mStackTimers : NULL);
- mMemStats.reset(other ? &other->mMemStats : NULL);
-}
-
-void RecordingBuffers::flush()
-{
- LLUnitImplicit<F64, LLUnits::Seconds> time_stamp = LLTimer::getTotalSeconds();
-
- mSamples.flush(time_stamp);
-}
-
+
///////////////////////////////////////////////////////////////////////
// Recording
///////////////////////////////////////////////////////////////////////
@@ -119,7 +41,7 @@ void RecordingBuffers::flush()
Recording::Recording()
: mElapsedSeconds(0)
{
- mBuffers = new RecordingBuffers();
+ mBuffers = new AccumulatorBufferGroup();
}
Recording::Recording( const Recording& other )
@@ -132,17 +54,17 @@ Recording& Recording::operator = (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);
- mutable_other.update();
+ const_cast<Recording&>(other).update();
EPlayState other_play_state = other.getPlayState();
- mBuffers = mutable_other.mBuffers;
-
- LLStopWatchControlsMixin<Recording>::setPlayState(other_play_state);
+ mBuffers = other.mBuffers;
// above call will clear mElapsedSeconds as a side effect, so copy it here
mElapsedSeconds = other.mElapsedSeconds;
mSamplingTimer = other.mSamplingTimer;
+
+ setPlayState(other_play_state);
+
return *this;
}
@@ -151,7 +73,7 @@ Recording::~Recording()
{
if (isStarted() && LLTrace::get_thread_recorder().notNull())
{
- LLTrace::get_thread_recorder()->deactivate(this);
+ LLTrace::get_thread_recorder()->deactivate(mBuffers.write());
}
}
@@ -159,8 +81,10 @@ void Recording::update()
{
if (isStarted())
{
- mBuffers.write()->flush();
- LLTrace::get_thread_recorder()->bringUpToDate(this);
+ mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
+ AccumulatorBufferGroup* buffers = mBuffers.write();
+ LLTrace::get_thread_recorder()->bringUpToDate(buffers);
+
mSamplingTimer.reset();
}
}
@@ -176,14 +100,14 @@ void Recording::handleReset()
void Recording::handleStart()
{
mSamplingTimer.reset();
- LLTrace::get_thread_recorder()->activate(this);
+ LLTrace::get_thread_recorder()->activate(mBuffers.write());
}
void Recording::handleStop()
{
mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
- mBuffers.write()->flush();
- LLTrace::get_thread_recorder()->deactivate(this);
+ AccumulatorBufferGroup* buffers = mBuffers.write();
+ LLTrace::get_thread_recorder()->deactivate(buffers);
}
void Recording::handleSplitTo(Recording& other)
@@ -191,19 +115,14 @@ void Recording::handleSplitTo(Recording& other)
mBuffers.write()->handOffTo(*other.mBuffers.write());
}
-void Recording::appendRecording( const Recording& other )
+void Recording::appendRecording( Recording& other )
{
update();
+ other.update();
mBuffers.write()->append(*other.mBuffers);
mElapsedSeconds += other.mElapsedSeconds;
}
-void Recording::mergeRecording( const Recording& other)
-{
- update();
- mBuffers.write()->merge(*other.mBuffers);
-}
-
LLUnit<F64, LLUnits::Seconds> Recording::getSum(const TraceType<TimeBlockAccumulator>& stat)
{
const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()];
@@ -710,8 +629,6 @@ F64 PeriodicRecording::getPeriodMean( const TraceType<SampleAccumulator>& stat,
void ExtendableRecording::extend()
{
- // stop recording to get latest data
- mPotentialRecording.update();
// push the data back to accepted recording
mAcceptedRecording.appendRecording(mPotentialRecording);
// flush data, so we can start from scratch
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h
index b839e85de0..355dbabb1c 100644
--- a/indra/llcommon/lltracerecording.h
+++ b/indra/llcommon/lltracerecording.h
@@ -32,7 +32,7 @@
#include "llpointer.h"
#include "lltimer.h"
-#include "lltrace.h"
+#include "lltraceaccumulators.h"
class LLStopWatchControlsMixinCommon
{
@@ -81,6 +81,7 @@ class LLStopWatchControlsMixin
: public LLStopWatchControlsMixinCommon
{
public:
+
typedef LLStopWatchControlsMixin<DERIVED> self_t;
virtual void splitTo(DERIVED& other)
{
@@ -98,6 +99,11 @@ public:
static_cast<self_t&>(other).handleSplitTo(*static_cast<DERIVED*>(this));
}
private:
+ self_t& operator = (const self_t& other)
+ {
+ // don't do anything, derived class must implement logic
+ }
+
// atomically stop this object while starting the other
// no data can be missed in between stop and start
virtual void handleSplitTo(DERIVED& other) {};
@@ -106,26 +112,6 @@ private:
namespace LLTrace
{
- struct RecordingBuffers : public LLRefCount
- {
- RecordingBuffers();
-
- void handOffTo(RecordingBuffers& other);
- void makePrimary();
- bool isPrimary() const;
-
- void append(const RecordingBuffers& other);
- void merge(const RecordingBuffers& other);
- void reset(RecordingBuffers* other = NULL);
- void flush();
-
- AccumulatorBuffer<CountAccumulator> mCounts;
- AccumulatorBuffer<SampleAccumulator> mSamples;
- AccumulatorBuffer<EventAccumulator> mEvents;
- AccumulatorBuffer<TimeBlockAccumulator> mStackTimers;
- AccumulatorBuffer<MemStatAccumulator> mMemStats;
- };
-
class Recording
: public LLStopWatchControlsMixin<Recording>
{
@@ -138,10 +124,7 @@ namespace LLTrace
Recording& operator = (const Recording& other);
// accumulate data from subsequent, non-overlapping recording
- void appendRecording(const Recording& other);
-
- // gather data from recording, ignoring time relationship (for example, pulling data from slave threads)
- void mergeRecording(const Recording& other);
+ void appendRecording(Recording& other);
// grab latest recorded data
void update();
@@ -291,7 +274,7 @@ namespace LLTrace
LLTimer mSamplingTimer;
LLUnit<F64, LLUnits::Seconds> mElapsedSeconds;
- LLCopyOnWritePointer<RecordingBuffers> mBuffers;
+ LLCopyOnWritePointer<AccumulatorBufferGroup> mBuffers;
};
class LL_COMMON_API PeriodicRecording
diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp
index 54006f4e5b..7192564c94 100644
--- a/indra/llcommon/lltracethreadrecorder.cpp
+++ b/indra/llcommon/lltracethreadrecorder.cpp
@@ -31,6 +31,7 @@
namespace LLTrace
{
+MasterThreadRecorder* gUIThreadRecorder = NULL;
///////////////////////////////////////////////////////////////////////
// ThreadRecorder
@@ -49,7 +50,7 @@ ThreadRecorder::ThreadRecorder()
mNumTimeBlockTreeNodes = AccumulatorBuffer<TimeBlockAccumulator>::getDefaultBuffer()->size();
mTimeBlockTreeNodes = new TimeBlockTreeNode[mNumTimeBlockTreeNodes];
- mThreadRecording.start();
+ activate(&mThreadRecordingBuffers);
// initialize time block parent pointers
for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances();
@@ -72,6 +73,8 @@ ThreadRecorder::ThreadRecorder()
ThreadRecorder::~ThreadRecorder()
{
+ deactivate(&mThreadRecordingBuffers);
+
delete mRootTimer;
if (!mActiveRecordings.empty())
@@ -84,7 +87,7 @@ ThreadRecorder::~ThreadRecorder()
delete[] mTimeBlockTreeNodes;
}
-TimeBlockTreeNode* ThreadRecorder::getTimeBlockTreeNode(S32 index)
+TimeBlockTreeNode* ThreadRecorder::getTimeBlockTreeNode( S32 index )
{
if (0 <= index && index < mNumTimeBlockTreeNodes)
{
@@ -94,23 +97,33 @@ TimeBlockTreeNode* ThreadRecorder::getTimeBlockTreeNode(S32 index)
}
-void ThreadRecorder::activate( Recording* recording )
+void ThreadRecorder::activate( AccumulatorBufferGroup* recording )
{
+ active_recording_list_t::reverse_iterator it, end_it;
+ for (it = mActiveRecordings.rbegin(), end_it = mActiveRecordings.rend();
+ it != end_it;
+ ++it)
+ {
+ llassert((*it)->mTargetRecording != recording);
+ }
+
ActiveRecording* active_recording = new ActiveRecording(recording);
if (!mActiveRecordings.empty())
{
- mActiveRecordings.back()->mPartialRecording.handOffTo(active_recording->mPartialRecording);
+ AccumulatorBufferGroup& prev_active_recording = mActiveRecordings.back()->mPartialRecording;
+ prev_active_recording.sync();
+ prev_active_recording.handOffTo(active_recording->mPartialRecording);
}
mActiveRecordings.push_back(active_recording);
mActiveRecordings.back()->mPartialRecording.makePrimary();
}
-ThreadRecorder::active_recording_list_t::reverse_iterator ThreadRecorder::bringUpToDate( Recording* recording )
+ThreadRecorder::active_recording_list_t::reverse_iterator ThreadRecorder::bringUpToDate( AccumulatorBufferGroup* recording )
{
if (mActiveRecordings.empty()) return mActiveRecordings.rend();
- mActiveRecordings.back()->mPartialRecording.flush();
+ mActiveRecordings.back()->mPartialRecording.sync();
TimeBlock::updateTimes();
active_recording_list_t::reverse_iterator it, end_it;
@@ -148,34 +161,38 @@ ThreadRecorder::active_recording_list_t::reverse_iterator ThreadRecorder::bringU
return it;
}
-void ThreadRecorder::deactivate( Recording* recording )
+void ThreadRecorder::deactivate( AccumulatorBufferGroup* recording )
{
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::reverse_iterator next_it = it;
- ++next_it;
- if (next_it != mActiveRecordings.rend())
- {
- (*next_it)->mPartialRecording.makePrimary();
- }
-
active_recording_list_t::iterator recording_to_remove = (++it).base();
+ bool was_primary = (*recording_to_remove)->mPartialRecording.isPrimary();
llassert((*recording_to_remove)->mTargetRecording == recording);
delete *recording_to_remove;
mActiveRecordings.erase(recording_to_remove);
+ if (was_primary)
+ {
+ if (mActiveRecordings.empty())
+ {
+ AccumulatorBufferGroup::clearPrimary();
+ }
+ else
+ {
+ mActiveRecordings.back()->mPartialRecording.makePrimary();
+ }
+ }
}
}
-ThreadRecorder::ActiveRecording::ActiveRecording( Recording* target )
+ThreadRecorder::ActiveRecording::ActiveRecording( AccumulatorBufferGroup* target )
: mTargetRecording(target)
{
}
void ThreadRecorder::ActiveRecording::movePartialToTarget()
{
- mTargetRecording->mBuffers.write()->append(mPartialRecording);
+ mTargetRecording->append(mPartialRecording);
// reset based on self to keep history
mPartialRecording.reset(&mPartialRecording);
}
@@ -197,79 +214,49 @@ SlaveThreadRecorder::~SlaveThreadRecorder()
}
void SlaveThreadRecorder::pushToMaster()
-{
- mThreadRecording.stop();
- {
- LLMutexLock(mMasterRecorder.getSlaveListMutex());
- mSharedData.appendFrom(mThreadRecording);
+{
+ { LLMutexLock lock(&mSharedRecordingMutex);
+ LLTrace::get_thread_recorder()->bringUpToDate(&mThreadRecordingBuffers);
+ mSharedRecordingBuffers.append(mThreadRecordingBuffers);
}
- mThreadRecording.start();
-}
-
-void SlaveThreadRecorder::SharedData::appendFrom( const Recording& source )
-{
- LLMutexLock lock(&mRecordingMutex);
- appendRecording(source);
}
-void SlaveThreadRecorder::SharedData::appendTo( Recording& sink )
-{
- LLMutexLock lock(&mRecordingMutex);
- sink.appendRecording(*this);
-}
-
-void SlaveThreadRecorder::SharedData::mergeFrom( const RecordingBuffers& source )
-{
- LLMutexLock lock(&mRecordingMutex);
- mBuffers.write()->merge(source);
-}
-
-void SlaveThreadRecorder::SharedData::mergeTo( RecordingBuffers& sink )
-{
- LLMutexLock lock(&mRecordingMutex);
- sink.merge(*mBuffers);
-}
-
-void SlaveThreadRecorder::SharedData::reset()
-{
- LLMutexLock lock(&mRecordingMutex);
- Recording::reset();
-}
-
-
///////////////////////////////////////////////////////////////////////
// MasterThreadRecorder
///////////////////////////////////////////////////////////////////////
static LLFastTimer::DeclareTimer FTM_PULL_TRACE_DATA_FROM_SLAVES("Pull slave trace data");
+
void MasterThreadRecorder::pullFromSlaveThreads()
{
- LLFastTimer _(FTM_PULL_TRACE_DATA_FROM_SLAVES);
+ /*LLFastTimer _(FTM_PULL_TRACE_DATA_FROM_SLAVES);
if (mActiveRecordings.empty()) return;
- LLMutexLock lock(&mSlaveListMutex);
+ { LLMutexLock lock(&mSlaveListMutex);
- RecordingBuffers& target_recording_buffers = mActiveRecordings.back()->mPartialRecording;
+ AccumulatorBufferGroup& target_recording_buffers = mActiveRecordings.back()->mPartialRecording;
+ target_recording_buffers.sync();
for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end();
- it != end_it;
- ++it)
- {
- // ignore block timing info for now
- (*it)->mSharedData.mergeTo(target_recording_buffers);
- (*it)->mSharedData.reset();
+ it != end_it;
+ ++it)
+ { LLMutexLock lock(&(*it)->mSharedRecordingMutex);
+
+ target_recording_buffers.merge((*it)->mSharedRecordingBuffers);
+ (*it)->mSharedRecordingBuffers.reset();
}
+ }*/
}
+// called by slave thread
void MasterThreadRecorder::addSlaveThread( class SlaveThreadRecorder* child )
-{
- LLMutexLock lock(&mSlaveListMutex);
+{ LLMutexLock lock(&mSlaveListMutex);
mSlaveThreadRecorders.push_back(child);
}
+// called by slave thread
void MasterThreadRecorder::removeSlaveThread( class SlaveThreadRecorder* child )
-{
- LLMutexLock lock(&mSlaveListMutex);
+{ LLMutexLock lock(&mSlaveListMutex);
for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end();
it != end_it;
@@ -289,4 +276,28 @@ void MasterThreadRecorder::pushToMaster()
MasterThreadRecorder::MasterThreadRecorder()
{}
+
+MasterThreadRecorder& getUIThreadRecorder()
+{
+ llassert(gUIThreadRecorder != NULL);
+ return *gUIThreadRecorder;
+}
+
+LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder_ptr()
+{
+ static LLThreadLocalPointer<ThreadRecorder> s_thread_recorder;
+ return s_thread_recorder;
+}
+
+const LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder()
+{
+ return get_thread_recorder_ptr();
+}
+
+void set_thread_recorder(ThreadRecorder* recorder)
+{
+ get_thread_recorder_ptr() = recorder;
+}
+
+
}
diff --git a/indra/llcommon/lltracethreadrecorder.h b/indra/llcommon/lltracethreadrecorder.h
index bf3701304f..6b7a8e5865 100644
--- a/indra/llcommon/lltracethreadrecorder.h
+++ b/indra/llcommon/lltracethreadrecorder.h
@@ -31,7 +31,8 @@
#include "llpreprocessor.h"
#include "llmutex.h"
-#include "lltracerecording.h"
+#include "lltraceaccumulators.h"
+#include "llthreadlocalstorage.h"
namespace LLTrace
{
@@ -45,9 +46,9 @@ namespace LLTrace
virtual ~ThreadRecorder();
- void activate(Recording* recording);
- void deactivate(Recording* recording);
- active_recording_list_t::reverse_iterator bringUpToDate(Recording* recording);
+ void activate(AccumulatorBufferGroup* recording);
+ void deactivate(AccumulatorBufferGroup* recording);
+ active_recording_list_t::reverse_iterator bringUpToDate(AccumulatorBufferGroup* recording);
virtual void pushToMaster() = 0;
@@ -56,20 +57,21 @@ namespace LLTrace
protected:
struct ActiveRecording
{
- ActiveRecording(Recording* target);
+ ActiveRecording(AccumulatorBufferGroup* target);
- Recording* mTargetRecording;
- RecordingBuffers mPartialRecording;
+ AccumulatorBufferGroup* mTargetRecording;
+ AccumulatorBufferGroup mPartialRecording;
void movePartialToTarget();
};
- Recording mThreadRecording;
+ AccumulatorBufferGroup mThreadRecordingBuffers;
active_recording_list_t mActiveRecordings;
class BlockTimer* mRootTimer;
TimeBlockTreeNode* mTimeBlockTreeNodes;
size_t mNumTimeBlockTreeNodes;
+ BlockTimerStackRecord mBlockTimerStackRecord;
};
class LL_COMMON_API MasterThreadRecorder : public ThreadRecorder
@@ -85,9 +87,6 @@ namespace LLTrace
// call this periodically to gather stats data from slave threads
void pullFromSlaveThreads();
- LLMutex* getSlaveListMutex() { return &mSlaveListMutex; }
-
-
private:
typedef std::list<class SlaveThreadRecorder*> slave_thread_recorder_list_t;
@@ -105,22 +104,20 @@ namespace LLTrace
// call this periodically to gather stats data for master thread to consume
/*virtual*/ void pushToMaster();
- MasterThreadRecorder* mMaster;
-
- class SharedData : public Recording
- {
- public:
- void appendFrom(const Recording& source);
- void appendTo(Recording& sink);
- void mergeFrom(const RecordingBuffers& source);
- void mergeTo(RecordingBuffers& sink);
- void reset();
- private:
- LLMutex mRecordingMutex;
- };
- SharedData mSharedData;
+ private:
+ friend class MasterThreadRecorder;
+ LLMutex mSharedRecordingMutex;
+ AccumulatorBufferGroup mSharedRecordingBuffers;
MasterThreadRecorder& mMasterRecorder;
};
+
+ //FIXME: let user code set up thread recorder topology
+ extern MasterThreadRecorder* gUIThreadRecorder ;
+
+ const LLThreadLocalPointer<class ThreadRecorder>& get_thread_recorder();
+ void set_thread_recorder(class ThreadRecorder*);
+ class MasterThreadRecorder& getUIThreadRecorder();
+
}
#endif // LL_LLTRACETHREADRECORDER_H
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 733c9cc9df..7c5cd520da 100755
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1294,6 +1294,8 @@ bool LLAppViewer::mainLoop()
{
LLFastTimer _(FTM_FRAME);
LLTrace::TimeBlock::processTimes();
+ llassert((LLTrace::get_frame_recording().getCurRecording().update(),
+ LLTrace::get_frame_recording().getCurRecording().getSampleCount(LLStatViewer::FPS) <= 1));
LLTrace::get_frame_recording().nextPeriod();
LLTrace::TimeBlock::logStats();
@@ -5617,6 +5619,6 @@ void LLAppViewer::metricsSend(bool enable_reporting)
// Reset even if we can't report. Rather than gather up a huge chunk of
// data, we'll keep to our sampling interval and retain the data
// resolution in time.
- gViewerAssetStats->reset();
+ gViewerAssetStats->restart();
}
diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp
index ed9eeb9330..a4d693ec0b 100644
--- a/indra/newview/llscenemonitor.cpp
+++ b/indra/newview/llscenemonitor.cpp
@@ -260,14 +260,7 @@ void LLSceneMonitor::capture()
static LLCachedControl<bool> monitor_enabled(gSavedSettings, "SceneLoadingMonitorEnabled");
static LLCachedControl<F32> scene_load_sample_time(gSavedSettings, "SceneLoadingMonitorSampleTime");
static LLFrameTimer timer;
-
- if (mEnabled
- && (mMonitorRecording.getSum(*LLViewerCamera::getVelocityStat()) > 0.1f
- || mMonitorRecording.getSum(*LLViewerCamera::getAngularVelocityStat()) > 0.05f))
- {
- reset();
- freezeScene();
- }
+ static bool force_capture = true;
bool enabled = monitor_enabled || mDebugViewerVisible;
if(mEnabled != enabled)
@@ -275,6 +268,7 @@ void LLSceneMonitor::capture()
if(mEnabled)
{
unfreezeScene();
+ force_capture = true;
}
else
{
@@ -285,11 +279,23 @@ void LLSceneMonitor::capture()
mEnabled = enabled;
}
- if(timer.getElapsedTimeF32() > scene_load_sample_time()
+ if (mEnabled
+ && (mMonitorRecording.getSum(*LLViewerCamera::getVelocityStat()) > 0.1f
+ || mMonitorRecording.getSum(*LLViewerCamera::getAngularVelocityStat()) > 0.05f))
+ {
+ reset();
+ freezeScene();
+ force_capture = true;
+ }
+
+ if((timer.getElapsedTimeF32() > scene_load_sample_time()
+ || force_capture)
&& mEnabled
&& LLGLSLShader::sNoFixedFunction
&& last_capture_time != gFrameCount)
{
+ force_capture = false;
+
mSceneLoadRecording.resume();
mMonitorRecording.resume();
@@ -479,12 +485,10 @@ void LLSceneMonitor::fetchQueryResult()
if(mDiffResult > diff_threshold())
{
mSceneLoadRecording.extend();
- llassert(mSceneLoadRecording.getAcceptedRecording().getLastRecording().getSum(LLStatViewer::FPS));
}
else
{
mSceneLoadRecording.getPotentialRecording().nextPeriod();
- llassert(mSceneLoadRecording.getPotentialRecording().getLastRecording().getSum(LLStatViewer::FPS));
}
}
}
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index de8d549055..097ea7cc8d 100755
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -2054,6 +2054,7 @@ bool idle_startup()
const F32 wearables_time = wearables_timer.getElapsedTimeF32();
static LLCachedControl<F32> max_wearables_time(gSavedSettings, "ClothingLoadingDelay");
+ display_startup();
if (!gAgent.isGenderChosen() && isAgentAvatarValid())
{
// No point in waiting for clothing, we don't even
@@ -2067,50 +2068,39 @@ bool idle_startup()
LLNotificationsUtil::add("WelcomeChooseSex", LLSD(), LLSD(),
callback_choose_gender);
LLStartUp::setStartupState( STATE_CLEANUP );
- return TRUE;
}
-
- display_startup();
-
- if (wearables_time > max_wearables_time())
+ else if (wearables_time >= max_wearables_time())
{
LLNotificationsUtil::add("ClothingLoading");
record(LLStatViewer::LOADING_WEARABLES_LONG_DELAY, wearables_time);
LLStartUp::setStartupState( STATE_CLEANUP );
- return TRUE;
}
-
- if (gAgent.isFirstLogin())
+ else if (gAgent.isFirstLogin()
+ && isAgentAvatarValid()
+ && gAgentAvatarp->isFullyLoaded())
{
// wait for avatar to be completely loaded
- if (isAgentAvatarValid()
- && gAgentAvatarp->isFullyLoaded())
- {
- //llinfos << "avatar fully loaded" << llendl;
- LLStartUp::setStartupState( STATE_CLEANUP );
- return TRUE;
- }
+ //llinfos << "avatar fully loaded" << llendl;
+ LLStartUp::setStartupState( STATE_CLEANUP );
+ }
+ // OK to just get the wearables
+ else if (!gAgent.isFirstLogin() && gAgentWearables.areWearablesLoaded() )
+ {
+ // We have our clothing, proceed.
+ //llinfos << "wearables loaded" << llendl;
+ LLStartUp::setStartupState( STATE_CLEANUP );
}
else
{
- // OK to just get the wearables
- if ( gAgentWearables.areWearablesLoaded() )
- {
- // We have our clothing, proceed.
- //llinfos << "wearables loaded" << llendl;
- LLStartUp::setStartupState( STATE_CLEANUP );
- return TRUE;
- }
+ display_startup();
+ update_texture_fetch();
+ display_startup();
+ set_startup_status(0.9f + 0.1f * wearables_time / max_wearables_time(),
+ LLTrans::getString("LoginDownloadingClothing").c_str(),
+ gAgent.mMOTD.c_str());
+ display_startup();
}
-
- display_startup();
- update_texture_fetch();
- display_startup();
- set_startup_status(0.9f + 0.1f * wearables_time / max_wearables_time(),
- LLTrans::getString("LoginDownloadingClothing").c_str(),
- gAgent.mMOTD.c_str());
- display_startup();
- return TRUE;
+ //fall through this frame to STATE_CLEANUP
}
if (STATE_CLEANUP == LLStartUp::getStartupState())
diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp
index 6ab2aefc34..80412c215f 100755
--- a/indra/newview/llviewerassetstats.cpp
+++ b/indra/newview/llviewerassetstats.cpp
@@ -314,9 +314,9 @@ void LLViewerAssetStats::handleStop()
}
void LLViewerAssetStats::handleReset()
- {
+{
reset();
- }
+}
void LLViewerAssetStats::reset()
@@ -328,6 +328,7 @@ void LLViewerAssetStats::reset()
if (mRegionHandle)
{
mCurRecording = &mRegionRecordings[mRegionHandle];
+ mCurRecording->setPlayState(getPlayState());
}
}
@@ -346,7 +347,7 @@ void LLViewerAssetStats::setRegion(region_handle_t region_handle)
if (region_handle)
{
mCurRecording = &mRegionRecordings[region_handle];
- mCurRecording->start();
+ mCurRecording->setPlayState(getPlayState());
}
mRegionHandle = region_handle;
@@ -493,19 +494,19 @@ void LLViewerAssetStats::getStats(AssetStats& stats, bool compact_output)
}
LLSD LLViewerAssetStats::asLLSD(bool compact_output)
- {
+{
LLParamSDParser parser;
LLSD sd;
AssetStats stats;
getStats(stats, compact_output);
LLInitParam::predicate_rule_t rule = LLInitParam::default_parse_rules();
if (!compact_output)
- {
+ {
rule.allow(LLInitParam::EMPTY);
- }
+ }
parser.writeSD(sd, stats, rule);
return sd;
- }
+}
// ------------------------------------------------------
// Global free-function definitions (LLViewerAssetStatsFF namespace)
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index ebc4f09edb..57a0195d23 100755
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -155,7 +155,7 @@ void LLViewerCamera::updateCameraLocation(const LLVector3 &center,
setOriginAndLookAt(origin, up_direction, point_of_interest);
- mVelocityDir = center - last_position ;
+ mVelocityDir = origin - last_position ;
F32 dpos = mVelocityDir.normVec() ;
LLQuaternion rotation;
rotation.shortestArc(last_axis, getAtAxis());
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 1de8493749..ee5793fe6a 100755
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -106,6 +106,7 @@ LLFrameTimer gRecentMemoryTime;
void pre_show_depth_buffer();
void post_show_depth_buffer();
void render_ui(F32 zoom_factor = 1.f, int subfield = 0);
+void swap();
void render_hud_attachments();
void render_ui_3d();
void render_ui_2d();
@@ -344,7 +345,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
// Bail out if we're in the startup state and don't want to try to
// render the world.
//
- if (LLStartUp::getStartupState() < STATE_STARTED)
+ if (LLStartUp::getStartupState() < STATE_WEARABLES_WAIT)
{
LLAppViewer::instance()->pingMainloopTimeout("Display:Startup");
display_startup();
@@ -553,6 +554,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
{
LLAppViewer::instance()->pingMainloopTimeout("Display:Disconnected");
render_ui();
+ swap();
}
//////////////////////////
@@ -1021,6 +1023,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
{
LLFastTimer t(FTM_RENDER_UI);
render_ui();
+ swap();
}
@@ -1244,8 +1247,6 @@ BOOL setup_hud_matrices(const LLRect& screen_region)
return TRUE;
}
-static LLFastTimer::DeclareTimer FTM_SWAP("Swap");
-
void render_ui(F32 zoom_factor, int subfield)
{
LLGLState::checkStates();
@@ -1322,10 +1323,16 @@ void render_ui(F32 zoom_factor, int subfield)
glh_set_current_modelview(saved_view);
gGL.popMatrix();
}
+}
+
+static LLFastTimer::DeclareTimer FTM_SWAP("Swap");
+
+void swap()
+{
+ LLFastTimer t(FTM_SWAP);
if (gDisplaySwapBuffers)
{
- LLFastTimer t(FTM_SWAP);
gViewerWindow->getWindow()->swapBuffers();
}
gDisplaySwapBuffers = TRUE;