diff options
Diffstat (limited to 'indra')
| -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 | 
