diff options
Diffstat (limited to 'indra/llcommon/lltracerecording.h')
-rw-r--r-- | indra/llcommon/lltracerecording.h | 648 |
1 files changed, 648 insertions, 0 deletions
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h new file mode 100644 index 0000000000..085780198d --- /dev/null +++ b/indra/llcommon/lltracerecording.h @@ -0,0 +1,648 @@ +/** + * @file lltracerecording.h + * @brief Sampling object for collecting runtime statistics originating from lltrace. + * + * $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_LLTRACERECORDING_H +#define LL_LLTRACERECORDING_H + +#include "stdtypes.h" +#include "llpreprocessor.h" + +#include "lltimer.h" +#include "lltraceaccumulators.h" + +class LLStopWatchControlsMixinCommon +{ +public: + virtual ~LLStopWatchControlsMixinCommon() {} + + enum EPlayState + { + STOPPED, + PAUSED, + STARTED + }; + + void start(); + void stop(); + void pause(); + void resume(); + void restart(); + void reset(); + + bool isStarted() const { return mPlayState == STARTED; } + bool isPaused() const { return mPlayState == PAUSED; } + bool isStopped() const { return mPlayState == STOPPED; } + EPlayState getPlayState() const { return mPlayState; } + // force play state to specific value by calling appropriate handle* methods + void setPlayState(EPlayState state); + +protected: + LLStopWatchControlsMixinCommon() + : mPlayState(STOPPED) + {} + +private: + // trigger active behavior (without reset) + virtual void handleStart() = 0; + // stop active behavior + virtual void handleStop() = 0; + // clear accumulated state, can be called while started + virtual void handleReset() = 0; + + EPlayState mPlayState; +}; + +template<typename DERIVED> +class LLStopWatchControlsMixin +: public LLStopWatchControlsMixinCommon +{ +public: + + typedef LLStopWatchControlsMixin<DERIVED> self_t; + virtual void splitTo(DERIVED& other) + { + EPlayState play_state = getPlayState(); + stop(); + other.reset(); + + handleSplitTo(other); + + other.setPlayState(play_state); + } + + virtual void splitFrom(DERIVED& other) + { + static_cast<self_t&>(other).handleSplitTo(*static_cast<DERIVED*>(this)); + } +private: + self_t& operator = (const self_t& other) + { + // don't do anything, derived class must implement logic + } + + // atomically stop this object while starting the other + // no data can be missed in between stop and start + virtual void handleSplitTo(DERIVED& other) {}; + +}; + +namespace LLTrace +{ + template<typename T> + class TraceType; + + template<typename T> + class CountStatHandle; + + template<typename T> + class SampleStatHandle; + + template<typename T> + class EventStatHandle; + + class MemStatHandle; + + template<typename T> + struct RelatedTypes + { + typedef F64 fractional_t; + typedef T sum_t; + }; + + template<typename T, typename UNIT_T> + struct RelatedTypes<LLUnit<T, UNIT_T> > + { + typedef LLUnit<typename RelatedTypes<T>::fractional_t, UNIT_T> fractional_t; + typedef LLUnit<typename RelatedTypes<T>::sum_t, UNIT_T> sum_t; + }; + + template<> + struct RelatedTypes<bool> + { + typedef F64 fractional_t; + typedef S32 sum_t; + }; + + class Recording + : public LLStopWatchControlsMixin<Recording> + { + public: + Recording(EPlayState state = LLStopWatchControlsMixinCommon::STOPPED); + + Recording(const Recording& other); + ~Recording(); + + Recording& operator = (const Recording& other); + + // accumulate data from subsequent, non-overlapping recording + void appendRecording(Recording& other); + + // grab latest recorded data + void update(); + + // ensure that buffers are exclusively owned by this recording + void makeUnique() { mBuffers.makeUnique(); } + + // Timer accessors + F64Seconds getSum(const TraceType<TimeBlockAccumulator>& stat); + F64Seconds getSum(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat); + S32 getSum(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat); + + F64Seconds getPerSec(const TraceType<TimeBlockAccumulator>& stat); + F64Seconds getPerSec(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat); + F32 getPerSec(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat); + + // Memory accessors + bool hasValue(const TraceType<MemStatAccumulator>& stat); + + F64Kilobytes getMin(const TraceType<MemStatAccumulator>& stat); + F64Kilobytes getMean(const TraceType<MemStatAccumulator>& stat); + F64Kilobytes getMax(const TraceType<MemStatAccumulator>& stat); + F64Kilobytes getStandardDeviation(const TraceType<MemStatAccumulator>& stat); + F64Kilobytes getLastValue(const TraceType<MemStatAccumulator>& stat); + + F64Kilobytes getSum(const TraceType<MemStatAccumulator::AllocationFacet>& stat); + F64Kilobytes getPerSec(const TraceType<MemStatAccumulator::AllocationFacet>& stat); + S32 getSampleCount(const TraceType<MemStatAccumulator::AllocationFacet>& stat); + + F64Kilobytes getSum(const TraceType<MemStatAccumulator::DeallocationFacet>& stat); + F64Kilobytes getPerSec(const TraceType<MemStatAccumulator::DeallocationFacet>& stat); + S32 getSampleCount(const TraceType<MemStatAccumulator::DeallocationFacet>& stat); + + // CountStatHandle accessors + F64 getSum(const TraceType<CountAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::sum_t getSum(const CountStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::sum_t)getSum(static_cast<const TraceType<CountAccumulator>&> (stat)); + } + + F64 getPerSec(const TraceType<CountAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::fractional_t getPerSec(const CountStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::fractional_t)getPerSec(static_cast<const TraceType<CountAccumulator>&> (stat)); + } + + S32 getSampleCount(const TraceType<CountAccumulator>& stat); + + + // SampleStatHandle accessors + bool hasValue(const TraceType<SampleAccumulator>& stat); + + F64 getMin(const TraceType<SampleAccumulator>& stat); + template <typename T> + T getMin(const SampleStatHandle<T>& stat) + { + return (T)getMin(static_cast<const TraceType<SampleAccumulator>&> (stat)); + } + + F64 getMax(const TraceType<SampleAccumulator>& stat); + template <typename T> + T getMax(const SampleStatHandle<T>& stat) + { + return (T)getMax(static_cast<const TraceType<SampleAccumulator>&> (stat)); + } + + F64 getMean(const TraceType<SampleAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::fractional_t getMean(SampleStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::fractional_t)getMean(static_cast<const TraceType<SampleAccumulator>&> (stat)); + } + + F64 getStandardDeviation(const TraceType<SampleAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::fractional_t getStandardDeviation(const SampleStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::fractional_t)getStandardDeviation(static_cast<const TraceType<SampleAccumulator>&> (stat)); + } + + F64 getLastValue(const TraceType<SampleAccumulator>& stat); + template <typename T> + T getLastValue(const SampleStatHandle<T>& stat) + { + return (T)getLastValue(static_cast<const TraceType<SampleAccumulator>&> (stat)); + } + + S32 getSampleCount(const TraceType<SampleAccumulator>& stat); + + // EventStatHandle accessors + bool hasValue(const TraceType<EventAccumulator>& stat); + + F64 getSum(const TraceType<EventAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::sum_t getSum(const EventStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::sum_t)getSum(static_cast<const TraceType<EventAccumulator>&> (stat)); + } + + F64 getMin(const TraceType<EventAccumulator>& stat); + template <typename T> + T getMin(const EventStatHandle<T>& stat) + { + return (T)getMin(static_cast<const TraceType<EventAccumulator>&> (stat)); + } + + F64 getMax(const TraceType<EventAccumulator>& stat); + template <typename T> + T getMax(const EventStatHandle<T>& stat) + { + return (T)getMax(static_cast<const TraceType<EventAccumulator>&> (stat)); + } + + F64 getMean(const TraceType<EventAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::fractional_t getMean(EventStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::fractional_t)getMean(static_cast<const TraceType<EventAccumulator>&> (stat)); + } + + F64 getStandardDeviation(const TraceType<EventAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::fractional_t getStandardDeviation(const EventStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::fractional_t)getStandardDeviation(static_cast<const TraceType<EventAccumulator>&> (stat)); + } + + F64 getLastValue(const TraceType<EventAccumulator>& stat); + template <typename T> + T getLastValue(const EventStatHandle<T>& stat) + { + return (T)getLastValue(static_cast<const TraceType<EventAccumulator>&> (stat)); + } + + S32 getSampleCount(const TraceType<EventAccumulator>& stat); + + F64Seconds getDuration() const { return mElapsedSeconds; } + + protected: + friend class ThreadRecorder; + + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(Recording& other); + + // returns data for current thread + class ThreadRecorder* getThreadRecorder(); + + LLTimer mSamplingTimer; + F64Seconds mElapsedSeconds; + LLCopyOnWritePointer<AccumulatorBufferGroup> mBuffers; + bool mInHandOff; + + }; + + class LL_COMMON_API PeriodicRecording + : public LLStopWatchControlsMixin<PeriodicRecording> + { + public: + PeriodicRecording(S32 num_periods, EPlayState state = STOPPED); + + void nextPeriod(); + S32 getNumRecordedPeriods() { return mNumPeriods; } + + F64Seconds getDuration() const; + + void appendPeriodicRecording(PeriodicRecording& other); + void appendRecording(Recording& recording); + Recording& getLastRecording(); + const Recording& getLastRecording() const; + Recording& getCurRecording(); + const Recording& getCurRecording() const; + Recording& getPrevRecording(S32 offset); + const Recording& getPrevRecording(S32 offset) const; + Recording snapshotCurRecording() const; + + template <typename T> + S32 getSampleCount(const TraceType<T>& stat, S32 num_periods = S32_MAX) + { + S32 total_periods = mNumPeriods; + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + S32 num_samples = 0; + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + num_samples += recording.getSampleCount(stat); + } + return num_samples; + } + + // + // PERIODIC MIN + // + + // catch all for stats that have a defined sum + template <typename T> + typename T::value_t getPeriodMin(const TraceType<T>& stat, S32 num_periods = S32_MAX) + { + S32 total_periods = mNumPeriods; + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + typename T::value_t min_val = std::numeric_limits<typename T::value_t>::max(); + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + min_val = llmin(min_val, recording.getSum(stat)); + } + return min_val; + } + + template<typename T> + T getPeriodMin(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return T(getPeriodMin(static_cast<const TraceType<CountAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMin(const TraceType<SampleAccumulator>& stat, S32 num_periods = S32_MAX); + template<typename T> + T getPeriodMin(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return T(getPeriodMin(static_cast<const TraceType<SampleAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMin(const TraceType<EventAccumulator>& stat, S32 num_periods = S32_MAX); + template<typename T> + T getPeriodMin(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return T(getPeriodMin(static_cast<const TraceType<EventAccumulator>&>(stat), num_periods)); + } + + F64Kilobytes getPeriodMin(const TraceType<MemStatAccumulator>& stat, S32 num_periods = S32_MAX); + F64Kilobytes getPeriodMin(const MemStatHandle& stat, S32 num_periods = S32_MAX); + + template <typename T> + typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMinPerSec(const TraceType<T>& stat, S32 num_periods = S32_MAX) + { + S32 total_periods = mNumPeriods; + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + typename RelatedTypes<typename T::value_t>::fractional_t min_val = std::numeric_limits<F64>::max(); + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + min_val = llmin(min_val, recording.getPerSec(stat)); + } + return (typename RelatedTypes<typename T::value_t>::fractional_t) min_val; + } + + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMinPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return typename RelatedTypes<T>::fractional_t(getPeriodMinPerSec(static_cast<const TraceType<CountAccumulator>&>(stat), num_periods)); + } + + // + // PERIODIC MAX + // + + // catch all for stats that have a defined sum + template <typename T> + typename T::value_t getPeriodMax(const TraceType<T>& stat, S32 num_periods = S32_MAX) + { + S32 total_periods = mNumPeriods; + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + typename T::value_t max_val = std::numeric_limits<typename T::value_t>::min(); + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + max_val = llmax(max_val, recording.getSum(stat)); + } + return max_val; + } + + template<typename T> + T getPeriodMax(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return T(getPeriodMax(static_cast<const TraceType<CountAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMax(const TraceType<SampleAccumulator>& stat, S32 num_periods = S32_MAX); + template<typename T> + T getPeriodMax(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return T(getPeriodMax(static_cast<const TraceType<SampleAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMax(const TraceType<EventAccumulator>& stat, S32 num_periods = S32_MAX); + template<typename T> + T getPeriodMax(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return T(getPeriodMax(static_cast<const TraceType<EventAccumulator>&>(stat), num_periods)); + } + + F64Kilobytes getPeriodMax(const TraceType<MemStatAccumulator>& stat, S32 num_periods = S32_MAX); + F64Kilobytes getPeriodMax(const MemStatHandle& stat, S32 num_periods = S32_MAX); + + template <typename T> + typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMaxPerSec(const TraceType<T>& stat, S32 num_periods = S32_MAX) + { + S32 total_periods = mNumPeriods; + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + F64 max_val = std::numeric_limits<F64>::min(); + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + max_val = llmax(max_val, recording.getPerSec(stat)); + } + return (typename RelatedTypes<typename T::value_t>::fractional_t)max_val; + } + + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMaxPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return typename RelatedTypes<T>::fractional_t(getPeriodMaxPerSec(static_cast<const TraceType<CountAccumulator>&>(stat), num_periods)); + } + + // + // PERIODIC MEAN + // + + // catch all for stats that have a defined sum + template <typename T> + typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMean(const TraceType<T >& stat, S32 num_periods = S32_MAX) + { + S32 total_periods = mNumPeriods; + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + typename RelatedTypes<typename T::value_t>::fractional_t mean(0); + + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.getDuration() > (F32Seconds)0.f) + { + mean += recording.getSum(stat); + } + } + return (num_periods + ? typename RelatedTypes<typename T::value_t>::fractional_t(mean / num_periods) + : typename RelatedTypes<typename T::value_t>::fractional_t(NaN)); + } + + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMean(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const TraceType<CountAccumulator>&>(stat), num_periods)); + } + F64 getPeriodMean(const TraceType<SampleAccumulator>& stat, S32 num_periods = S32_MAX); + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMean(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const TraceType<SampleAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMean(const TraceType<EventAccumulator>& stat, S32 num_periods = S32_MAX); + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMean(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const TraceType<EventAccumulator>&>(stat), num_periods)); + } + + F64Kilobytes getPeriodMean(const TraceType<MemStatAccumulator>& stat, S32 num_periods = S32_MAX); + F64Kilobytes getPeriodMean(const MemStatHandle& stat, S32 num_periods = S32_MAX); + + template <typename T> + typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMeanPerSec(const TraceType<T>& stat, S32 num_periods = S32_MAX) + { + S32 total_periods = mNumPeriods; + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + typename RelatedTypes<typename T::value_t>::fractional_t mean = 0; + + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.getDuration() > (F32Seconds)0.f) + { + mean += recording.getPerSec(stat); + } + } + + return (num_periods + ? typename RelatedTypes<typename T::value_t>::fractional_t(mean / num_periods) + : typename RelatedTypes<typename T::value_t>::fractional_t(NaN)); + } + + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMeanPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return typename RelatedTypes<T>::fractional_t(getPeriodMeanPerSec(static_cast<const TraceType<CountAccumulator>&>(stat), num_periods)); + } + + // + // PERIODIC STANDARD DEVIATION + // + + F64 getPeriodStandardDeviation(const TraceType<SampleAccumulator>& stat, S32 num_periods = S32_MAX); + + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const TraceType<SampleAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodStandardDeviation(const TraceType<EventAccumulator>& stat, S32 num_periods = S32_MAX); + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const TraceType<EventAccumulator>&>(stat), num_periods)); + } + + F64Kilobytes getPeriodStandardDeviation(const TraceType<MemStatAccumulator>& stat, S32 num_periods = S32_MAX); + F64Kilobytes getPeriodStandardDeviation(const MemStatHandle& stat, S32 num_periods = S32_MAX); + + private: + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(PeriodicRecording& other); + + private: + std::vector<Recording> mRecordingPeriods; + const bool mAutoResize; + S32 mCurPeriod; + S32 mNumPeriods; + }; + + PeriodicRecording& get_frame_recording(); + + class ExtendableRecording + : public LLStopWatchControlsMixin<ExtendableRecording> + { + public: + void extend(); + + Recording& getAcceptedRecording() { return mAcceptedRecording; } + const Recording& getAcceptedRecording() const {return mAcceptedRecording;} + + Recording& getPotentialRecording() { return mPotentialRecording; } + const Recording& getPotentialRecording() const { return mPotentialRecording;} + + private: + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(ExtendableRecording& other); + + private: + Recording mAcceptedRecording; + Recording mPotentialRecording; + }; + + class ExtendablePeriodicRecording + : public LLStopWatchControlsMixin<ExtendablePeriodicRecording> + { + public: + ExtendablePeriodicRecording(); + void extend(); + + PeriodicRecording& getResults() { return mAcceptedRecording; } + const PeriodicRecording& getResults() const {return mAcceptedRecording;} + + void nextPeriod() { mPotentialRecording.nextPeriod(); } + + private: + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(ExtendablePeriodicRecording& other); + + private: + PeriodicRecording mAcceptedRecording; + PeriodicRecording mPotentialRecording; + }; +} + +#endif // LL_LLTRACERECORDING_H |