diff options
author | Roxanne Skelly <roxie@lindenlab.com> | 2024-05-20 14:36:14 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-20 14:36:14 -0700 |
commit | a1d7d2abc304b59fbca26f0ca23c926762be10a1 (patch) | |
tree | fcb3901b838af753e40c2ddd1ce84b95a6c2f603 /indra/llcommon/lltraceaccumulators.h | |
parent | f51797f088808029745161854aa86b775f041a64 (diff) | |
parent | 3a212d9608492ae64a3a32f80790371b90be9e9e (diff) |
Merge pull request #1532 from secondlife/roxie/webrtc-voice
[WebRTC] Merge from main
Diffstat (limited to 'indra/llcommon/lltraceaccumulators.h')
-rw-r--r-- | indra/llcommon/lltraceaccumulators.h | 1018 |
1 files changed, 509 insertions, 509 deletions
diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h index b9d577be9e..692bbe5acf 100644 --- a/indra/llcommon/lltraceaccumulators.h +++ b/indra/llcommon/lltraceaccumulators.h @@ -39,515 +39,515 @@ namespace LLTrace { - const F64 NaN = std::numeric_limits<double>::quiet_NaN(); - - enum EBufferAppendType - { - SEQUENTIAL, - NON_SEQUENTIAL - }; - - template<typename ACCUMULATOR> - class AccumulatorBuffer : public LLRefCount - { - typedef AccumulatorBuffer<ACCUMULATOR> self_t; - static const S32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 32; - private: - struct StaticAllocationMarker { }; - - AccumulatorBuffer(StaticAllocationMarker m) - : mStorageSize(0), - mStorage(NULL) - {} - - public: - AccumulatorBuffer() - : mStorageSize(0), - mStorage(NULL) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - const AccumulatorBuffer& other = *getDefaultBuffer(); - resize(sNextStorageSlot); - for (S32 i = 0; i < sNextStorageSlot; i++) - { - mStorage[i] = other.mStorage[i]; - } - } - - ~AccumulatorBuffer() - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - if (isCurrent()) - { - 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]; - } - - - AccumulatorBuffer(const AccumulatorBuffer& other) - : mStorageSize(0), - mStorage(NULL) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - resize(sNextStorageSlot); - for (S32 i = 0; i < sNextStorageSlot; i++) - { - mStorage[i] = other.mStorage[i]; - } - } - - void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other, EBufferAppendType append_type) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot); - for (size_t i = 0; i < sNextStorageSlot; i++) - { - mStorage[i].addSamples(other.mStorage[i], append_type); - } - } - - void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - 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) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - llassert(mStorageSize >= sNextStorageSlot); - for (size_t i = 0; i < sNextStorageSlot; i++) - { - mStorage[i].reset(other ? &other->mStorage[i] : NULL); - } - } - - void sync(F64SecondsImplicit time_stamp) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - llassert(mStorageSize >= sNextStorageSlot); - for (size_t i = 0; i < sNextStorageSlot; i++) - { - mStorage[i].sync(time_stamp); - } - } - - void makeCurrent() - { - LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(mStorage); - } - - bool isCurrent() const - { - return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage; - } - - static void clearCurrent() - { - LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL); - } - - // 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() - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - size_t next_slot = sNextStorageSlot++; - if (next_slot >= mStorageSize) - { - // don't perform doubling, as this should only happen during startup - // want to keep a tight bounds as we will have a lot of these buffers - resize(mStorageSize + mStorageSize / 2); - } - llassert(mStorage && next_slot < mStorageSize); - return next_slot; - } - - void resize(size_t new_size) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - 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(); - } - - size_t capacity() const - { - return mStorageSize; - } - - static size_t getNumIndices() - { - return sNextStorageSlot; - } - - static self_t* getDefaultBuffer() - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - 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; - static F64 getDefaultValue() { return NaN; } - - EventAccumulator() - : mSum(0), - mMin(F32(NaN)), - mMax(F32(NaN)), - mMean(NaN), - mSumOfSquares(0), - mNumSamples(0), - mLastValue(NaN) - {} - - void record(F64 value) - { - if (mNumSamples == 0) - { - mSum = value; - mMean = value; - mMin = value; - mMax = value; - } - else - { - mSum += value; - F64 old_mean = mMean; - mMean += (value - old_mean) / (F64)mNumSamples; - mSumOfSquares += (value - old_mean) * (value - mMean); - - if (value < mMin) { mMin = value; } - else if (value > mMax) { mMax = value; } - } - - mNumSamples++; - mLastValue = value; - } - - void addSamples(const EventAccumulator& other, EBufferAppendType append_type); - void reset(const EventAccumulator* other); - void sync(F64SecondsImplicit) {} - - F64 getSum() const { return mSum; } - F32 getMin() const { return mMin; } - F32 getMax() const { return mMax; } - F64 getLastValue() const { return mLastValue; } - F64 getMean() const { return mMean; } - F64 getStandardDeviation() const { return sqrtf(mSumOfSquares / mNumSamples); } - F64 getSumOfSquares() const { return mSumOfSquares; } - S32 getSampleCount() const { return mNumSamples; } - bool hasValue() const { return mNumSamples > 0; } - - // helper utility to calculate combined sumofsquares total - static F64 mergeSumsOfSquares(const EventAccumulator& a, const EventAccumulator& b); - - private: - F64 mSum, - mLastValue; - - F64 mMean, - mSumOfSquares; - - F32 mMin, - mMax; - - S32 mNumSamples; - }; - - - class SampleAccumulator - { - public: - typedef F64 value_t; - static F64 getDefaultValue() { return NaN; } - - SampleAccumulator() - : mSum(0), - mMin(F32(NaN)), - mMax(F32(NaN)), - mMean(NaN), - mSumOfSquares(0), - mLastSampleTimeStamp(0), - mTotalSamplingTime(0), - mNumSamples(0), - mLastValue(NaN), - mHasValue(false) - {} - - void sample(F64 value) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds(); - - // store effect of last value - sync(time_stamp); - - if (!mHasValue) - { - mHasValue = true; - - mMin = value; - mMax = value; - mMean = value; - mLastSampleTimeStamp = time_stamp; - } - else - { - if (value < mMin) { mMin = value; } - else if (value > mMax) { mMax = value; } - } - - mLastValue = value; - mNumSamples++; - } - - void addSamples(const SampleAccumulator& other, EBufferAppendType append_type); - void reset(const SampleAccumulator* other); - - void sync(F64SecondsImplicit time_stamp) - { - if (mHasValue && time_stamp != mLastSampleTimeStamp) - { - F64SecondsImplicit delta_time = time_stamp - mLastSampleTimeStamp; - mSum += mLastValue * delta_time; - mTotalSamplingTime += delta_time; - F64 old_mean = mMean; - mMean += (delta_time / mTotalSamplingTime) * (mLastValue - old_mean); - mSumOfSquares += delta_time * (mLastValue - old_mean) * (mLastValue - mMean); - } - mLastSampleTimeStamp = time_stamp; - } - - F64 getSum() const { return mSum; } - F32 getMin() const { return mMin; } - F32 getMax() const { return mMax; } - F64 getLastValue() const { return mLastValue; } - F64 getMean() const { return mMean; } - F64 getStandardDeviation() const { return sqrtf(mSumOfSquares / mTotalSamplingTime); } - F64 getSumOfSquares() const { return mSumOfSquares; } - F64SecondsImplicit getSamplingTime() const { return mTotalSamplingTime; } - S32 getSampleCount() const { return mNumSamples; } - bool hasValue() const { return mHasValue; } - - // helper utility to calculate combined sumofsquares total - static F64 mergeSumsOfSquares(const SampleAccumulator& a, const SampleAccumulator& b); - - private: - F64 mSum, - mLastValue; - - F64 mMean, - mSumOfSquares; - - F64SecondsImplicit - mLastSampleTimeStamp, - mTotalSamplingTime; - - F32 mMin, - mMax; - - S32 mNumSamples; - // distinct from mNumSamples, since we might have inherited a last value from - // a previous sampling period - bool mHasValue; - }; - - class CountAccumulator - { - public: - typedef F64 value_t; - static F64 getDefaultValue() { return 0; } - - CountAccumulator() - : mSum(0), - mNumSamples(0) - {} - - void add(F64 value) - { - mNumSamples++; - mSum += value; - } - - void addSamples(const CountAccumulator& other, EBufferAppendType /*type*/) - { - mSum += other.mSum; - mNumSamples += other.mNumSamples; - } - - void reset(const CountAccumulator* other) - { - mNumSamples = 0; - mSum = 0; - } - - void sync(F64SecondsImplicit) {} - - F64 getSum() const { return mSum; } - - S32 getSampleCount() const { return mNumSamples; } - - bool hasValue() const { return true; } - - private: - F64 mSum; - - S32 mNumSamples; - }; - - class alignas(32) TimeBlockAccumulator - { - public: - typedef F64Seconds value_t; - static F64Seconds getDefaultValue() { return F64Seconds(0); } - - typedef TimeBlockAccumulator self_t; - - // fake classes that allows us to view different facets of underlying statistic - struct CallCountFacet - { - typedef S32 value_t; - }; - - struct SelfTimeFacet - { - typedef F64Seconds value_t; - }; - - // arrays are allocated with 32 byte alignment - void *operator new [](size_t size) - { - return ll_aligned_malloc<32>(size); - } - - void operator delete[](void* ptr, size_t size) - { - ll_aligned_free<32>(ptr); - } - - TimeBlockAccumulator(); - void addSamples(const self_t& other, EBufferAppendType append_type); - void reset(const self_t* other); - void sync(F64SecondsImplicit) {} - bool hasValue() const { return true; } - - // - // members - // - U64 mTotalTimeCounter, - mSelfTimeCounter; - S32 mCalls; - class BlockTimerStatHandle* mParent; // last acknowledged parent of this time block - class BlockTimerStatHandle* 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 BlockTimerStatHandle; - - class TimeBlockTreeNode - { - public: - TimeBlockTreeNode(); - - void setParent(BlockTimerStatHandle* parent); - BlockTimerStatHandle* getParent() { return mParent; } - - BlockTimerStatHandle* mBlock; - BlockTimerStatHandle* mParent; - std::vector<BlockTimerStatHandle*> mChildren; - bool mCollapsed; - bool mNeedsSorting; - }; - - struct BlockTimerStackRecord - { - class BlockTimer* mActiveTimer; - class BlockTimerStatHandle* mTimeBlock; - U64 mChildTime; - }; - - struct AccumulatorBufferGroup : public LLRefCount - { - AccumulatorBufferGroup(); - AccumulatorBufferGroup(const AccumulatorBufferGroup&); - ~AccumulatorBufferGroup(); - - void handOffTo(AccumulatorBufferGroup& other); - void makeCurrent(); - bool isCurrent() const; - static void clearCurrent(); - - 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; - }; + const F64 NaN = std::numeric_limits<double>::quiet_NaN(); + + enum EBufferAppendType + { + SEQUENTIAL, + NON_SEQUENTIAL + }; + + template<typename ACCUMULATOR> + class AccumulatorBuffer : public LLRefCount + { + typedef AccumulatorBuffer<ACCUMULATOR> self_t; + static const S32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 32; + private: + struct StaticAllocationMarker { }; + + AccumulatorBuffer(StaticAllocationMarker m) + : mStorageSize(0), + mStorage(NULL) + {} + + public: + AccumulatorBuffer() + : mStorageSize(0), + mStorage(NULL) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + const AccumulatorBuffer& other = *getDefaultBuffer(); + resize(sNextStorageSlot); + for (S32 i = 0; i < sNextStorageSlot; i++) + { + mStorage[i] = other.mStorage[i]; + } + } + + ~AccumulatorBuffer() + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + if (isCurrent()) + { + 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]; + } + + + AccumulatorBuffer(const AccumulatorBuffer& other) + : mStorageSize(0), + mStorage(NULL) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + resize(sNextStorageSlot); + for (S32 i = 0; i < sNextStorageSlot; i++) + { + mStorage[i] = other.mStorage[i]; + } + } + + void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other, EBufferAppendType append_type) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i].addSamples(other.mStorage[i], append_type); + } + } + + void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + 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) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + llassert(mStorageSize >= sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i].reset(other ? &other->mStorage[i] : NULL); + } + } + + void sync(F64SecondsImplicit time_stamp) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + llassert(mStorageSize >= sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i].sync(time_stamp); + } + } + + void makeCurrent() + { + LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(mStorage); + } + + bool isCurrent() const + { + return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage; + } + + static void clearCurrent() + { + LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL); + } + + // 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() + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + size_t next_slot = sNextStorageSlot++; + if (next_slot >= mStorageSize) + { + // don't perform doubling, as this should only happen during startup + // want to keep a tight bounds as we will have a lot of these buffers + resize(mStorageSize + mStorageSize / 2); + } + llassert(mStorage && next_slot < mStorageSize); + return next_slot; + } + + void resize(size_t new_size) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + 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(); + } + + size_t capacity() const + { + return mStorageSize; + } + + static size_t getNumIndices() + { + return sNextStorageSlot; + } + + static self_t* getDefaultBuffer() + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + 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; + static F64 getDefaultValue() { return NaN; } + + EventAccumulator() + : mSum(0), + mMin(F32(NaN)), + mMax(F32(NaN)), + mMean(NaN), + mSumOfSquares(0), + mNumSamples(0), + mLastValue(NaN) + {} + + void record(F64 value) + { + if (mNumSamples == 0) + { + mSum = value; + mMean = value; + mMin = value; + mMax = value; + } + else + { + mSum += value; + F64 old_mean = mMean; + mMean += (value - old_mean) / (F64)mNumSamples; + mSumOfSquares += (value - old_mean) * (value - mMean); + + if (value < mMin) { mMin = value; } + else if (value > mMax) { mMax = value; } + } + + mNumSamples++; + mLastValue = value; + } + + void addSamples(const EventAccumulator& other, EBufferAppendType append_type); + void reset(const EventAccumulator* other); + void sync(F64SecondsImplicit) {} + + F64 getSum() const { return mSum; } + F32 getMin() const { return mMin; } + F32 getMax() const { return mMax; } + F64 getLastValue() const { return mLastValue; } + F64 getMean() const { return mMean; } + F64 getStandardDeviation() const { return sqrtf(mSumOfSquares / mNumSamples); } + F64 getSumOfSquares() const { return mSumOfSquares; } + S32 getSampleCount() const { return mNumSamples; } + bool hasValue() const { return mNumSamples > 0; } + + // helper utility to calculate combined sumofsquares total + static F64 mergeSumsOfSquares(const EventAccumulator& a, const EventAccumulator& b); + + private: + F64 mSum, + mLastValue; + + F64 mMean, + mSumOfSquares; + + F32 mMin, + mMax; + + S32 mNumSamples; + }; + + + class SampleAccumulator + { + public: + typedef F64 value_t; + static F64 getDefaultValue() { return NaN; } + + SampleAccumulator() + : mSum(0), + mMin(F32(NaN)), + mMax(F32(NaN)), + mMean(NaN), + mSumOfSquares(0), + mLastSampleTimeStamp(0), + mTotalSamplingTime(0), + mNumSamples(0), + mLastValue(NaN), + mHasValue(false) + {} + + void sample(F64 value) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds(); + + // store effect of last value + sync(time_stamp); + + if (!mHasValue) + { + mHasValue = true; + + mMin = value; + mMax = value; + mMean = value; + mLastSampleTimeStamp = time_stamp; + } + else + { + if (value < mMin) { mMin = value; } + else if (value > mMax) { mMax = value; } + } + + mLastValue = value; + mNumSamples++; + } + + void addSamples(const SampleAccumulator& other, EBufferAppendType append_type); + void reset(const SampleAccumulator* other); + + void sync(F64SecondsImplicit time_stamp) + { + if (mHasValue && time_stamp != mLastSampleTimeStamp) + { + F64SecondsImplicit delta_time = time_stamp - mLastSampleTimeStamp; + mSum += mLastValue * delta_time; + mTotalSamplingTime += delta_time; + F64 old_mean = mMean; + mMean += (delta_time / mTotalSamplingTime) * (mLastValue - old_mean); + mSumOfSquares += delta_time * (mLastValue - old_mean) * (mLastValue - mMean); + } + mLastSampleTimeStamp = time_stamp; + } + + F64 getSum() const { return mSum; } + F32 getMin() const { return mMin; } + F32 getMax() const { return mMax; } + F64 getLastValue() const { return mLastValue; } + F64 getMean() const { return mMean; } + F64 getStandardDeviation() const { return sqrtf(mSumOfSquares / mTotalSamplingTime); } + F64 getSumOfSquares() const { return mSumOfSquares; } + F64SecondsImplicit getSamplingTime() const { return mTotalSamplingTime; } + S32 getSampleCount() const { return mNumSamples; } + bool hasValue() const { return mHasValue; } + + // helper utility to calculate combined sumofsquares total + static F64 mergeSumsOfSquares(const SampleAccumulator& a, const SampleAccumulator& b); + + private: + F64 mSum, + mLastValue; + + F64 mMean, + mSumOfSquares; + + F64SecondsImplicit + mLastSampleTimeStamp, + mTotalSamplingTime; + + F32 mMin, + mMax; + + S32 mNumSamples; + // distinct from mNumSamples, since we might have inherited a last value from + // a previous sampling period + bool mHasValue; + }; + + class CountAccumulator + { + public: + typedef F64 value_t; + static F64 getDefaultValue() { return 0; } + + CountAccumulator() + : mSum(0), + mNumSamples(0) + {} + + void add(F64 value) + { + mNumSamples++; + mSum += value; + } + + void addSamples(const CountAccumulator& other, EBufferAppendType /*type*/) + { + mSum += other.mSum; + mNumSamples += other.mNumSamples; + } + + void reset(const CountAccumulator* other) + { + mNumSamples = 0; + mSum = 0; + } + + void sync(F64SecondsImplicit) {} + + F64 getSum() const { return mSum; } + + S32 getSampleCount() const { return mNumSamples; } + + bool hasValue() const { return true; } + + private: + F64 mSum; + + S32 mNumSamples; + }; + + class alignas(32) TimeBlockAccumulator + { + public: + typedef F64Seconds value_t; + static F64Seconds getDefaultValue() { return F64Seconds(0); } + + typedef TimeBlockAccumulator self_t; + + // fake classes that allows us to view different facets of underlying statistic + struct CallCountFacet + { + typedef S32 value_t; + }; + + struct SelfTimeFacet + { + typedef F64Seconds value_t; + }; + + // arrays are allocated with 32 byte alignment + void *operator new [](size_t size) + { + return ll_aligned_malloc<32>(size); + } + + void operator delete[](void* ptr, size_t size) + { + ll_aligned_free<32>(ptr); + } + + TimeBlockAccumulator(); + void addSamples(const self_t& other, EBufferAppendType append_type); + void reset(const self_t* other); + void sync(F64SecondsImplicit) {} + bool hasValue() const { return true; } + + // + // members + // + U64 mTotalTimeCounter, + mSelfTimeCounter; + S32 mCalls; + class BlockTimerStatHandle* mParent; // last acknowledged parent of this time block + class BlockTimerStatHandle* 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 BlockTimerStatHandle; + + class TimeBlockTreeNode + { + public: + TimeBlockTreeNode(); + + void setParent(BlockTimerStatHandle* parent); + BlockTimerStatHandle* getParent() { return mParent; } + + BlockTimerStatHandle* mBlock; + BlockTimerStatHandle* mParent; + std::vector<BlockTimerStatHandle*> mChildren; + bool mCollapsed; + bool mNeedsSorting; + }; + + struct BlockTimerStackRecord + { + class BlockTimer* mActiveTimer; + class BlockTimerStatHandle* mTimeBlock; + U64 mChildTime; + }; + + struct AccumulatorBufferGroup : public LLRefCount + { + AccumulatorBufferGroup(); + AccumulatorBufferGroup(const AccumulatorBufferGroup&); + ~AccumulatorBufferGroup(); + + void handOffTo(AccumulatorBufferGroup& other); + void makeCurrent(); + bool isCurrent() const; + static void clearCurrent(); + + 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; + }; } #endif // LL_LLTRACEACCUMULATORS_H |