diff options
-rw-r--r-- | indra/llcommon/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/llcommon/lltrace.cpp | 195 | ||||
-rw-r--r-- | indra/llcommon/lltrace.h | 143 | ||||
-rw-r--r-- | indra/llcommon/lltracerecording.cpp | 54 | ||||
-rw-r--r-- | indra/llcommon/lltracerecording.h | 30 | ||||
-rw-r--r-- | indra/llcommon/lltracethreadrecorder.cpp | 219 | ||||
-rw-r--r-- | indra/llcommon/lltracethreadrecorder.h | 124 |
7 files changed, 450 insertions, 317 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 471558ea01..c0e9266aa9 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -102,6 +102,7 @@ set(llcommon_SOURCE_FILES lltimer.cpp lltrace.cpp lltracerecording.cpp + lltracethreadrecorder.cpp lluri.cpp lluuid.cpp llworkerthread.cpp @@ -245,6 +246,7 @@ set(llcommon_HEADER_FILES lltimer.h lltrace.h lltracerecording.h + lltracethreadrecorder.h lltreeiterators.h lltypeinfolookup.h llunit.h diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp index 6d928721de..2b1c8d8ce8 100644 --- a/indra/llcommon/lltrace.cpp +++ b/indra/llcommon/lltrace.cpp @@ -44,206 +44,19 @@ void cleanup() gMasterThreadRecorder = NULL; } -LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder() -{ - static LLThreadLocalPointer<ThreadRecorder> s_thread_recorder; - return s_thread_recorder; - -} - -BlockTimer::Recorder::StackEntry BlockTimer::sCurRecorder; - - - MasterThreadRecorder& getMasterThreadRecorder() { llassert(gMasterThreadRecorder != NULL); return *gMasterThreadRecorder; } -/////////////////////////////////////////////////////////////////////// -// ThreadRecorder -/////////////////////////////////////////////////////////////////////// - -ThreadRecorder::ThreadRecorder() -: mPrimaryRecording(NULL) -{ - get_thread_recorder() = this; - mFullRecording.start(); -} - -ThreadRecorder::ThreadRecorder( const ThreadRecorder& other ) -: mFullRecording(other.mFullRecording), - mPrimaryRecording(NULL) -{ - get_thread_recorder() = this; - mFullRecording.start(); -} - -ThreadRecorder::~ThreadRecorder() -{ - get_thread_recorder() = NULL; -} - -//TODO: remove this and use llviewerstats recording -Recording* ThreadRecorder::getPrimaryRecording() -{ - return mPrimaryRecording; -} - -void ThreadRecorder::activate( Recording* recording ) -{ - mActiveRecordings.push_front(ActiveRecording(mPrimaryRecording, recording)); - mActiveRecordings.front().mBaseline.makePrimary(); - mPrimaryRecording = &mActiveRecordings.front().mBaseline; -} - -//TODO: consider merging results down the list to one past the buffered item. -// this would require 2 buffers per sampler, to separate current total from running total - -void ThreadRecorder::deactivate( Recording* recording ) -{ - for (std::list<ActiveRecording>::iterator it = mActiveRecordings.begin(), end_it = mActiveRecordings.end(); - it != end_it; - ++it) - { - std::list<ActiveRecording>::iterator next_it = it; - if (++next_it != mActiveRecordings.end()) - { - next_it->mergeMeasurements((*it)); - } - - it->flushAccumulators(mPrimaryRecording); - - if (it->mTargetRecording == recording) - { - if (next_it != mActiveRecordings.end()) - { - next_it->mBaseline.makePrimary(); - mPrimaryRecording = &next_it->mBaseline; - } - mActiveRecordings.erase(it); - break; - } - } -} - -ThreadRecorder::ActiveRecording::ActiveRecording( Recording* source, Recording* target ) -: mTargetRecording(target) -{ - // take snapshots of current values rates and timers - if (source) - { - mBaseline.mRates.write()->copyFrom(*source->mRates); - mBaseline.mStackTimers.write()->copyFrom(*source->mStackTimers); - } -} - -void ThreadRecorder::ActiveRecording::mergeMeasurements(ThreadRecorder::ActiveRecording& other) -{ - mBaseline.mMeasurements.write()->mergeSamples(*other.mBaseline.mMeasurements); -} - -void ThreadRecorder::ActiveRecording::flushAccumulators(Recording* current) -{ - // accumulate statistics-like measurements - mTargetRecording->mMeasurements.write()->mergeSamples(*mBaseline.mMeasurements); - // for rate-like measurements, merge total change since baseline - mTargetRecording->mRates.write()->mergeDeltas(*mBaseline.mRates, *current->mRates); - mTargetRecording->mStackTimers.write()->mergeDeltas(*mBaseline.mStackTimers, *current->mStackTimers); - // reset baselines - mBaseline.mRates.write()->copyFrom(*current->mRates); - mBaseline.mStackTimers.write()->copyFrom(*current->mStackTimers); -} - -/////////////////////////////////////////////////////////////////////// -// SlaveThreadRecorder -/////////////////////////////////////////////////////////////////////// - -SlaveThreadRecorder::SlaveThreadRecorder() -: ThreadRecorder(getMasterThreadRecorder()) -{ - getMasterThreadRecorder().addSlaveThread(this); -} - -SlaveThreadRecorder::~SlaveThreadRecorder() -{ - getMasterThreadRecorder().removeSlaveThread(this); -} - -void SlaveThreadRecorder::pushToMaster() -{ - mFullRecording.stop(); - { - LLMutexLock(getMasterThreadRecorder().getSlaveListMutex()); - mSharedData.copyFrom(mFullRecording); - } - mFullRecording.start(); -} - -void SlaveThreadRecorder::SharedData::copyFrom( const Recording& source ) -{ - LLMutexLock lock(&mRecorderMutex); - mRecorder.mergeSamples(source); -} - -void SlaveThreadRecorder::SharedData::copyTo( Recording& sink ) -{ - LLMutexLock lock(&mRecorderMutex); - sink.mergeSamples(mRecorder); -} - -/////////////////////////////////////////////////////////////////////// -// MasterThreadRecorder -/////////////////////////////////////////////////////////////////////// - -void MasterThreadRecorder::pullFromSlaveThreads() -{ - LLMutexLock lock(&mSlaveListMutex); - - for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end(); - it != end_it; - ++it) - { - (*it)->mRecorder->mSharedData.copyTo((*it)->mSlaveRecording); - } -} - -void MasterThreadRecorder::addSlaveThread( class SlaveThreadRecorder* child ) -{ - LLMutexLock lock(&mSlaveListMutex); - - mSlaveThreadRecorders.push_back(new SlaveThreadRecorderProxy(child)); -} - -void MasterThreadRecorder::removeSlaveThread( class SlaveThreadRecorder* child ) +LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder() { - LLMutexLock lock(&mSlaveListMutex); + static LLThreadLocalPointer<ThreadRecorder> s_thread_recorder; + return s_thread_recorder; - for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end(); - it != end_it; - ++it) - { - if ((*it)->mRecorder == child) - { - mSlaveThreadRecorders.erase(it); - break; - } - } } -void MasterThreadRecorder::pushToMaster() -{} - -MasterThreadRecorder::MasterThreadRecorder() -{} - -/////////////////////////////////////////////////////////////////////// -// MasterThreadRecorder::SlaveThreadTraceProxy -/////////////////////////////////////////////////////////////////////// - -MasterThreadRecorder::SlaveThreadRecorderProxy::SlaveThreadRecorderProxy( class SlaveThreadRecorder* recorder) -: mRecorder(recorder) -{} +BlockTimer::Recorder::StackEntry BlockTimer::sCurRecorder; } diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h index 6a889f74df..d83ea77363 100644 --- a/indra/llcommon/lltrace.h +++ b/indra/llcommon/lltrace.h @@ -30,11 +30,10 @@ #include "stdtypes.h" #include "llpreprocessor.h" -#include "llmutex.h" #include "llmemory.h" -#include "lltimer.h" #include "llrefcount.h" #include "lltracerecording.h" +#include "lltracethreadrecorder.h" #include "llunit.h" #include <list> @@ -171,7 +170,7 @@ namespace LLTrace template<typename ACCUMULATOR> LLThreadLocalPointer<ACCUMULATOR> AccumulatorBuffer<ACCUMULATOR>::sPrimaryStorage; template<typename ACCUMULATOR> - class LL_COMMON_API TraceType + class LL_COMMON_API TraceType { public: TraceType(const std::string& name) @@ -186,6 +185,7 @@ namespace LLTrace } ACCUMULATOR& getAccumulator(AccumulatorBuffer<ACCUMULATOR>* buffer) { return (*buffer)[mAccumulatorIndex]; } + const ACCUMULATOR& getAccumulator(AccumulatorBuffer<ACCUMULATOR>* buffer) const { return (*buffer)[mAccumulatorIndex]; } protected: std::string mName; @@ -265,11 +265,11 @@ namespace LLTrace mMax = 0; } - T getSum() { return mSum; } - T getMin() { return mMin; } - T getMax() { return mMax; } - F32 getMean() { return mMean; } - F32 getStandardDeviation() { return mStandardDeviation; } + T getSum() const { return mSum; } + T getMin() const { return mMin; } + T getMax() const { return mMax; } + F32 getMean() const { return mMean; } + F32 getStandardDeviation() const { return mStandardDeviation; } private: T mSum, @@ -315,7 +315,7 @@ namespace LLTrace mSum = 0; } - T getSum() { return mSum; } + T getSum() const { return mSum; } private: T mSum; @@ -355,13 +355,6 @@ namespace LLTrace { base_measurement_t::sample(value.get()); } - - template<typename UNIT_T> - typename T::value_t get() - { - UNIT_T value(*this); - return value.get(); - } }; template <typename T, typename IS_UNIT = void> @@ -395,14 +388,35 @@ namespace LLTrace { getPrimaryAccumulator().add(value.get()); } + }; - template<typename UNIT_T> - typename T::value_t get() + template <typename T> + class LL_COMMON_API Count + { + public: + Count(const std::string& name) + : mIncrease(name + "_increase"), + mDecrease(name + "_decrease"), + mTotal(name) + {} + + void count(T value) { - UNIT_T value(*this); - return value.get(); + if (value < 0) + { + mDecrease.add(value * -1); + } + else + { + mIncrease.add(value); + } + mTotal.add(value); } - + private: + friend class LLTrace::Recording; + Rate<T> mIncrease; + Rate<T> mDecrease; + Rate<T> mTotal; }; class LL_COMMON_API TimerAccumulator @@ -527,93 +541,6 @@ namespace LLTrace static Recorder::StackEntry sCurRecorder; }; - - class Recording; - - class LL_COMMON_API ThreadRecorder - { - public: - ThreadRecorder(); - ThreadRecorder(const ThreadRecorder& other); - - virtual ~ThreadRecorder(); - - void activate(Recording* recording); - void deactivate(Recording* recording); - - virtual void pushToMaster() = 0; - - Recording* getPrimaryRecording(); - protected: - struct ActiveRecording - { - ActiveRecording(Recording* source, Recording* target); - - Recording* mTargetRecording; - Recording mBaseline; - - void mergeMeasurements(ActiveRecording& other); - void flushAccumulators(Recording* current); - }; - Recording* mPrimaryRecording; - Recording mFullRecording; - std::list<ActiveRecording> mActiveRecordings; - }; - - class LL_COMMON_API MasterThreadRecorder : public ThreadRecorder - { - public: - MasterThreadRecorder(); - - void addSlaveThread(class SlaveThreadRecorder* child); - void removeSlaveThread(class SlaveThreadRecorder* child); - - /*virtual */ void pushToMaster(); - - // call this periodically to gather stats data from slave threads - void pullFromSlaveThreads(); - - LLMutex* getSlaveListMutex() { return &mSlaveListMutex; } - - private: - struct SlaveThreadRecorderProxy - { - SlaveThreadRecorderProxy(class SlaveThreadRecorder* recorder); - - class SlaveThreadRecorder* mRecorder; - Recording mSlaveRecording; - private: - //no need to copy these and then have to duplicate the storage - SlaveThreadRecorderProxy(const SlaveThreadRecorderProxy& other) {} - }; - typedef std::list<SlaveThreadRecorderProxy*> slave_thread_recorder_list_t; - - slave_thread_recorder_list_t mSlaveThreadRecorders; - LLMutex mSlaveListMutex; - }; - - class LL_COMMON_API SlaveThreadRecorder : public ThreadRecorder - { - public: - SlaveThreadRecorder(); - ~SlaveThreadRecorder(); - - // call this periodically to gather stats data for master thread to consume - /*virtual*/ void pushToMaster(); - - MasterThreadRecorder* mMaster; - - class SharedData - { - public: - void copyFrom(const Recording& source); - void copyTo(Recording& sink); - private: - LLMutex mRecorderMutex; - Recording mRecorder; - }; - SharedData mSharedData; - }; } #endif // LL_LLTRACE_H diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp index 95cdb44e4b..e4cff551f9 100644 --- a/indra/llcommon/lltracerecording.cpp +++ b/indra/llcommon/lltracerecording.cpp @@ -110,46 +110,80 @@ void Recording::mergeDeltas(const Recording& baseline, const Recording& target) } -F32 Recording::getSum( Rate<F32>& stat ) +F32 Recording::getSum(const Rate<F32>& stat) { return stat.getAccumulator(mRates).getSum(); } -F32 Recording::getSum( Measurement<F32>& stat ) +F32 Recording::getPerSec(const Rate<F32>& stat) { - return stat.getAccumulator(mMeasurements).getSum(); + return stat.getAccumulator(mRates).getSum() / mElapsedSeconds; } - -F32 Recording::getPerSec( Rate<F32>& stat ) +F32 Recording::getSum(const Measurement<F32>& stat) { - return stat.getAccumulator(mRates).getSum() / mElapsedSeconds; + return stat.getAccumulator(mMeasurements).getSum(); } -F32 Recording::getMin( Measurement<F32>& stat ) +F32 Recording::getMin(const Measurement<F32>& stat) { return stat.getAccumulator(mMeasurements).getMin(); } -F32 Recording::getMax( Measurement<F32>& stat ) +F32 Recording::getMax(const Measurement<F32>& stat) { return stat.getAccumulator(mMeasurements).getMax(); } -F32 Recording::getMean( Measurement<F32>& stat ) +F32 Recording::getMean(const Measurement<F32>& stat) { return stat.getAccumulator(mMeasurements).getMean(); } -F32 Recording::getStandardDeviation( Measurement<F32>& stat ) +F32 Recording::getStandardDeviation(const Measurement<F32>& stat) { return stat.getAccumulator(mMeasurements).getStandardDeviation(); } +F32 Recording::getSum(const Count<F32>& stat) +{ + return getSum(stat.mTotal); +} + +F32 Recording::getPerSec(const Count<F32>& stat) +{ + return getPerSec(stat.mTotal); +} + +F32 Recording::getIncrease(const Count<F32>& stat) +{ + return getSum(stat.mIncrease); +} + +F32 Recording::getIncreasePerSec(const Count<F32>& stat) +{ + return getPerSec(stat.mIncrease); +} +F32 Recording::getDecrease(const Count<F32>& stat) +{ + return getSum(stat.mDecrease); +} +F32 Recording::getDecreasePerSec(const Count<F32>& stat) +{ + return getPerSec(stat.mDecrease); +} +F32 Recording::getChurn(const Count<F32>& stat) +{ + return getIncrease(stat) + getDecrease(stat); +} +F32 Recording::getChurnPerSec(const Count<F32>& stat) +{ + return getIncreasePerSec(stat) + getDecreasePerSec(stat); +} } diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h index 4d5793014f..f9bc6b61b2 100644 --- a/indra/llcommon/lltracerecording.h +++ b/indra/llcommon/lltracerecording.h @@ -37,6 +37,7 @@ namespace LLTrace { template<typename T, typename IS_UNIT> class Rate; template<typename T, typename IS_UNIT> class Measurement; + template<typename T> class Count; template<typename T> class AccumulatorBuffer; template<typename T> class RateAccumulator; template<typename T> class MeasurementAccumulator; @@ -63,14 +64,27 @@ namespace LLTrace bool isStarted() { return mIsStarted; } - F32 getSum(Rate<F32, void>& stat); - F32 getPerSec(Rate<F32, void>& stat); - - F32 getSum(Measurement<F32, void>& stat); - F32 getMin(Measurement<F32, void>& stat); - F32 getMax(Measurement<F32, void>& stat); - F32 getMean(Measurement<F32, void>& stat); - F32 getStandardDeviation(Measurement<F32, void>& stat); + // Rate accessors + F32 getSum(const Rate<F32, void>& stat); + F32 getPerSec(const Rate<F32, void>& stat); + + // Measurement accessors + F32 getSum(const Measurement<F32, void>& stat); + F32 getPerSec(const Measurement<F32, void>& stat); + F32 getMin(const Measurement<F32, void>& stat); + F32 getMax(const Measurement<F32, void>& stat); + F32 getMean(const Measurement<F32, void>& stat); + F32 getStandardDeviation(const Measurement<F32, void>& stat); + + // Count accessors + F32 getSum(const Count<F32>& stat); + F32 getPerSec(const Count<F32>& stat); + F32 getIncrease(const Count<F32>& stat); + F32 getIncreasePerSec(const Count<F32>& stat); + F32 getDecrease(const Count<F32>& stat); + F32 getDecreasePerSec(const Count<F32>& stat); + F32 getChurn(const Count<F32>& stat); + F32 getChurnPerSec(const Count<F32>& stat); F64 getSampleTime() { return mElapsedSeconds; } diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp new file mode 100644 index 0000000000..9115a52fd1 --- /dev/null +++ b/indra/llcommon/lltracethreadrecorder.cpp @@ -0,0 +1,219 @@ +/** + * @file lltracethreadrecorder.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 "lltrace.h" + +namespace LLTrace +{ + + +/////////////////////////////////////////////////////////////////////// +// ThreadRecorder +/////////////////////////////////////////////////////////////////////// + +ThreadRecorder::ThreadRecorder() +: mPrimaryRecording(NULL) +{ + get_thread_recorder() = this; + mFullRecording.start(); +} + +ThreadRecorder::ThreadRecorder( const ThreadRecorder& other ) +: mFullRecording(other.mFullRecording), + mPrimaryRecording(NULL) +{ + get_thread_recorder() = this; + mFullRecording.start(); +} + +ThreadRecorder::~ThreadRecorder() +{ + get_thread_recorder() = NULL; +} + +//TODO: remove this and use llviewerstats recording +Recording* ThreadRecorder::getPrimaryRecording() +{ + return mPrimaryRecording; +} + +void ThreadRecorder::activate( Recording* recording ) +{ + mActiveRecordings.push_front(ActiveRecording(mPrimaryRecording, recording)); + mActiveRecordings.front().mBaseline.makePrimary(); + mPrimaryRecording = &mActiveRecordings.front().mBaseline; +} + +//TODO: consider merging results down the list to one past the buffered item. +// this would require 2 buffers per sampler, to separate current total from running total + +void ThreadRecorder::deactivate( Recording* recording ) +{ + for (std::list<ActiveRecording>::iterator it = mActiveRecordings.begin(), end_it = mActiveRecordings.end(); + it != end_it; + ++it) + { + std::list<ActiveRecording>::iterator next_it = it; + if (++next_it != mActiveRecordings.end()) + { + next_it->mergeMeasurements((*it)); + } + + it->flushAccumulators(mPrimaryRecording); + + if (it->mTargetRecording == recording) + { + if (next_it != mActiveRecordings.end()) + { + next_it->mBaseline.makePrimary(); + mPrimaryRecording = &next_it->mBaseline; + } + mActiveRecordings.erase(it); + break; + } + } +} + +ThreadRecorder::ActiveRecording::ActiveRecording( Recording* source, Recording* target ) +: mTargetRecording(target) +{ + // take snapshots of current values rates and timers + if (source) + { + mBaseline.mRates.write()->copyFrom(*source->mRates); + mBaseline.mStackTimers.write()->copyFrom(*source->mStackTimers); + } +} + +void ThreadRecorder::ActiveRecording::mergeMeasurements(ThreadRecorder::ActiveRecording& other) +{ + mBaseline.mMeasurements.write()->mergeSamples(*other.mBaseline.mMeasurements); +} + +void ThreadRecorder::ActiveRecording::flushAccumulators(Recording* current) +{ + // accumulate statistics-like measurements + mTargetRecording->mMeasurements.write()->mergeSamples(*mBaseline.mMeasurements); + // for rate-like measurements, merge total change since baseline + mTargetRecording->mRates.write()->mergeDeltas(*mBaseline.mRates, *current->mRates); + mTargetRecording->mStackTimers.write()->mergeDeltas(*mBaseline.mStackTimers, *current->mStackTimers); + // reset baselines + mBaseline.mRates.write()->copyFrom(*current->mRates); + mBaseline.mStackTimers.write()->copyFrom(*current->mStackTimers); +} + +/////////////////////////////////////////////////////////////////////// +// SlaveThreadRecorder +/////////////////////////////////////////////////////////////////////// + +SlaveThreadRecorder::SlaveThreadRecorder() +: ThreadRecorder(getMasterThreadRecorder()) +{ + getMasterThreadRecorder().addSlaveThread(this); +} + +SlaveThreadRecorder::~SlaveThreadRecorder() +{ + getMasterThreadRecorder().removeSlaveThread(this); +} + +void SlaveThreadRecorder::pushToMaster() +{ + mFullRecording.stop(); + { + LLMutexLock(getMasterThreadRecorder().getSlaveListMutex()); + mSharedData.copyFrom(mFullRecording); + } + mFullRecording.start(); +} + +void SlaveThreadRecorder::SharedData::copyFrom( const Recording& source ) +{ + LLMutexLock lock(&mRecorderMutex); + mRecorder.mergeSamples(source); +} + +void SlaveThreadRecorder::SharedData::copyTo( Recording& sink ) +{ + LLMutexLock lock(&mRecorderMutex); + sink.mergeSamples(mRecorder); +} + +/////////////////////////////////////////////////////////////////////// +// MasterThreadRecorder +/////////////////////////////////////////////////////////////////////// + +void MasterThreadRecorder::pullFromSlaveThreads() +{ + LLMutexLock lock(&mSlaveListMutex); + + for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end(); + it != end_it; + ++it) + { + (*it)->mRecorder->mSharedData.copyTo((*it)->mSlaveRecording); + } +} + +void MasterThreadRecorder::addSlaveThread( class SlaveThreadRecorder* child ) +{ + LLMutexLock lock(&mSlaveListMutex); + + mSlaveThreadRecorders.push_back(new SlaveThreadRecorderProxy(child)); +} + +void MasterThreadRecorder::removeSlaveThread( class SlaveThreadRecorder* child ) +{ + LLMutexLock lock(&mSlaveListMutex); + + for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end(); + it != end_it; + ++it) + { + if ((*it)->mRecorder == child) + { + mSlaveThreadRecorders.erase(it); + break; + } + } +} + +void MasterThreadRecorder::pushToMaster() +{} + +MasterThreadRecorder::MasterThreadRecorder() +{} + +/////////////////////////////////////////////////////////////////////// +// MasterThreadRecorder::SlaveThreadTraceProxy +/////////////////////////////////////////////////////////////////////// + +MasterThreadRecorder::SlaveThreadRecorderProxy::SlaveThreadRecorderProxy( class SlaveThreadRecorder* recorder) +: mRecorder(recorder) +{} + +} diff --git a/indra/llcommon/lltracethreadrecorder.h b/indra/llcommon/lltracethreadrecorder.h new file mode 100644 index 0000000000..40441d0447 --- /dev/null +++ b/indra/llcommon/lltracethreadrecorder.h @@ -0,0 +1,124 @@ +/** + * @file lltrace.h + * @brief Runtime statistics accumulation. + * + * $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_LLTRACETHREADRECORDER_H +#define LL_LLTRACETHREADRECORDER_H + +#include "stdtypes.h" +#include "llpreprocessor.h" + +#include "llmutex.h" +#include "lltracerecording.h" + +namespace LLTrace +{ + class LL_COMMON_API ThreadRecorder + { + public: + ThreadRecorder(); + ThreadRecorder(const ThreadRecorder& other); + + virtual ~ThreadRecorder(); + + void activate(Recording* recording); + void deactivate(Recording* recording); + + virtual void pushToMaster() = 0; + + Recording* getPrimaryRecording(); + protected: + struct ActiveRecording + { + ActiveRecording(Recording* source, Recording* target); + + Recording* mTargetRecording; + Recording mBaseline; + + void mergeMeasurements(ActiveRecording& other); + void flushAccumulators(Recording* current); + }; + Recording* mPrimaryRecording; + Recording mFullRecording; + std::list<ActiveRecording> mActiveRecordings; + }; + + class LL_COMMON_API MasterThreadRecorder : public ThreadRecorder + { + public: + MasterThreadRecorder(); + + void addSlaveThread(class SlaveThreadRecorder* child); + void removeSlaveThread(class SlaveThreadRecorder* child); + + /*virtual */ void pushToMaster(); + + // call this periodically to gather stats data from slave threads + void pullFromSlaveThreads(); + + LLMutex* getSlaveListMutex() { return &mSlaveListMutex; } + + private: + struct SlaveThreadRecorderProxy + { + SlaveThreadRecorderProxy(class SlaveThreadRecorder* recorder); + + class SlaveThreadRecorder* mRecorder; + Recording mSlaveRecording; + private: + //no need to copy these and then have to duplicate the storage + SlaveThreadRecorderProxy(const SlaveThreadRecorderProxy& other) {} + }; + typedef std::list<SlaveThreadRecorderProxy*> slave_thread_recorder_list_t; + + slave_thread_recorder_list_t mSlaveThreadRecorders; + LLMutex mSlaveListMutex; + }; + + class LL_COMMON_API SlaveThreadRecorder : public ThreadRecorder + { + public: + SlaveThreadRecorder(); + ~SlaveThreadRecorder(); + + // call this periodically to gather stats data for master thread to consume + /*virtual*/ void pushToMaster(); + + MasterThreadRecorder* mMaster; + + class SharedData + { + public: + void copyFrom(const Recording& source); + void copyTo(Recording& sink); + private: + LLMutex mRecorderMutex; + Recording mRecorder; + }; + SharedData mSharedData; + }; +} + +#endif // LL_LLTRACETHREADRECORDER_H |