diff options
author | Richard Linden <none@none> | 2013-06-22 12:00:18 -0700 |
---|---|---|
committer | Richard Linden <none@none> | 2013-06-22 12:00:18 -0700 |
commit | 8bddaeec6647e735415f9bd72a4e1313e11fe720 (patch) | |
tree | eca49ce086d071a28a0fabd17342cf79955768d6 /indra | |
parent | 090fa057b5ff17170d846473a2bc9ebc315c99d3 (diff) |
fixed scene load monitor resetting to eagerly due to spurious camer amotion
pulled swap() out of ui time block
cleaned up internal lltrace dependencies, factored out common accumulator definitions
Diffstat (limited to 'indra')
-rwxr-xr-x | indra/llcommon/CMakeLists.txt | 2 | ||||
-rwxr-xr-x | indra/llcommon/llthread.cpp | 4 | ||||
-rw-r--r-- | indra/llcommon/llthreadlocalstorage.cpp | 2 | ||||
-rw-r--r-- | indra/llcommon/llthreadlocalstorage.h | 31 | ||||
-rw-r--r-- | indra/llcommon/lltrace.cpp | 24 | ||||
-rw-r--r-- | indra/llcommon/lltrace.h | 594 | ||||
-rw-r--r-- | indra/llcommon/lltraceaccumulators.cpp | 112 | ||||
-rw-r--r-- | indra/llcommon/lltraceaccumulators.h | 648 | ||||
-rw-r--r-- | indra/llcommon/lltracerecording.cpp | 113 | ||||
-rw-r--r-- | indra/llcommon/lltracerecording.h | 29 | ||||
-rw-r--r-- | indra/llcommon/lltracethreadrecorder.cpp | 108 | ||||
-rw-r--r-- | indra/llcommon/lltracethreadrecorder.h | 45 | ||||
-rw-r--r-- | indra/newview/llscenemonitor.cpp | 26 | ||||
-rwxr-xr-x | indra/newview/llstartup.cpp | 54 | ||||
-rwxr-xr-x | indra/newview/llviewercamera.cpp | 2 | ||||
-rwxr-xr-x | indra/newview/llviewerdisplay.cpp | 15 |
16 files changed, 920 insertions, 889 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/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 fb7ffb0a29..36a3eb8fe8 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" @@ -80,185 +80,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> @@ -290,344 +111,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> @@ -651,23 +134,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> @@ -735,64 +201,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..5948696418 --- /dev/null +++ b/indra/llcommon/lltraceaccumulators.cpp @@ -0,0 +1,112 @@ +/** + * @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; + } + } +} + +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::flush() +{ + LLUnitImplicit<F64, LLUnits::Seconds> time_stamp = LLTimer::getTotalSeconds(); + + mSamples.flush(time_stamp); +} + +} diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h new file mode 100644 index 0000000000..7994dcc217 --- /dev/null +++ b/indra/llcommon/lltraceaccumulators.h @@ -0,0 +1,648 @@ +/** + * @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 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; + + + 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 + + }; + + 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 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; + }; + + struct AccumulatorBufferGroup : public LLRefCount + { + AccumulatorBufferGroup(); + + void handOffTo(AccumulatorBufferGroup& other); + void makePrimary(); + bool isPrimary() const; + + void append(const AccumulatorBufferGroup& other); + void merge(const AccumulatorBufferGroup& other); + void reset(AccumulatorBufferGroup* other = NULL); + void flush(); + + 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 ff1589d12d..c30f204fa4 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,11 +54,10 @@ 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; + mBuffers = other.mBuffers; LLStopWatchControlsMixin<Recording>::setPlayState(other_play_state); @@ -151,7 +72,7 @@ Recording::~Recording() { if (isStarted() && LLTrace::get_thread_recorder().notNull()) { - LLTrace::get_thread_recorder()->deactivate(this); + LLTrace::get_thread_recorder()->deactivate(mBuffers.write()); } } @@ -159,9 +80,11 @@ void Recording::update() { if (isStarted()) { - mBuffers.write()->flush(); - LLTrace::get_thread_recorder()->bringUpToDate(this); mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); + AccumulatorBufferGroup* buffers = mBuffers.write(); + buffers->flush(); + LLTrace::get_thread_recorder()->bringUpToDate(buffers); + mSamplingTimer.reset(); } } @@ -177,14 +100,15 @@ 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(); + buffers->flush(); + LLTrace::get_thread_recorder()->deactivate(buffers); } void Recording::handleSplitTo(Recording& other) @@ -192,19 +116,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()]; @@ -711,8 +630,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..38eaa47f9f 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 { @@ -106,26 +106,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 +118,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 +268,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..c571e013e1 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()) @@ -94,7 +97,7 @@ TimeBlockTreeNode* ThreadRecorder::getTimeBlockTreeNode(S32 index) } -void ThreadRecorder::activate( Recording* recording ) +void ThreadRecorder::activate( AccumulatorBufferGroup* recording ) { ActiveRecording* active_recording = new ActiveRecording(recording); if (!mActiveRecordings.empty()) @@ -106,7 +109,7 @@ void ThreadRecorder::activate( Recording* 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(); @@ -148,7 +151,7 @@ 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()) @@ -168,14 +171,14 @@ void ThreadRecorder::deactivate( Recording* recording ) } } -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,46 +200,14 @@ SlaveThreadRecorder::~SlaveThreadRecorder() } void SlaveThreadRecorder::pushToMaster() -{ - mThreadRecording.stop(); - { - LLMutexLock(mMasterRecorder.getSlaveListMutex()); - mSharedData.appendFrom(mThreadRecording); +{ + { LLMutexLock lock(&mSharedRecordingMutex); + mThreadRecordingBuffers.flush(); + 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 /////////////////////////////////////////////////////////////////////// @@ -247,29 +218,30 @@ void MasterThreadRecorder::pullFromSlaveThreads() LLFastTimer _(FTM_PULL_TRACE_DATA_FROM_SLAVES); if (mActiveRecordings.empty()) return; - LLMutexLock lock(&mSlaveListMutex); + { LLMutexLock lock(&mSlaveListMutex); - RecordingBuffers& target_recording_buffers = mActiveRecordings.back()->mPartialRecording; - for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end(); - it != end_it; - ++it) - { - // ignore block timing info for now - (*it)->mSharedData.mergeTo(target_recording_buffers); - (*it)->mSharedData.reset(); + AccumulatorBufferGroup& target_recording_buffers = mActiveRecordings.back()->mPartialRecording; + for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end(); + 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 +261,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..0680c2c590 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,14 +57,14 @@ 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; @@ -85,9 +86,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 +103,21 @@ namespace LLTrace // call this periodically to gather stats data for master thread to consume /*virtual*/ void pushToMaster(); + private: + friend class MasterThreadRecorder; 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; + 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/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/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 ¢er, 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; |