summaryrefslogtreecommitdiff
path: root/indra/llcommon/lltraceaccumulators.h
diff options
context:
space:
mode:
authorRoxanne Skelly <roxie@lindenlab.com>2024-05-20 14:36:14 -0700
committerGitHub <noreply@github.com>2024-05-20 14:36:14 -0700
commita1d7d2abc304b59fbca26f0ca23c926762be10a1 (patch)
treefcb3901b838af753e40c2ddd1ce84b95a6c2f603 /indra/llcommon/lltraceaccumulators.h
parentf51797f088808029745161854aa86b775f041a64 (diff)
parent3a212d9608492ae64a3a32f80790371b90be9e9e (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.h1018
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