diff options
42 files changed, 1313 insertions, 1413 deletions
| diff --git a/indra/llcharacter/llkeyframewalkmotion.cpp b/indra/llcharacter/llkeyframewalkmotion.cpp index c6ca0b542e..b627110da6 100755 --- a/indra/llcharacter/llkeyframewalkmotion.cpp +++ b/indra/llcharacter/llkeyframewalkmotion.cpp @@ -383,7 +383,7 @@ BOOL LLFlyAdjustMotion::onUpdate(F32 time, U8* joint_mask)  	F32 target_roll = llclamp(ang_vel.mV[VZ], -4.f, 4.f) * roll_factor;  	// roll is critically damped interpolation between current roll and angular velocity-derived target roll -	mRoll = LLSmoothInterpolation::lerp(mRoll, target_roll, LLUnit<F32, LLUnits::Milliseconds>(100)); +	mRoll = LLSmoothInterpolation::lerp(mRoll, target_roll, LLUnits::Milliseconds::fromValue(100));  	LLQuaternion roll(mRoll, LLVector3(0.f, 0.f, 1.f));  	mPelvisState->setRotation(roll); diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index bf99a4c3a0..0c76fd46c0 100755 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -103,6 +103,7 @@ set(llcommon_SOURCE_FILES      llthreadsafequeue.cpp      lltimer.cpp      lltrace.cpp +    lltraceaccumulators.cpp      lltracerecording.cpp      lltracethreadrecorder.cpp      lluri.cpp @@ -231,6 +232,7 @@ set(llcommon_HEADER_FILES      llthreadsafequeue.h      lltimer.h      lltrace.h +	lltraceaccumulators.h      lltracerecording.h      lltracethreadrecorder.h      lltreeiterators.h diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp index c720df7555..96ec0cdefe 100755 --- a/indra/llcommon/llcommon.cpp +++ b/indra/llcommon/llcommon.cpp @@ -30,10 +30,13 @@  #include "llmemory.h"  #include "llthread.h"  #include "lltrace.h" +#include "lltracethreadrecorder.h"  //static  BOOL LLCommon::sAprInitialized = FALSE; +static LLTrace::ThreadRecorder* sMasterThreadRecorder = NULL; +  //static  void LLCommon::initClass()  { @@ -45,13 +48,20 @@ void LLCommon::initClass()  	}  	LLTimer::initClass();  	LLThreadSafeRefCount::initThreadSafeRefCount(); -	LLTrace::init(); + +	if (!sMasterThreadRecorder) +	{ +		sMasterThreadRecorder = new LLTrace::ThreadRecorder(); +		LLTrace::set_master_thread_recorder(sMasterThreadRecorder); +	}  }  //static  void LLCommon::cleanupClass()  { -	LLTrace::cleanup(); +	delete sMasterThreadRecorder; +	sMasterThreadRecorder = NULL; +	LLTrace::set_master_thread_recorder(NULL);  	LLThreadSafeRefCount::cleanupThreadSafeRefCount();  	LLTimer::cleanupClass();  	if (sAprInitialized) diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp index 60c451b137..a72f16d385 100755 --- a/indra/llcommon/llfasttimer.cpp +++ b/indra/llcommon/llfasttimer.cpp @@ -247,17 +247,18 @@ void TimeBlock::incrementalUpdateTimerTree()  void TimeBlock::updateTimes() -	{ -	U64 cur_time = getCPUClockCount64(); - +{  	// walk up stack of active timers and accumulate current time while leaving timing structures active -	BlockTimerStackRecord* stack_record	= ThreadTimerStack::getInstance(); +	BlockTimerStackRecord* stack_record	= LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance(); +	if (!stack_record) return; + +	U64 cur_time = getCPUClockCount64();  	BlockTimer* cur_timer				= stack_record->mActiveTimer;  	TimeBlockAccumulator* accumulator	= stack_record->mTimeBlock->getPrimaryAccumulator();  	while(cur_timer   		&& cur_timer->mParentTimerData.mActiveTimer != cur_timer) // root defined by parent pointing to self -		{ +	{  		U64 cumulative_time_delta = cur_time - cur_timer->mStartTime;  		accumulator->mTotalTimeCounter += cumulative_time_delta   			- (accumulator->mTotalTimeCounter  @@ -386,7 +387,7 @@ void TimeBlock::dumpCurTimes()  		U32 num_calls = last_frame_recording.getSum(timerp->callCount());  		// Don't bother with really brief times, keep output concise -		if (total_time < LLUnit<F32, LLUnits::Milliseconds>(0.1)) continue; +		if (total_time < LLUnits::Milliseconds::fromValue(0.1f)) continue;  		std::ostringstream out_str;  		TimeBlock* parent_timerp = timerp; @@ -397,7 +398,7 @@ void TimeBlock::dumpCurTimes()  		}  		out_str << timerp->getName() << " "  -			<< std::setprecision(3) << total_time.getAs<LLUnits::Milliseconds>() << " ms, " +			<< std::setprecision(3) << total_time.valueAs<LLUnits::Milliseconds>() << " ms, "  			<< num_calls << " calls";  		llinfos << out_str.str() << llendl; diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 642c99ccce..73c40749ed 100755 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -38,29 +38,6 @@ class LLMutex;  namespace LLTrace  { -struct BlockTimerStackRecord -{ -	class BlockTimer*	mActiveTimer; -	class TimeBlock*	mTimeBlock; -	U64					mChildTime; -}; - -class ThreadTimerStack  -:	public BlockTimerStackRecord,  -	public LLThreadLocalSingleton<ThreadTimerStack> -{ -	friend class LLThreadLocalSingleton<ThreadTimerStack>; -	ThreadTimerStack()  -	{} - -public: -	ThreadTimerStack& operator=(const BlockTimerStackRecord& other) -	{ -		BlockTimerStackRecord::operator=(other); -		return *this; -	} -}; -  class BlockTimer  {  public: @@ -278,7 +255,8 @@ public:  LL_FORCE_INLINE BlockTimer::BlockTimer(TimeBlock& timer)  {  #if FAST_TIMER_ON -	BlockTimerStackRecord* cur_timer_data = ThreadTimerStack::getIfExists(); +	BlockTimerStackRecord* cur_timer_data = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance(); +	if (!cur_timer_data) return;  	TimeBlockAccumulator* accumulator = timer.getPrimaryAccumulator();  	accumulator->mActiveCount++;  	mBlockStartTotalTimeCounter = accumulator->mTotalTimeCounter; @@ -300,7 +278,9 @@ LL_FORCE_INLINE BlockTimer::~BlockTimer()  {  #if FAST_TIMER_ON  	U64 total_time = TimeBlock::getCPUClockCount64() - mStartTime; -	BlockTimerStackRecord* cur_timer_data = ThreadTimerStack::getIfExists(); +	BlockTimerStackRecord* cur_timer_data = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance(); +	if (!cur_timer_data) return; +  	TimeBlockAccumulator* accumulator = cur_timer_data->mTimeBlock->getPrimaryAccumulator();  	accumulator->mCalls++; diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index 6a0a8fcb0d..c827996db1 100755 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -173,15 +173,23 @@ public:      typedef LLPointer<Type> pointer_t;  	LLCopyOnWritePointer()  +	:	mStayUnique(false)  	{}  	LLCopyOnWritePointer(Type* ptr)  -	:	LLPointer<Type>(ptr) +	:	LLPointer<Type>(ptr), +		mStayUnique(false)  	{}  	LLCopyOnWritePointer(LLPointer<Type>& ptr) -	:	LLPointer<Type>(ptr) -	{} +	:	LLPointer<Type>(ptr), +		mStayUnique(false) +	{ +		if (ptr.mForceUnique) +		{ +			makeUnique(); +		} +	}  	Type* write()  	{ @@ -199,6 +207,10 @@ public:  	const Type*	operator->() const	{ return pointer_t::mPointer; }  	const Type&	operator*() const	{ return *pointer_t::mPointer; } + +	void setStayUnique(bool stay) { makeUnique(); mStayUnique = stay; } +private: +	bool mStayUnique;  };  #endif diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index 4339f203db..3689c4728e 100755 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -470,7 +470,7 @@ S32 LLQueuedThread::processNextRequest()  			}  		} -		LLTrace::get_thread_recorder()->pushToMaster(); +		LLTrace::get_thread_recorder()->pushToParent();  	}  	S32 pending = getPending(); @@ -502,7 +502,7 @@ void LLQueuedThread::run()  		if (isQuitting())  		{ -			LLTrace::get_thread_recorder()->pushToMaster(); +			LLTrace::get_thread_recorder()->pushToParent();  			endThread();  			break;  		} diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 118568d5ef..166a4eb26d 100755 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -93,7 +93,7 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap  {  	LLThread *threadp = (LLThread *)datap; -	LLTrace::ThreadRecorder* thread_recorder = new LLTrace::SlaveThreadRecorder(LLTrace::getUIThreadRecorder()); +	LLTrace::ThreadRecorder thread_recorder(*LLTrace::get_master_thread_recorder());  #if !LL_DARWIN  	sThreadID = threadp->mID; @@ -107,8 +107,6 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap  	// We're done with the run function, this thread is done executing now.  	threadp->mStatus = STOPPED; -	delete thread_recorder; -  	return NULL;  } diff --git a/indra/llcommon/llthreadlocalstorage.cpp b/indra/llcommon/llthreadlocalstorage.cpp index 32d94331a6..03c306cc7f 100644 --- a/indra/llcommon/llthreadlocalstorage.cpp +++ b/indra/llcommon/llthreadlocalstorage.cpp @@ -88,6 +88,7 @@ void LLThreadLocalPointerBase::destroyStorage()  	}  } +//static  void LLThreadLocalPointerBase::initAllThreadLocalStorage()  {  	if (!sInitialized) @@ -102,6 +103,7 @@ void LLThreadLocalPointerBase::initAllThreadLocalStorage()  	}  } +//static  void LLThreadLocalPointerBase::destroyAllThreadLocalStorage()  {  	if (sInitialized) diff --git a/indra/llcommon/llthreadlocalstorage.h b/indra/llcommon/llthreadlocalstorage.h index a15f9185b1..3b2f5f4193 100644 --- a/indra/llcommon/llthreadlocalstorage.h +++ b/indra/llcommon/llthreadlocalstorage.h @@ -125,178 +125,6 @@ public:  };  template<typename DERIVED_TYPE> -class LLThreadLocalSingleton -{ -	typedef enum e_init_state -	{ -		UNINITIALIZED = 0, -		CONSTRUCTING, -		INITIALIZING, -		INITIALIZED, -		DELETED -	} EInitState; - -public: -	LLThreadLocalSingleton() -	{} -	 -	virtual ~LLThreadLocalSingleton() -	{ -#if LL_DARWIN -        pthread_setspecific(sInstanceKey, NULL); -#else -        sInstance = NULL; -#endif -		setInitState(DELETED); -	} - -	static void deleteSingleton() -	{ -		delete getIfExists(); -	} - -	static DERIVED_TYPE* getInstance() -	{ -        EInitState init_state = getInitState(); -		if (init_state == CONSTRUCTING) -		{ -			llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl; -		} - -		if (init_state == DELETED) -		{ -			llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl; -		} - -#if LL_DARWIN -        createTLSInstance(); -#endif -		if (!getIfExists()) -		{ -			setInitState(CONSTRUCTING); -            DERIVED_TYPE* instancep = new DERIVED_TYPE(); -#if LL_DARWIN -            S32 result = pthread_setspecific(sInstanceKey, (void*)instancep); -            if (result != 0) -            { -                llerrs << "Could not set thread local storage" << llendl; -            } -#else -			sInstance = instancep; -#endif -			setInitState(INITIALIZING); -			instancep->initSingleton(); -			setInitState(INITIALIZED); -		} - -        return getIfExists(); -	} - -	static DERIVED_TYPE* getIfExists() -	{ -#if LL_DARWIN -        return (DERIVED_TYPE*)pthread_getspecific(sInstanceKey); -#else -		return sInstance; -#endif -	} - -	// Reference version of getInstance() -	// Preferred over getInstance() as it disallows checking for NULL -	static DERIVED_TYPE& instance() -	{ -		return *getInstance(); -	} - -	// Has this singleton been created uet? -	// Use this to avoid accessing singletons before the can safely be constructed -	static bool instanceExists() -	{ -		return getInitState() == INITIALIZED; -	} - -	// Has this singleton already been deleted? -	// Use this to avoid accessing singletons from a static object's destructor -	static bool destroyed() -	{ -		return getInitState() == DELETED; -	} -private: -#if LL_DARWIN -    static void createTLSInitState() -    { -        static S32 key_created = pthread_key_create(&sInitStateKey, NULL); -        if (key_created != 0) -        { -            llerrs << "Could not create thread local storage" << llendl; -        } -    } -     -    static void createTLSInstance() -    { -        static S32 key_created = pthread_key_create(&sInstanceKey, NULL); -        if (key_created != 0) -        { -            llerrs << "Could not create thread local storage" << llendl; -        } -    } -#endif -    static EInitState getInitState() -    { -#if LL_DARWIN -        createTLSInitState(); -        return (EInitState)(int)pthread_getspecific(sInitStateKey); -#else -        return sInitState; -#endif -    } -     -    static void setInitState(EInitState state) -    { -#if LL_DARWIN -        createTLSInitState(); -        pthread_setspecific(sInitStateKey, (void*)state); -#else -        sInitState = state; -#endif -    } -	LLThreadLocalSingleton(const LLThreadLocalSingleton& other); -	virtual void initSingleton() {} - -#ifdef LL_WINDOWS -	static __declspec(thread) DERIVED_TYPE* sInstance; -	static __declspec(thread) EInitState sInitState; -#elif LL_LINUX -	static __thread DERIVED_TYPE* sInstance; -	static __thread EInitState sInitState; -#elif LL_DARWIN -    static pthread_key_t sInstanceKey; -    static pthread_key_t sInitStateKey; -#endif -}; - -#if LL_WINDOWS -template<typename DERIVED_TYPE> -__declspec(thread) DERIVED_TYPE* LLThreadLocalSingleton<DERIVED_TYPE>::sInstance = NULL; - -template<typename DERIVED_TYPE> -__declspec(thread) typename LLThreadLocalSingleton<DERIVED_TYPE>::EInitState LLThreadLocalSingleton<DERIVED_TYPE>::sInitState = LLThreadLocalSingleton<DERIVED_TYPE>::UNINITIALIZED; -#elif LL_LINUX -template<typename DERIVED_TYPE> -__thread DERIVED_TYPE* LLThreadLocalSingleton<DERIVED_TYPE>::sInstance = NULL; - -template<typename DERIVED_TYPE> -__thread typename LLThreadLocalSingleton<DERIVED_TYPE>::EInitState LLThreadLocalSingleton<DERIVED_TYPE>::sInitState = LLThreadLocalSingleton<DERIVED_TYPE>::UNINITIALIZED; -#elif LL_DARWIN -template<typename DERIVED_TYPE> -pthread_key_t LLThreadLocalSingleton<DERIVED_TYPE>::sInstanceKey; - -template<typename DERIVED_TYPE> -pthread_key_t LLThreadLocalSingleton<DERIVED_TYPE>::sInitStateKey; - -#endif - -template<typename DERIVED_TYPE>  class LLThreadLocalSingletonPointer  {  public: diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp index 59a4b42c97..3dffbe6d4a 100644 --- a/indra/llcommon/lltrace.cpp +++ b/indra/llcommon/lltrace.cpp @@ -30,58 +30,26 @@  #include "lltracethreadrecorder.h"  #include "llfasttimer.h" -static S32 sInitializationCount = 0; -  namespace LLTrace  { -static MasterThreadRecorder* gUIThreadRecorder = NULL; - -void init() -{ -	if (sInitializationCount++ == 0) -	{ -		gUIThreadRecorder = new MasterThreadRecorder(); -	} -} - -bool isInitialized() -{ -	return sInitializationCount > 0;  -} - -void cleanup() +TraceBase::TraceBase( const char* name, const char* description )  +:	mName(name), +	mDescription(description ? description : "")  { -	if (--sInitializationCount == 0) +#ifndef LL_RELEASE_FOR_DOWNLOAD +	if (LLTrace::get_master_thread_recorder() != NULL)  	{ -		delete gUIThreadRecorder; -		gUIThreadRecorder = NULL; +		llerrs << "Attempting to declare trace object after program initialization.  Trace objects should be statically initialized." << llendl;  	} +#endif  } -MasterThreadRecorder& getUIThreadRecorder() +const char* TraceBase::getUnitLabel()  { -	llassert(gUIThreadRecorder != NULL); -	return *gUIThreadRecorder; +	return "";  } -LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder_ptr() -{ -	static LLThreadLocalPointer<ThreadRecorder> s_thread_recorder; -	return s_thread_recorder; -} - -const LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder() -{ -	return get_thread_recorder_ptr(); -} - -void set_thread_recorder(ThreadRecorder* recorder) -{ -	get_thread_recorder_ptr() = recorder; -} - -  TimeBlockTreeNode::TimeBlockTreeNode()   :	mBlock(NULL),  	mParent(NULL), diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h index 884a316a3b..2c45923aac 100644 --- a/indra/llcommon/lltrace.h +++ b/indra/llcommon/lltrace.h @@ -32,7 +32,7 @@  #include "llmemory.h"  #include "llrefcount.h" -#include "llunit.h" +#include "lltraceaccumulators.h"  #include "llthreadlocalstorage.h"  #include "lltimer.h" @@ -53,198 +53,29 @@ STORAGE_TYPE storage_value(LLUnit<STORAGE_TYPE, UNIT_TYPE> val) { return val.val  template<typename UNIT_TYPE, typename STORAGE_TYPE>   STORAGE_TYPE storage_value(LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> val) { return val.value(); } -void init(); -void cleanup(); -bool isInitialized(); - -const LLThreadLocalPointer<class ThreadRecorder>& get_thread_recorder(); -void set_thread_recorder(class ThreadRecorder*); - -class MasterThreadRecorder& getUIThreadRecorder(); - -template<typename ACCUMULATOR> -class AccumulatorBuffer : public LLRefCount +class TraceBase  { -	typedef AccumulatorBuffer<ACCUMULATOR> self_t; -	static const U32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 64; -private: -	struct StaticAllocationMarker { }; - -	AccumulatorBuffer(StaticAllocationMarker m) -	:	mStorageSize(0), -		mStorage(NULL) -	{} -  public: +	TraceBase(const char* name, const char* description); +	virtual ~TraceBase() {}; +	virtual const char* getUnitLabel(); -	AccumulatorBuffer(const AccumulatorBuffer& other = *getDefaultBuffer()) -	:	mStorageSize(0), -		mStorage(NULL) -	{ -		resize(other.mStorageSize); -		for (S32 i = 0; i < sNextStorageSlot; i++) -		{ -			mStorage[i] = other.mStorage[i]; -		} -	} - -	~AccumulatorBuffer() -	{ -		if (isPrimary()) -		{ -			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];  -	} - -	void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other, bool append = true) -	{ -		llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize > sNextStorageSlot); -		for (size_t i = 0; i < sNextStorageSlot; i++) -		{ -			mStorage[i].addSamples(other.mStorage[i], append); -		} -	} - -	void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other) -	{ -		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) -	{ -		llassert(mStorageSize >= sNextStorageSlot); -		for (size_t i = 0; i < sNextStorageSlot; i++) -		{ -			mStorage[i].reset(other ? &other->mStorage[i] : NULL); -		} -	} - -	void flush(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp) -	{ -		llassert(mStorageSize >= sNextStorageSlot); -		for (size_t i = 0; i < sNextStorageSlot; i++) -		{ -			mStorage[i].flush(time_stamp); -		} -	} - -	void makePrimary() -	{ -		LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(mStorage); -	} - -	bool isPrimary() const -	{ -		return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage; -	} - -	LL_FORCE_INLINE static ACCUMULATOR* getPrimaryStorage()  -	{  -		ACCUMULATOR* accumulator = LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance(); -		return accumulator ? accumulator : getDefaultBuffer()->mStorage; -	} - -	// 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() -	{ -#ifndef LL_RELEASE_FOR_DOWNLOAD -		if (LLTrace::isInitialized()) -		{ -			llerrs << "Attempting to declare trace object after program initialization.  Trace objects should be statically initialized." << llendl; -		} -#endif -		size_t next_slot = sNextStorageSlot++; -		if (next_slot >= mStorageSize) -		{ -			resize(mStorageSize + (mStorageSize >> 2)); -		} -		llassert(mStorage && next_slot < mStorageSize); -		return next_slot; -	} - -	void resize(size_t new_size) -	{ -		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(); -	} - -	static size_t getNumIndices()  -	{ -		return sNextStorageSlot; -	} - -	static self_t* getDefaultBuffer() -	{ -		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; -	} +	const std::string& getName() const { return mName; } -private: -	ACCUMULATOR*	mStorage; -	size_t			mStorageSize; -	static size_t	sNextStorageSlot; -	static self_t*	sDefaultBuffer; +protected: +	const std::string	mName; +	const std::string	mDescription;  }; -template<typename ACCUMULATOR> size_t AccumulatorBuffer<ACCUMULATOR>::sNextStorageSlot = 0; -template<typename ACCUMULATOR> AccumulatorBuffer<ACCUMULATOR>* AccumulatorBuffer<ACCUMULATOR>::sDefaultBuffer = NULL; -  template<typename ACCUMULATOR>  class TraceType  -:	 public LLInstanceTracker<TraceType<ACCUMULATOR>, std::string> +:	public TraceBase, +	public LLInstanceTracker<TraceType<ACCUMULATOR>, std::string>  {  public:  	TraceType(const char* name, const char* description = NULL)  	:	LLInstanceTracker<TraceType<ACCUMULATOR>, std::string>(name), -		mName(name), -		mDescription(description ? description : ""), +		TraceBase(name, description),  		mAccumulatorIndex(AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer()->reserveSlot())  	{} @@ -257,354 +88,10 @@ public:  	size_t getIndex() const { return mAccumulatorIndex; }  	static size_t getNumIndices() { return AccumulatorBuffer<ACCUMULATOR>::getNumIndices(); } -	virtual const char* getUnitLabel() { return ""; } - -	const std::string& getName() const { return mName; } - -protected: -	const std::string	mName; -	const std::string	mDescription; -	const size_t		mAccumulatorIndex; -}; - -class EventAccumulator -{ -public: -	typedef F64 value_t; -	typedef F64 mean_t; - -	EventAccumulator() -	:	mSum(0), -		mMin((std::numeric_limits<F64>::max)()), -		mMax((std::numeric_limits<F64>::min)()), -		mMean(0), -		mVarianceSum(0), -		mNumSamples(0), -		mLastValue(0) -	{} - -	void record(F64 value) -	{ -		mNumSamples++; -		mSum += value; -		// NOTE: both conditions will hold on first pass through -		if (value < mMin) -		{ -			mMin = value; -		} -		if (value > mMax) -		{ -			mMax = value; -		} -		F64 old_mean = mMean; -		mMean += (value - old_mean) / (F64)mNumSamples; -		mVarianceSum += (value - old_mean) * (value - mMean); -		mLastValue = value; -	} - -	void addSamples(const EventAccumulator& other, bool append) -	{ -		if (other.mNumSamples) -		{ -			mSum += other.mSum; - -			// NOTE: both conditions will hold first time through -			if (other.mMin < mMin) { mMin = other.mMin; } -			if (other.mMax > mMax) { mMax = other.mMax; } - -			// combine variance (and hence standard deviation) of 2 different sized sample groups using -			// the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm -			F64 n_1 = (F64)mNumSamples, -				n_2 = (F64)other.mNumSamples; -			F64 m_1 = mMean, -				m_2 = other.mMean; -			F64 v_1 = mVarianceSum / mNumSamples, -				v_2 = other.mVarianceSum / other.mNumSamples; -			if (n_1 == 0) -			{ -				mVarianceSum = other.mVarianceSum; -			} -			else if (n_2 == 0) -			{ -				// don't touch variance -				// mVarianceSum = mVarianceSum; -			} -			else -			{ -				mVarianceSum = (F64)mNumSamples -								* ((((n_1 - 1.f) * v_1) -									+ ((n_2 - 1.f) * v_2) -									+ (((n_1 * n_2) / (n_1 + n_2)) -										* ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) -									/ (n_1 + n_2 - 1.f)); -			} - -			F64 weight = (F64)mNumSamples / (F64)(mNumSamples + other.mNumSamples); -			mNumSamples += other.mNumSamples; -			mMean = mMean * weight + other.mMean * (1.f - weight); -			if (append) mLastValue = other.mLastValue; -		} -	} - -	void reset(const EventAccumulator* other) -	{ -		mNumSamples = 0; -		mSum = 0; -		mMin = std::numeric_limits<F64>::max(); -		mMax = std::numeric_limits<F64>::min(); -		mMean = 0; -		mVarianceSum = 0; -		mLastValue = other ? other->mLastValue : 0; -	} - -	void flush(LLUnitImplicit<F64, LLUnits::Seconds>) {} - -	F64	getSum() const { return mSum; } -	F64	getMin() const { return mMin; } -	F64	getMax() const { return mMax; } -	F64	getLastValue() const { return mLastValue; } -	F64	getMean() const { return mMean; } -	F64 getStandardDeviation() const { return sqrtf(mVarianceSum / mNumSamples); } -	U32 getSampleCount() const { return mNumSamples; } - -private: -	F64	mSum, -		mMin, -		mMax, -		mLastValue; - -	F64	mMean, -		mVarianceSum; - -	U32	mNumSamples; -}; - - -class SampleAccumulator -{ -public: -	typedef F64 value_t; -	typedef F64 mean_t; - -	SampleAccumulator() -	:	mSum(0), -		mMin((std::numeric_limits<F64>::max)()), -		mMax((std::numeric_limits<F64>::min)()), -		mMean(0), -		mVarianceSum(0), -		mLastSampleTimeStamp(LLTimer::getTotalSeconds()), -		mTotalSamplingTime(0), -		mNumSamples(0), -		mLastValue(0), -		mHasValue(false) -	{} - -	void sample(F64 value) -	{ -		LLUnitImplicit<F64, LLUnits::Seconds> time_stamp = LLTimer::getTotalSeconds(); -		LLUnitImplicit<F64, LLUnits::Seconds> delta_time = time_stamp - mLastSampleTimeStamp; -		mLastSampleTimeStamp = time_stamp; - -		if (mHasValue) -		{ -			mTotalSamplingTime += delta_time; -			mSum += mLastValue * delta_time; - -			// NOTE: both conditions will hold first time through -			if (value < mMin) { mMin = value; } -			if (value > mMax) { mMax = value; } - -			F64 old_mean = mMean; -			mMean += (delta_time / mTotalSamplingTime) * (mLastValue - old_mean); -			mVarianceSum += delta_time * (mLastValue - old_mean) * (mLastValue - mMean); -		} - -		mLastValue = value; -		mNumSamples++; -		mHasValue = true; -	} - -	void addSamples(const SampleAccumulator& other, bool append) -	{ -		if (other.mTotalSamplingTime) -		{ -			mSum += other.mSum; - -			// NOTE: both conditions will hold first time through -			if (other.mMin < mMin) { mMin = other.mMin; } -			if (other.mMax > mMax) { mMax = other.mMax; } - -			// combine variance (and hence standard deviation) of 2 different sized sample groups using -			// the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm -			F64 n_1 = mTotalSamplingTime, -				n_2 = other.mTotalSamplingTime; -			F64 m_1 = mMean, -				m_2 = other.mMean; -			F64 v_1 = mVarianceSum / mTotalSamplingTime, -				v_2 = other.mVarianceSum / other.mTotalSamplingTime; -			if (n_1 == 0) -			{ -				mVarianceSum = other.mVarianceSum; -			} -			else if (n_2 == 0) -			{ -				// variance is unchanged -				// mVarianceSum = mVarianceSum; -			} -			else -			{ -				mVarianceSum =	mTotalSamplingTime -								* ((((n_1 - 1.f) * v_1) -									+ ((n_2 - 1.f) * v_2) -									+ (((n_1 * n_2) / (n_1 + n_2)) -										* ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) -									/ (n_1 + n_2 - 1.f)); -			} - -			llassert(other.mTotalSamplingTime > 0); -			F64 weight = mTotalSamplingTime / (mTotalSamplingTime + other.mTotalSamplingTime); -			mNumSamples += other.mNumSamples; -			mTotalSamplingTime += other.mTotalSamplingTime; -			mMean = (mMean * weight) + (other.mMean * (1.0 - weight)); -			if (append) -			{ -				mLastValue = other.mLastValue; -				mLastSampleTimeStamp = other.mLastSampleTimeStamp; -				mHasValue |= other.mHasValue; -			} -		} -	} - -	void reset(const SampleAccumulator* other) -	{ -		mNumSamples = 0; -		mSum = 0; -		mMin = std::numeric_limits<F64>::max(); -		mMax = std::numeric_limits<F64>::min(); -		mMean = other ? other->mLastValue : 0; -		mVarianceSum = 0; -		mLastSampleTimeStamp = LLTimer::getTotalSeconds(); -		mTotalSamplingTime = 0; -		mLastValue = other ? other->mLastValue : 0; -		mHasValue = other ? other->mHasValue : false; -	} - -	void flush(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp) -	{ -		LLUnitImplicit<F64, LLUnits::Seconds> delta_time = time_stamp - mLastSampleTimeStamp; - -		if (mHasValue) -		{ -			mSum += mLastValue * delta_time; -			mTotalSamplingTime += delta_time; -		} -		mLastSampleTimeStamp = time_stamp; -	} - -	F64	getSum() const { return mSum; } -	F64	getMin() const { return mMin; } -	F64	getMax() const { return mMax; } -	F64	getLastValue() const { return mLastValue; } -	F64	getMean() const { return mMean; } -	F64 getStandardDeviation() const { return sqrtf(mVarianceSum / mTotalSamplingTime); } -	U32 getSampleCount() const { return mNumSamples; } - -private: -	F64	mSum, -		mMin, -		mMax, -		mLastValue; - -	bool mHasValue; - -	F64	mMean, -		mVarianceSum; - -	LLUnitImplicit<F64, LLUnits::Seconds>	mLastSampleTimeStamp, -											mTotalSamplingTime; - -	U32	mNumSamples; -}; - -class CountAccumulator -{ -public: -	typedef F64 value_t; -	typedef F64 mean_t; - -	CountAccumulator() -	:	mSum(0), -		mNumSamples(0) -	{} - -	void add(F64 value) -	{ -		mNumSamples++; -		mSum += value; -	} - -	void addSamples(const CountAccumulator& other, bool /*append*/) -	{ -		mSum += other.mSum; -		mNumSamples += other.mNumSamples; -	} - -	void reset(const CountAccumulator* other) -	{ -		mNumSamples = 0; -		mSum = 0; -	} - -	void flush(LLUnitImplicit<F64, LLUnits::Seconds>) {} - -	F64	getSum() const { return mSum; } - -	U32 getSampleCount() const { return mNumSamples; } -  private: -	F64	mSum; - -	U32	mNumSamples; +	const size_t		mAccumulatorIndex;  }; -class TimeBlockAccumulator -{ -public: -	typedef LLUnit<F64, LLUnits::Seconds> value_t; -	typedef LLUnit<F64, LLUnits::Seconds> mean_t; -	typedef TimeBlockAccumulator self_t; - -	// fake classes that allows us to view different facets of underlying statistic -	struct CallCountFacet  -	{ -		typedef U32 value_t; -		typedef F32 mean_t; -	}; - -	struct SelfTimeFacet -	{ -		typedef LLUnit<F64, LLUnits::Seconds> value_t; -		typedef LLUnit<F64, LLUnits::Seconds> mean_t; -	}; - -	TimeBlockAccumulator(); -	void addSamples(const self_t& other, bool /*append*/); -	void reset(const self_t* other); -	void flush(LLUnitImplicit<F64, LLUnits::Seconds>) {} - -	// -	// members -	// -	U64							mStartTotalTimeCounter, -								mTotalTimeCounter, -								mSelfTimeCounter; -	U32							mCalls; -	class TimeBlock*			mParent;		// last acknowledged parent of this time block -	class TimeBlock*			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 - -};  template<>  class TraceType<TimeBlockAccumulator::CallCountFacet> @@ -628,23 +115,6 @@ public:  	{}  }; -class TimeBlock; -class TimeBlockTreeNode -{ -public: -	TimeBlockTreeNode(); - -	void setParent(TimeBlock* parent); -	TimeBlock* getParent() { return mParent; } - -	TimeBlock*					mBlock; -	TimeBlock*					mParent;	 -	std::vector<TimeBlock*>		mChildren; -	bool						mCollapsed; -	bool						mNeedsSorting; -}; - -  template <typename T = F64>  class EventStatHandle  :	public TraceType<EventAccumulator> @@ -712,64 +182,6 @@ void add(CountStatHandle<T>& count, VALUE_T value)  	count.getPrimaryAccumulator()->add(storage_value(converted_value));  } - -struct MemStatAccumulator -{ -	typedef MemStatAccumulator self_t; - -	// fake classes that allows us to view different facets of underlying statistic -	struct AllocationCountFacet  -	{ -		typedef U32 value_t; -		typedef F32 mean_t; -	}; - -	struct DeallocationCountFacet  -	{ -		typedef U32 value_t; -		typedef F32 mean_t; -	}; - -	struct ChildMemFacet -	{ -		typedef LLUnit<F64, LLUnits::Bytes> value_t; -		typedef LLUnit<F64, LLUnits::Bytes> mean_t; -	}; - -	MemStatAccumulator() -	:	mAllocatedCount(0), -		mDeallocatedCount(0) -	{} - -	void addSamples(const MemStatAccumulator& other, bool append) -	{ -		mSize.addSamples(other.mSize, append); -		mChildSize.addSamples(other.mChildSize, append); -		mAllocatedCount += other.mAllocatedCount; -		mDeallocatedCount += other.mDeallocatedCount; -	} - -	void reset(const MemStatAccumulator* other) -	{ -		mSize.reset(other ? &other->mSize : NULL); -		mChildSize.reset(other ? &other->mChildSize : NULL); -		mAllocatedCount = 0; -		mDeallocatedCount = 0; -	} - -	void flush(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp)  -	{ -		mSize.flush(time_stamp); -		mChildSize.flush(time_stamp); -	} - -	SampleAccumulator	mSize, -						mChildSize; -	int					mAllocatedCount, -						mDeallocatedCount; -}; - -  template<>  class TraceType<MemStatAccumulator::AllocationCountFacet>  :	public TraceType<MemStatAccumulator> @@ -912,7 +324,7 @@ class MemTrackable  	template<typename TRACKED, typename TRACKED_IS_TRACKER>  	struct TrackMemImpl; -	typedef MemTrackable<DERIVED> mem_trackable_t; +	typedef MemTrackable<DERIVED, ALIGNMENT> mem_trackable_t;  public:  	typedef void mem_trackable_tag_t; @@ -986,14 +398,16 @@ public:  	} -	void memClaimAmount(size_t size) +	template<typename AMOUNT_T> +	AMOUNT_T& memClaimAmount(AMOUNT_T& size)  	{  		MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator(); -		mMemFootprint += size; +		mMemFootprint += (size_t)size;  		if (accumulator)  		{  			accumulator->mSize.sample(accumulator->mSize.getLastValue() + (F64)size);  		} +		return size;  	}  	// remove memory we had claimed from our calculated footprint @@ -1011,13 +425,15 @@ public:  		return value;  	} -	void memDisclaimAmount(size_t size) +	template<typename AMOUNT_T> +	AMOUNT_T& memDisclaimAmount(AMOUNT_T& size)  	{  		MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();  		if (accumulator)  		{  			accumulator->mSize.sample(accumulator->mSize.getLastValue() - (F64)size);  		} +		return size;  	}  private: diff --git a/indra/llcommon/lltraceaccumulators.cpp b/indra/llcommon/lltraceaccumulators.cpp new file mode 100644 index 0000000000..950c1d97d1 --- /dev/null +++ b/indra/llcommon/lltraceaccumulators.cpp @@ -0,0 +1,123 @@ +/**  + * @file lltracesampler.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 "lltraceaccumulators.h" +#include "lltracethreadrecorder.h" + +namespace LLTrace +{ + + +/////////////////////////////////////////////////////////////////////// +// AccumulatorBufferGroup +/////////////////////////////////////////////////////////////////////// + +AccumulatorBufferGroup::AccumulatorBufferGroup()  +{} + +void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other) +{ +	other.mCounts.reset(&mCounts); +	other.mSamples.reset(&mSamples); +	other.mEvents.reset(&mEvents); +	other.mStackTimers.reset(&mStackTimers); +	other.mMemStats.reset(&mMemStats); +} + +void AccumulatorBufferGroup::makePrimary() +{ +	mCounts.makePrimary(); +	mSamples.makePrimary(); +	mEvents.makePrimary(); +	mStackTimers.makePrimary(); +	mMemStats.makePrimary(); + +	ThreadRecorder* thread_recorder = get_thread_recorder().get(); +	AccumulatorBuffer<TimeBlockAccumulator>& timer_accumulator_buffer = mStackTimers; +	// update stacktimer parent pointers +	for (S32 i = 0, end_i = mStackTimers.size(); i < end_i; i++) +	{ +		TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(i); +		if (tree_node) +		{ +			timer_accumulator_buffer[i].mParent = tree_node->mParent; +		} +	} +} + +//static +void AccumulatorBufferGroup::clearPrimary() +{ +	AccumulatorBuffer<CountAccumulator>::clearPrimary();	 +	AccumulatorBuffer<SampleAccumulator>::clearPrimary(); +	AccumulatorBuffer<EventAccumulator>::clearPrimary(); +	AccumulatorBuffer<TimeBlockAccumulator>::clearPrimary(); +	AccumulatorBuffer<MemStatAccumulator>::clearPrimary(); +} + +bool AccumulatorBufferGroup::isPrimary() const +{ +	return mCounts.isPrimary(); +} + +void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other ) +{ +	mCounts.addSamples(other.mCounts); +	mSamples.addSamples(other.mSamples); +	mEvents.addSamples(other.mEvents); +	mMemStats.addSamples(other.mMemStats); +	mStackTimers.addSamples(other.mStackTimers); +} + +void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other) +{ +	mCounts.addSamples(other.mCounts, false); +	mSamples.addSamples(other.mSamples, false); +	mEvents.addSamples(other.mEvents, false); +	mMemStats.addSamples(other.mMemStats, false); +	// for now, hold out timers from merge, need to be displayed per thread +	//mStackTimers.addSamples(other.mStackTimers, false); +} + +void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other) +{ +	mCounts.reset(other ? &other->mCounts : NULL); +	mSamples.reset(other ? &other->mSamples : NULL); +	mEvents.reset(other ? &other->mEvents : NULL); +	mStackTimers.reset(other ? &other->mStackTimers : NULL); +	mMemStats.reset(other ? &other->mMemStats : NULL); +} + +void AccumulatorBufferGroup::sync() +{ +	LLUnitImplicit<F64, LLUnits::Seconds> time_stamp = LLTimer::getTotalSeconds(); + +	mSamples.sync(time_stamp); +	mMemStats.sync(time_stamp); +} + +} diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h new file mode 100644 index 0000000000..fac6347ff9 --- /dev/null +++ b/indra/llcommon/lltraceaccumulators.h @@ -0,0 +1,656 @@ +/**  + * @file lltraceaccumulators.h + * @brief Storage for accumulating statistics + * + * $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_LLTRACEACCUMULATORS_H +#define LL_LLTRACEACCUMULATORS_H + + +#include "stdtypes.h" +#include "llpreprocessor.h" +#include "llunit.h" +#include "lltimer.h" +#include "llrefcount.h" +#include "llthreadlocalstorage.h" + +namespace LLTrace +{ + +	template<typename ACCUMULATOR> +	class AccumulatorBuffer : public LLRefCount +	{ +		typedef AccumulatorBuffer<ACCUMULATOR> self_t; +		static const U32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 64; +	private: +		struct StaticAllocationMarker { }; + +		AccumulatorBuffer(StaticAllocationMarker m) +		:	mStorageSize(0), +			mStorage(NULL) +		{} + +	public: + +		AccumulatorBuffer(const AccumulatorBuffer& other = *getDefaultBuffer()) +		:	mStorageSize(0), +			mStorage(NULL) +		{ +			resize(other.mStorageSize); +			for (S32 i = 0; i < sNextStorageSlot; i++) +			{ +				mStorage[i] = other.mStorage[i]; +			} +		} + +		~AccumulatorBuffer() +		{ +			if (isPrimary()) +			{ +				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];  +		} + +		void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other, bool append = true) +		{ +			llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize > sNextStorageSlot); +			for (size_t i = 0; i < sNextStorageSlot; i++) +			{ +				mStorage[i].addSamples(other.mStorage[i], append); +			} +		} + +		void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other) +		{ +			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) +		{ +			llassert(mStorageSize >= sNextStorageSlot); +			for (size_t i = 0; i < sNextStorageSlot; i++) +			{ +				mStorage[i].reset(other ? &other->mStorage[i] : NULL); +			} +		} + +		void sync(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp) +		{ +			llassert(mStorageSize >= sNextStorageSlot); +			for (size_t i = 0; i < sNextStorageSlot; i++) +			{ +				mStorage[i].sync(time_stamp); +			} +		} + +		void makePrimary() +		{ +			LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(mStorage); +		} + +		bool isPrimary() const +		{ +			return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage; +		} + +		static void clearPrimary() +		{ +			LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL); +		} + +		LL_FORCE_INLINE static ACCUMULATOR* getPrimaryStorage()  +		{  +			ACCUMULATOR* accumulator = LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance(); +			return accumulator ? accumulator : getDefaultBuffer()->mStorage; +		} + +		// 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() +		{ +			size_t next_slot = sNextStorageSlot++; +			if (next_slot >= mStorageSize) +			{ +				resize(mStorageSize + (mStorageSize >> 2)); +			} +			llassert(mStorage && next_slot < mStorageSize); +			return next_slot; +		} + +		void resize(size_t new_size) +		{ +			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(); +		} + +		static size_t getNumIndices()  +		{ +			return sNextStorageSlot; +		} + +		static self_t* getDefaultBuffer() +		{ +			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; +		typedef F64 mean_t; + +		EventAccumulator() +		:	mSum(0), +			mMin((std::numeric_limits<F64>::max)()), +			mMax((std::numeric_limits<F64>::min)()), +			mMean(0), +			mVarianceSum(0), +			mNumSamples(0), +			mLastValue(0) +		{} + +		void record(F64 value) +		{ +			mNumSamples++; +			mSum += value; +			// NOTE: both conditions will hold on first pass through +			if (value < mMin) +			{ +				mMin = value; +			} +			if (value > mMax) +			{ +				mMax = value; +			} +			F64 old_mean = mMean; +			mMean += (value - old_mean) / (F64)mNumSamples; +			mVarianceSum += (value - old_mean) * (value - mMean); +			mLastValue = value; +		} + +		void addSamples(const EventAccumulator& other, bool append) +		{ +			if (other.mNumSamples) +			{ +				mSum += other.mSum; + +				// NOTE: both conditions will hold first time through +				if (other.mMin < mMin) { mMin = other.mMin; } +				if (other.mMax > mMax) { mMax = other.mMax; } + +				// combine variance (and hence standard deviation) of 2 different sized sample groups using +				// the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm +				F64 n_1 = (F64)mNumSamples, +					n_2 = (F64)other.mNumSamples; +				F64 m_1 = mMean, +					m_2 = other.mMean; +				F64 v_1 = mVarianceSum / mNumSamples, +					v_2 = other.mVarianceSum / other.mNumSamples; +				if (n_1 == 0) +				{ +					mVarianceSum = other.mVarianceSum; +				} +				else if (n_2 == 0) +				{ +					// don't touch variance +					// mVarianceSum = mVarianceSum; +				} +				else +				{ +					mVarianceSum = (F64)mNumSamples +						* ((((n_1 - 1.f) * v_1) +						+ ((n_2 - 1.f) * v_2) +						+ (((n_1 * n_2) / (n_1 + n_2)) +						* ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) +						/ (n_1 + n_2 - 1.f)); +				} + +				F64 weight = (F64)mNumSamples / (F64)(mNumSamples + other.mNumSamples); +				mNumSamples += other.mNumSamples; +				mMean = mMean * weight + other.mMean * (1.f - weight); +				if (append) mLastValue = other.mLastValue; +			} +		} + +		void reset(const EventAccumulator* other) +		{ +			mNumSamples = 0; +			mSum = 0; +			mMin = std::numeric_limits<F64>::max(); +			mMax = std::numeric_limits<F64>::min(); +			mMean = 0; +			mVarianceSum = 0; +			mLastValue = other ? other->mLastValue : 0; +		} + +		void sync(LLUnitImplicit<F64, LLUnits::Seconds>) {} + +		F64	getSum() const { return mSum; } +		F64	getMin() const { return mMin; } +		F64	getMax() const { return mMax; } +		F64	getLastValue() const { return mLastValue; } +		F64	getMean() const { return mMean; } +		F64 getStandardDeviation() const { return sqrtf(mVarianceSum / mNumSamples); } +		U32 getSampleCount() const { return mNumSamples; } + +	private: +		F64	mSum, +			mMin, +			mMax, +			mLastValue; + +		F64	mMean, +			mVarianceSum; + +		U32	mNumSamples; +	}; + + +	class SampleAccumulator +	{ +	public: +		typedef F64 value_t; +		typedef F64 mean_t; + +		SampleAccumulator() +		:	mSum(0), +			mMin((std::numeric_limits<F64>::max)()), +			mMax((std::numeric_limits<F64>::min)()), +			mMean(0), +			mVarianceSum(0), +			mLastSampleTimeStamp(LLTimer::getTotalSeconds()), +			mTotalSamplingTime(0), +			mNumSamples(0), +			mLastValue(0), +			mHasValue(false) +		{} + +		void sample(F64 value) +		{ +			LLUnitImplicit<F64, LLUnits::Seconds> time_stamp = LLTimer::getTotalSeconds(); +			LLUnitImplicit<F64, LLUnits::Seconds> delta_time = time_stamp - mLastSampleTimeStamp; +			mLastSampleTimeStamp = time_stamp; + +			if (mHasValue) +			{ +				mTotalSamplingTime += delta_time; +				mSum += mLastValue * delta_time; + +				// NOTE: both conditions will hold first time through +				if (value < mMin) { mMin = value; } +				if (value > mMax) { mMax = value; } + +				F64 old_mean = mMean; +				mMean += (delta_time / mTotalSamplingTime) * (mLastValue - old_mean); +				mVarianceSum += delta_time * (mLastValue - old_mean) * (mLastValue - mMean); +			} + +			mLastValue = value; +			mNumSamples++; +			mHasValue = true; +		} + +		void addSamples(const SampleAccumulator& other, bool append) +		{ +			if (other.mTotalSamplingTime) +			{ +				mSum += other.mSum; + +				// NOTE: both conditions will hold first time through +				if (other.mMin < mMin) { mMin = other.mMin; } +				if (other.mMax > mMax) { mMax = other.mMax; } + +				// combine variance (and hence standard deviation) of 2 different sized sample groups using +				// the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm +				F64 n_1 = mTotalSamplingTime, +					n_2 = other.mTotalSamplingTime; +				F64 m_1 = mMean, +					m_2 = other.mMean; +				F64 v_1 = mVarianceSum / mTotalSamplingTime, +					v_2 = other.mVarianceSum / other.mTotalSamplingTime; +				if (n_1 == 0) +				{ +					mVarianceSum = other.mVarianceSum; +				} +				else if (n_2 == 0) +				{ +					// variance is unchanged +					// mVarianceSum = mVarianceSum; +				} +				else +				{ +					mVarianceSum =	mTotalSamplingTime +						* ((((n_1 - 1.f) * v_1) +						+ ((n_2 - 1.f) * v_2) +						+ (((n_1 * n_2) / (n_1 + n_2)) +						* ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) +						/ (n_1 + n_2 - 1.f)); +				} + +				llassert(other.mTotalSamplingTime > 0); +				F64 weight = mTotalSamplingTime / (mTotalSamplingTime + other.mTotalSamplingTime); +				mNumSamples += other.mNumSamples; +				mTotalSamplingTime += other.mTotalSamplingTime; +				mMean = (mMean * weight) + (other.mMean * (1.0 - weight)); +				if (append) +				{ +					mLastValue = other.mLastValue; +					mLastSampleTimeStamp = other.mLastSampleTimeStamp; +					mHasValue |= other.mHasValue; +				} +			} +		} + +		void reset(const SampleAccumulator* other) +		{ +			mNumSamples = 0; +			mSum = 0; +			mMin = std::numeric_limits<F64>::max(); +			mMax = std::numeric_limits<F64>::min(); +			mMean = other ? other->mLastValue : 0; +			mVarianceSum = 0; +			mLastSampleTimeStamp = LLTimer::getTotalSeconds(); +			mTotalSamplingTime = 0; +			mLastValue = other ? other->mLastValue : 0; +			mHasValue = other ? other->mHasValue : false; +		} + +		void sync(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp) +		{ +			LLUnitImplicit<F64, LLUnits::Seconds> delta_time = time_stamp - mLastSampleTimeStamp; + +			if (mHasValue) +			{ +				mSum += mLastValue * delta_time; +				mTotalSamplingTime += delta_time; +			} +			mLastSampleTimeStamp = time_stamp; +		} + +		F64	getSum() const { return mSum; } +		F64	getMin() const { return mMin; } +		F64	getMax() const { return mMax; } +		F64	getLastValue() const { return mLastValue; } +		F64	getMean() const { return mMean; } +		F64 getStandardDeviation() const { return sqrtf(mVarianceSum / mTotalSamplingTime); } +		U32 getSampleCount() const { return mNumSamples; } + +	private: +		F64	mSum, +			mMin, +			mMax, +			mLastValue; + +		bool mHasValue; + +		F64	mMean, +			mVarianceSum; + +		LLUnitImplicit<F64, LLUnits::Seconds>	mLastSampleTimeStamp, +			mTotalSamplingTime; + +		U32	mNumSamples; +	}; + +	class CountAccumulator +	{ +	public: +		typedef F64 value_t; +		typedef F64 mean_t; + +		CountAccumulator() +		:	mSum(0), +			mNumSamples(0) +		{} + +		void add(F64 value) +		{ +			mNumSamples++; +			mSum += value; +		} + +		void addSamples(const CountAccumulator& other, bool /*append*/) +		{ +			mSum += other.mSum; +			mNumSamples += other.mNumSamples; +		} + +		void reset(const CountAccumulator* other) +		{ +			mNumSamples = 0; +			mSum = 0; +		} + +		void sync(LLUnitImplicit<F64, LLUnits::Seconds>) {} + +		F64	getSum() const { return mSum; } + +		U32 getSampleCount() const { return mNumSamples; } + +	private: +		F64	mSum; + +		U32	mNumSamples; +	}; + +	class TimeBlockAccumulator +	{ +	public: +		typedef LLUnit<F64, LLUnits::Seconds> value_t; +		typedef LLUnit<F64, LLUnits::Seconds> mean_t; +		typedef TimeBlockAccumulator self_t; + +		// fake classes that allows us to view different facets of underlying statistic +		struct CallCountFacet  +		{ +			typedef U32 value_t; +			typedef F32 mean_t; +		}; + +		struct SelfTimeFacet +		{ +			typedef LLUnit<F64, LLUnits::Seconds> value_t; +			typedef LLUnit<F64, LLUnits::Seconds> mean_t; +		}; + +		TimeBlockAccumulator(); +		void addSamples(const self_t& other, bool /*append*/); +		void reset(const self_t* other); +		void sync(LLUnitImplicit<F64, LLUnits::Seconds>) {} + +		// +		// members +		// +		U64							mStartTotalTimeCounter, +			mTotalTimeCounter, +			mSelfTimeCounter; +		U32							mCalls; +		class TimeBlock*			mParent;		// last acknowledged parent of this time block +		class TimeBlock*			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 TimeBlock; +	class TimeBlockTreeNode +	{ +	public: +		TimeBlockTreeNode(); + +		void setParent(TimeBlock* parent); +		TimeBlock* getParent() { return mParent; } + +		TimeBlock*					mBlock; +		TimeBlock*					mParent;	 +		std::vector<TimeBlock*>		mChildren; +		bool						mCollapsed; +		bool						mNeedsSorting; +	}; +	 +	struct BlockTimerStackRecord +	{ +		class BlockTimer*	mActiveTimer; +		class TimeBlock*	mTimeBlock; +		U64					mChildTime; +	}; + +	struct MemStatAccumulator +	{ +		typedef MemStatAccumulator self_t; + +		// fake classes that allows us to view different facets of underlying statistic +		struct AllocationCountFacet  +		{ +			typedef U32 value_t; +			typedef F32 mean_t; +		}; + +		struct DeallocationCountFacet  +		{ +			typedef U32 value_t; +			typedef F32 mean_t; +		}; + +		struct ChildMemFacet +		{ +			typedef LLUnit<F64, LLUnits::Bytes> value_t; +			typedef LLUnit<F64, LLUnits::Bytes> mean_t; +		}; + +		MemStatAccumulator() +		:	mAllocatedCount(0), +			mDeallocatedCount(0) +		{} + +		void addSamples(const MemStatAccumulator& other, bool append) +		{ +			mSize.addSamples(other.mSize, append); +			mChildSize.addSamples(other.mChildSize, append); +			mAllocatedCount += other.mAllocatedCount; +			mDeallocatedCount += other.mDeallocatedCount; +		} + +		void reset(const MemStatAccumulator* other) +		{ +			mSize.reset(other ? &other->mSize : NULL); +			mChildSize.reset(other ? &other->mChildSize : NULL); +			mAllocatedCount = 0; +			mDeallocatedCount = 0; +		} + +		void sync(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp)  +		{ +			mSize.sync(time_stamp); +			mChildSize.sync(time_stamp); +		} + +		SampleAccumulator	mSize, +							mChildSize; +		int					mAllocatedCount, +							mDeallocatedCount; +	}; + +	struct AccumulatorBufferGroup : public LLRefCount +	{ +		AccumulatorBufferGroup(); + +		void handOffTo(AccumulatorBufferGroup& other); +		void makePrimary(); +		bool isPrimary() const; +		static void clearPrimary(); + +		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; +		AccumulatorBuffer<MemStatAccumulator> 			mMemStats; +	}; +} + +#endif // LL_LLTRACEACCUMULATORS_H + diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp index d34434f161..f1388e7935 100644 --- a/indra/llcommon/lltracerecording.cpp +++ b/indra/llcommon/lltracerecording.cpp @@ -33,85 +33,7 @@  namespace LLTrace  { - - -/////////////////////////////////////////////////////////////////////// -// RecordingBuffers -/////////////////////////////////////////////////////////////////////// - -RecordingBuffers::RecordingBuffers()  -{} - -void RecordingBuffers::handOffTo(RecordingBuffers& other) -{ -	other.mCounts.reset(&mCounts); -	other.mSamples.reset(&mSamples); -	other.mEvents.reset(&mEvents); -	other.mStackTimers.reset(&mStackTimers); -	other.mMemStats.reset(&mMemStats); -} - -void RecordingBuffers::makePrimary() -{ -	mCounts.makePrimary(); -	mSamples.makePrimary(); -	mEvents.makePrimary(); -	mStackTimers.makePrimary(); -	mMemStats.makePrimary(); - -	ThreadRecorder* thread_recorder = get_thread_recorder().get(); -	AccumulatorBuffer<TimeBlockAccumulator>& timer_accumulator_buffer = mStackTimers; -	// update stacktimer parent pointers -	for (S32 i = 0, end_i = mStackTimers.size(); i < end_i; i++) -	{ -		TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(i); -		if (tree_node) -		{ -			timer_accumulator_buffer[i].mParent = tree_node->mParent; -		} -	} -} - -bool RecordingBuffers::isPrimary() const -{ -	return mCounts.isPrimary(); -} - -void RecordingBuffers::append( const RecordingBuffers& other ) -{ -	mCounts.addSamples(other.mCounts); -	mSamples.addSamples(other.mSamples); -	mEvents.addSamples(other.mEvents); -	mMemStats.addSamples(other.mMemStats); -	mStackTimers.addSamples(other.mStackTimers); -} - -void RecordingBuffers::merge( const RecordingBuffers& other) -{ -	mCounts.addSamples(other.mCounts, false); -	mSamples.addSamples(other.mSamples, false); -	mEvents.addSamples(other.mEvents, false); -	mMemStats.addSamples(other.mMemStats, false); -	// for now, hold out timers from merge, need to be displayed per thread -	//mStackTimers.addSamples(other.mStackTimers, false); -} - -void RecordingBuffers::reset(RecordingBuffers* other) -{ -	mCounts.reset(other ? &other->mCounts : NULL); -	mSamples.reset(other ? &other->mSamples : NULL); -	mEvents.reset(other ? &other->mEvents : NULL); -	mStackTimers.reset(other ? &other->mStackTimers : NULL); -	mMemStats.reset(other ? &other->mMemStats : NULL); -} - -void RecordingBuffers::flush() -{ -	LLUnitImplicit<F64, LLUnits::Seconds> time_stamp = LLTimer::getTotalSeconds(); - -	mSamples.flush(time_stamp); -} - +	  ///////////////////////////////////////////////////////////////////////  // Recording  /////////////////////////////////////////////////////////////////////// @@ -119,7 +41,7 @@ void RecordingBuffers::flush()  Recording::Recording()   :	mElapsedSeconds(0)  { -	mBuffers = new RecordingBuffers(); +	mBuffers = new AccumulatorBufferGroup();  }  Recording::Recording( const Recording& other ) @@ -132,17 +54,17 @@ Recording& Recording::operator = (const Recording& other)  	// this will allow us to seamlessly start without affecting any data we've acquired from other  	setPlayState(PAUSED); -	Recording& mutable_other = const_cast<Recording&>(other); -	mutable_other.update(); +	const_cast<Recording&>(other).update();  	EPlayState other_play_state = other.getPlayState(); -	mBuffers = mutable_other.mBuffers; - -	LLStopWatchControlsMixin<Recording>::setPlayState(other_play_state); +	mBuffers = other.mBuffers;  	// above call will clear mElapsedSeconds as a side effect, so copy it here  	mElapsedSeconds = other.mElapsedSeconds;  	mSamplingTimer = other.mSamplingTimer; + +	setPlayState(other_play_state); +  	return *this;  } @@ -151,7 +73,7 @@ Recording::~Recording()  {  	if (isStarted() && LLTrace::get_thread_recorder().notNull())  	{ -		LLTrace::get_thread_recorder()->deactivate(this); +		LLTrace::get_thread_recorder()->deactivate(mBuffers.write());  	}  } @@ -159,8 +81,10 @@ void Recording::update()  {  	if (isStarted())  	{ -		mBuffers.write()->flush(); -		LLTrace::get_thread_recorder()->bringUpToDate(this); +		mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); +		AccumulatorBufferGroup* buffers = mBuffers.write(); +		LLTrace::get_thread_recorder()->bringUpToDate(buffers); +  		mSamplingTimer.reset();  	}  } @@ -176,14 +100,15 @@ void Recording::handleReset()  void Recording::handleStart()  {  	mSamplingTimer.reset(); -	LLTrace::get_thread_recorder()->activate(this); +	mBuffers.setStayUnique(true); +	LLTrace::get_thread_recorder()->activate(mBuffers.write());  }  void Recording::handleStop()  {  	mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); -	mBuffers.write()->flush(); -	LLTrace::get_thread_recorder()->deactivate(this); +	LLTrace::get_thread_recorder()->deactivate(mBuffers.write()); +	mBuffers.setStayUnique(false);  }  void Recording::handleSplitTo(Recording& other) @@ -191,19 +116,14 @@ void Recording::handleSplitTo(Recording& other)  	mBuffers.write()->handOffTo(*other.mBuffers.write());  } -void Recording::appendRecording( const Recording& other ) +void Recording::appendRecording( Recording& other )  {  	update(); +	other.update();  	mBuffers.write()->append(*other.mBuffers);  	mElapsedSeconds += other.mElapsedSeconds;  } -void Recording::mergeRecording( const Recording& other) -{ -	update(); -	mBuffers.write()->merge(*other.mBuffers); -} -  LLUnit<F64, LLUnits::Seconds> Recording::getSum(const TraceType<TimeBlockAccumulator>& stat)  {  	const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; @@ -710,8 +630,6 @@ F64 PeriodicRecording::getPeriodMean( const TraceType<SampleAccumulator>& stat,  void ExtendableRecording::extend()  { -	// stop recording to get latest data -	mPotentialRecording.update();  	// push the data back to accepted recording  	mAcceptedRecording.appendRecording(mPotentialRecording);  	// flush data, so we can start from scratch diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h index b839e85de0..7b0970ffdf 100644 --- a/indra/llcommon/lltracerecording.h +++ b/indra/llcommon/lltracerecording.h @@ -32,7 +32,7 @@  #include "llpointer.h"  #include "lltimer.h" -#include "lltrace.h" +#include "lltraceaccumulators.h"  class LLStopWatchControlsMixinCommon  { @@ -81,6 +81,7 @@ class LLStopWatchControlsMixin  :	public LLStopWatchControlsMixinCommon  {  public: +  	typedef LLStopWatchControlsMixin<DERIVED> self_t;  	virtual void splitTo(DERIVED& other)  	{ @@ -98,6 +99,11 @@ public:  		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) {}; @@ -106,25 +112,17 @@ private:  namespace LLTrace  { -	struct RecordingBuffers : public LLRefCount -	{ -		RecordingBuffers(); - -		void handOffTo(RecordingBuffers& other); -		void makePrimary(); -		bool isPrimary() const; - -		void append(const RecordingBuffers& other); -		void merge(const RecordingBuffers& other); -		void reset(RecordingBuffers* other = NULL); -		void flush(); - -		AccumulatorBuffer<CountAccumulator>	 			mCounts; -		AccumulatorBuffer<SampleAccumulator>			mSamples; -		AccumulatorBuffer<EventAccumulator>				mEvents; -		AccumulatorBuffer<TimeBlockAccumulator> 		mStackTimers; -		AccumulatorBuffer<MemStatAccumulator> 			mMemStats; -	}; +	template<typename T> +	class TraceType; + +	template<typename T> +	class CountStatHandle; + +	template<typename T> +	class SampleStatHandle; + +	template<typename T> +	class EventStatHandle;  	class Recording   	:	public LLStopWatchControlsMixin<Recording> @@ -138,10 +136,7 @@ namespace LLTrace  		Recording& operator = (const Recording& other);  		// accumulate data from subsequent, non-overlapping recording -		void appendRecording(const Recording& other); - -		// gather data from recording, ignoring time relationship (for example, pulling data from slave threads) -		void mergeRecording(const Recording& other); +		void appendRecording(Recording& other);  		// grab latest recorded data  		void update(); @@ -291,7 +286,7 @@ namespace LLTrace  		LLTimer				mSamplingTimer;  		LLUnit<F64, LLUnits::Seconds>			mElapsedSeconds; -		LLCopyOnWritePointer<RecordingBuffers>	mBuffers; +		LLCopyOnWritePointer<AccumulatorBufferGroup>	mBuffers;  	};  	class LL_COMMON_API PeriodicRecording diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp index 54006f4e5b..7ac0e75154 100644 --- a/indra/llcommon/lltracethreadrecorder.cpp +++ b/indra/llcommon/lltracethreadrecorder.cpp @@ -31,25 +31,33 @@  namespace LLTrace  { +static ThreadRecorder* sMasterThreadRecorder = NULL;  ///////////////////////////////////////////////////////////////////////  // ThreadRecorder  ///////////////////////////////////////////////////////////////////////  ThreadRecorder::ThreadRecorder() +:	mMasterRecorder(NULL)  { +	init(); +} + +void ThreadRecorder::init() +{ +	LLThreadLocalSingletonPointer<BlockTimerStackRecord>::setInstance(&mBlockTimerStackRecord);  	//NB: the ordering of initialization in this function is very fragile due to a large number of implicit dependencies  	set_thread_recorder(this);  	TimeBlock& root_time_block = TimeBlock::getRootTimeBlock(); -	ThreadTimerStack* timer_stack = ThreadTimerStack::getInstance(); +	BlockTimerStackRecord* timer_stack = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance();  	timer_stack->mTimeBlock = &root_time_block;  	timer_stack->mActiveTimer = NULL;  	mNumTimeBlockTreeNodes = AccumulatorBuffer<TimeBlockAccumulator>::getDefaultBuffer()->size();  	mTimeBlockTreeNodes = new TimeBlockTreeNode[mNumTimeBlockTreeNodes]; -	mThreadRecording.start(); +	activate(&mThreadRecordingBuffers);  	// initialize time block parent pointers  	for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances();  @@ -70,8 +78,21 @@ ThreadRecorder::ThreadRecorder()  	TimeBlock::getRootTimeBlock().getPrimaryAccumulator()->mActiveCount = 1;  } + +ThreadRecorder::ThreadRecorder(ThreadRecorder& master) +:	mMasterRecorder(&master) +{ +	init(); +	mMasterRecorder->addChildRecorder(this); +} + +  ThreadRecorder::~ThreadRecorder()  { +	LLThreadLocalSingletonPointer<BlockTimerStackRecord>::setInstance(NULL); + +	deactivate(&mThreadRecordingBuffers); +  	delete mRootTimer;  	if (!mActiveRecordings.empty()) @@ -82,9 +103,14 @@ ThreadRecorder::~ThreadRecorder()  	set_thread_recorder(NULL);  	delete[] mTimeBlockTreeNodes; + +	if (mMasterRecorder) +	{ +		mMasterRecorder->removeChildRecorder(this); +	}  } -TimeBlockTreeNode* ThreadRecorder::getTimeBlockTreeNode(S32 index) +TimeBlockTreeNode* ThreadRecorder::getTimeBlockTreeNode( S32 index )  {  	if (0 <= index && index < mNumTimeBlockTreeNodes)  	{ @@ -94,23 +120,25 @@ TimeBlockTreeNode* ThreadRecorder::getTimeBlockTreeNode(S32 index)  } -void ThreadRecorder::activate( Recording* recording ) +void ThreadRecorder::activate( AccumulatorBufferGroup* recording )  {  	ActiveRecording* active_recording = new ActiveRecording(recording);  	if (!mActiveRecordings.empty())  	{ -		mActiveRecordings.back()->mPartialRecording.handOffTo(active_recording->mPartialRecording); +		AccumulatorBufferGroup& prev_active_recording = mActiveRecordings.back()->mPartialRecording; +		prev_active_recording.sync(); +		prev_active_recording.handOffTo(active_recording->mPartialRecording);  	}  	mActiveRecordings.push_back(active_recording);  	mActiveRecordings.back()->mPartialRecording.makePrimary();  } -ThreadRecorder::active_recording_list_t::reverse_iterator ThreadRecorder::bringUpToDate( Recording* recording ) +ThreadRecorder::active_recording_list_t::reverse_iterator ThreadRecorder::bringUpToDate( AccumulatorBufferGroup* recording )  {  	if (mActiveRecordings.empty()) return mActiveRecordings.rend(); -	mActiveRecordings.back()->mPartialRecording.flush(); +	mActiveRecordings.back()->mPartialRecording.sync();  	TimeBlock::updateTimes();  	active_recording_list_t::reverse_iterator it, end_it; @@ -148,145 +176,125 @@ ThreadRecorder::active_recording_list_t::reverse_iterator ThreadRecorder::bringU  	return it;  } -void ThreadRecorder::deactivate( Recording* recording ) +void ThreadRecorder::deactivate( AccumulatorBufferGroup* recording )  {  	active_recording_list_t::reverse_iterator it = bringUpToDate(recording);  	if (it != mActiveRecordings.rend())  	{ -		// and if we've found the recording we wanted to update -		active_recording_list_t::reverse_iterator next_it = it; -		++next_it; -		if (next_it != mActiveRecordings.rend()) -		{ -			(*next_it)->mPartialRecording.makePrimary(); -		} -  		active_recording_list_t::iterator recording_to_remove = (++it).base(); +		bool was_primary = (*recording_to_remove)->mPartialRecording.isPrimary();  		llassert((*recording_to_remove)->mTargetRecording == recording);  		delete *recording_to_remove;  		mActiveRecordings.erase(recording_to_remove); +		if (was_primary) +		{ +			if (mActiveRecordings.empty()) +			{ +				AccumulatorBufferGroup::clearPrimary(); +			} +			else +			{ +				mActiveRecordings.back()->mPartialRecording.makePrimary(); +			} +		}  	}  } -ThreadRecorder::ActiveRecording::ActiveRecording( Recording* target )  +ThreadRecorder::ActiveRecording::ActiveRecording( AccumulatorBufferGroup* target )   :	mTargetRecording(target)  {  }  void ThreadRecorder::ActiveRecording::movePartialToTarget()  { -	mTargetRecording->mBuffers.write()->append(mPartialRecording); +	mTargetRecording->append(mPartialRecording);  	// reset based on self to keep history  	mPartialRecording.reset(&mPartialRecording);  } -/////////////////////////////////////////////////////////////////////// -// SlaveThreadRecorder -/////////////////////////////////////////////////////////////////////// - -SlaveThreadRecorder::SlaveThreadRecorder(MasterThreadRecorder& master) -:	mMasterRecorder(master) -{ -	mMasterRecorder.addSlaveThread(this); +// called by child thread +void ThreadRecorder::addChildRecorder( class ThreadRecorder* child ) +{ LLMutexLock lock(&mChildListMutex); +	mChildThreadRecorders.push_back(child);  } -SlaveThreadRecorder::~SlaveThreadRecorder() -{ -	mMasterRecorder.removeSlaveThread(this); -} +// called by child thread +void ThreadRecorder::removeChildRecorder( class ThreadRecorder* child ) +{ LLMutexLock lock(&mChildListMutex); -void SlaveThreadRecorder::pushToMaster() +for (child_thread_recorder_list_t::iterator it = mChildThreadRecorders.begin(), end_it = mChildThreadRecorders.end(); +	it != end_it; +	++it)  { -	mThreadRecording.stop(); +	if ((*it) == child)  	{ -		LLMutexLock(mMasterRecorder.getSlaveListMutex()); -		mSharedData.appendFrom(mThreadRecording); +		mChildThreadRecorders.erase(it); +		break;  	} -	mThreadRecording.start(); -} - -void SlaveThreadRecorder::SharedData::appendFrom( const Recording& source ) -{ -	LLMutexLock lock(&mRecordingMutex); -	appendRecording(source);  } - -void SlaveThreadRecorder::SharedData::appendTo( Recording& sink ) -{ -	LLMutexLock lock(&mRecordingMutex); -	sink.appendRecording(*this);  } -void SlaveThreadRecorder::SharedData::mergeFrom( const RecordingBuffers& source ) +void ThreadRecorder::pushToParent()  { -	LLMutexLock lock(&mRecordingMutex); -	mBuffers.write()->merge(source); +	{ LLMutexLock lock(&mSharedRecordingMutex);	 +		LLTrace::get_thread_recorder()->bringUpToDate(&mThreadRecordingBuffers); +		mSharedRecordingBuffers.append(mThreadRecordingBuffers); +	}  } +	 -void SlaveThreadRecorder::SharedData::mergeTo( RecordingBuffers& sink ) -{ -	LLMutexLock lock(&mRecordingMutex); -	sink.merge(*mBuffers); -} -void SlaveThreadRecorder::SharedData::reset() -{ -	LLMutexLock lock(&mRecordingMutex); -	Recording::reset(); -} +static LLFastTimer::DeclareTimer FTM_PULL_TRACE_DATA_FROM_CHILDREN("Pull child thread trace data"); -/////////////////////////////////////////////////////////////////////// -// MasterThreadRecorder -/////////////////////////////////////////////////////////////////////// - -static LLFastTimer::DeclareTimer FTM_PULL_TRACE_DATA_FROM_SLAVES("Pull slave trace data"); -void MasterThreadRecorder::pullFromSlaveThreads() +void ThreadRecorder::pullFromChildren()  { -	LLFastTimer _(FTM_PULL_TRACE_DATA_FROM_SLAVES); +	LLFastTimer _(FTM_PULL_TRACE_DATA_FROM_CHILDREN);  	if (mActiveRecordings.empty()) return; -	LLMutexLock lock(&mSlaveListMutex); +	{ LLMutexLock lock(&mChildListMutex); -	RecordingBuffers& target_recording_buffers = mActiveRecordings.back()->mPartialRecording; -	for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end(); -		it != end_it; -		++it) -	{ -		// ignore block timing info for now -		(*it)->mSharedData.mergeTo(target_recording_buffers); -		(*it)->mSharedData.reset(); +		AccumulatorBufferGroup& target_recording_buffers = mActiveRecordings.back()->mPartialRecording; +		target_recording_buffers.sync(); +		for (child_thread_recorder_list_t::iterator it = mChildThreadRecorders.begin(), end_it = mChildThreadRecorders.end(); +			it != end_it; +			++it) +		{ LLMutexLock lock(&(*it)->mSharedRecordingMutex); + +			target_recording_buffers.merge((*it)->mSharedRecordingBuffers); +			(*it)->mSharedRecordingBuffers.reset(); +		}  	}  } -void MasterThreadRecorder::addSlaveThread( class SlaveThreadRecorder* child ) + +void set_master_thread_recorder(ThreadRecorder* recorder)  { -	LLMutexLock lock(&mSlaveListMutex); +	sMasterThreadRecorder = recorder; +} -	mSlaveThreadRecorders.push_back(child); + +ThreadRecorder* get_master_thread_recorder() +{ +	return sMasterThreadRecorder;  } -void MasterThreadRecorder::removeSlaveThread( class SlaveThreadRecorder* child ) +LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder_ptr()  { -	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) == child) -		{ -			mSlaveThreadRecorders.erase(it); -			break; -		} -	} +const LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder() +{ +	return get_thread_recorder_ptr();  } -void MasterThreadRecorder::pushToMaster() -{} +void set_thread_recorder(ThreadRecorder* recorder) +{ +	get_thread_recorder_ptr() = recorder; +} -MasterThreadRecorder::MasterThreadRecorder() -{}  } diff --git a/indra/llcommon/lltracethreadrecorder.h b/indra/llcommon/lltracethreadrecorder.h index bf3701304f..535f855200 100644 --- a/indra/llcommon/lltracethreadrecorder.h +++ b/indra/llcommon/lltracethreadrecorder.h @@ -31,7 +31,8 @@  #include "llpreprocessor.h"  #include "llmutex.h" -#include "lltracerecording.h" +#include "lltraceaccumulators.h" +#include "llthreadlocalstorage.h"  namespace LLTrace  { @@ -42,85 +43,60 @@ namespace LLTrace  		typedef std::vector<ActiveRecording*> active_recording_list_t;  	public:  		ThreadRecorder(); +		explicit ThreadRecorder(ThreadRecorder& master); -		virtual ~ThreadRecorder(); +		~ThreadRecorder(); -		void activate(Recording* recording); -		void deactivate(Recording* recording); -		active_recording_list_t::reverse_iterator bringUpToDate(Recording* recording); +		void activate(AccumulatorBufferGroup* recording); +		void deactivate(AccumulatorBufferGroup* recording); +		active_recording_list_t::reverse_iterator bringUpToDate(AccumulatorBufferGroup* recording); -		virtual void pushToMaster() = 0; +		void addChildRecorder(class ThreadRecorder* child); +		void removeChildRecorder(class ThreadRecorder* child); + +		// call this periodically to gather stats data from child threads +		void pullFromChildren(); +		void pushToParent();  		TimeBlockTreeNode* getTimeBlockTreeNode(S32 index);  	protected: +		void init(); + +	protected:  		struct ActiveRecording  		{ -			ActiveRecording(Recording* target); +			ActiveRecording(AccumulatorBufferGroup* target); -			Recording*			mTargetRecording; -			RecordingBuffers	mPartialRecording; +			AccumulatorBufferGroup*	mTargetRecording; +			AccumulatorBufferGroup	mPartialRecording;  			void movePartialToTarget();  		}; -		Recording					mThreadRecording; - -		active_recording_list_t		mActiveRecordings; - -		class BlockTimer*			mRootTimer; -		TimeBlockTreeNode*			mTimeBlockTreeNodes; -		size_t						mNumTimeBlockTreeNodes; -	}; - -	class LL_COMMON_API MasterThreadRecorder : public ThreadRecorder -	{ -	public: -		MasterThreadRecorder(); - -		void addSlaveThread(class SlaveThreadRecorder* child); -		void removeSlaveThread(class SlaveThreadRecorder* child); -		/*virtual */ void pushToMaster(); +		AccumulatorBufferGroup			mThreadRecordingBuffers; -		// call this periodically to gather stats data from slave threads -		void pullFromSlaveThreads(); +		BlockTimerStackRecord			mBlockTimerStackRecord; +		active_recording_list_t			mActiveRecordings; -		LLMutex* getSlaveListMutex() { return &mSlaveListMutex; } +		class BlockTimer*				mRootTimer; +		TimeBlockTreeNode*				mTimeBlockTreeNodes; +		size_t							mNumTimeBlockTreeNodes; +		typedef std::list<class ThreadRecorder*> child_thread_recorder_list_t; +		child_thread_recorder_list_t	mChildThreadRecorders;	// list of child thread recorders associated with this master +		LLMutex							mChildListMutex;		// protects access to child list +		LLMutex							mSharedRecordingMutex; +		AccumulatorBufferGroup			mSharedRecordingBuffers; +		ThreadRecorder*					mMasterRecorder; -	private: - -		typedef std::list<class SlaveThreadRecorder*> slave_thread_recorder_list_t; - -		slave_thread_recorder_list_t	mSlaveThreadRecorders;	// list of slave thread recorders associated with this master -		LLMutex							mSlaveListMutex;		// protects access to slave list  	}; -	class LL_COMMON_API SlaveThreadRecorder : public ThreadRecorder -	{ -	public: -		SlaveThreadRecorder(MasterThreadRecorder& master); -		~SlaveThreadRecorder(); - -		// call this periodically to gather stats data for master thread to consume -		/*virtual*/ void pushToMaster(); +	const LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder(); +	void set_thread_recorder(ThreadRecorder*); -		MasterThreadRecorder* 	mMaster; - -		class SharedData : public Recording -		{ -		public: -			void appendFrom(const Recording& source); -			void appendTo(Recording& sink); -			void mergeFrom(const RecordingBuffers& source); -			void mergeTo(RecordingBuffers& sink); -			void reset(); -		private: -			LLMutex		mRecordingMutex; -		}; -		SharedData				mSharedData; -		MasterThreadRecorder&	mMasterRecorder; -	}; +	void set_master_thread_recorder(ThreadRecorder*); +	ThreadRecorder* get_master_thread_recorder();  }  #endif // LL_LLTRACETHREADRECORDER_H diff --git a/indra/llcommon/llunit.h b/indra/llcommon/llunit.h index 2402cdbb95..c9bbed5574 100644 --- a/indra/llcommon/llunit.h +++ b/indra/llcommon/llunit.h @@ -75,17 +75,11 @@ struct LLUnit  	}  	template<typename NEW_UNIT_TYPE>  -	STORAGE_TYPE getAs() +	STORAGE_TYPE valueAs()  	{  		return LLUnit<STORAGE_TYPE, NEW_UNIT_TYPE>(*this).value();  	} -	template<typename NEW_UNIT_TYPE>  -	STORAGE_TYPE setAs(STORAGE_TYPE val) -	{ -		*this = LLUnit<STORAGE_TYPE, NEW_UNIT_TYPE>(val); -	} -  	void operator += (storage_t value)  	{  		mValue += value; @@ -181,6 +175,7 @@ LL_FORCE_INLINE void ll_convert_units(LLUnit<S1, T1> in, LLUnit<S2, T2>& out, ..  	if (boost::is_same<T1, typename T1::base_unit_t>::value)  	{  		if (boost::is_same<T2, typename T2::base_unit_t>::value) +  		{  			// T1 and T2 fully reduced and equal...just copy  			out = (S2)in.value(); @@ -493,26 +488,45 @@ struct LLUnitInverseLinearOps  	}  }; -#define LL_DECLARE_BASE_UNIT(base_unit_name, unit_label) \ -struct base_unit_name { typedef base_unit_name base_unit_t; static const char* getUnitLabel() { return unit_label; }} - -#define LL_DECLARE_DERIVED_UNIT(unit_name, unit_label, base_unit_name, conversion_operation)	\ -struct unit_name                                                                                \ -{                                                                                               \ -	typedef base_unit_name base_unit_t;                                                         \ -	static const char* getUnitLabel() { return unit_label; }									\ -};                                                                                              \ -	                                                                                            \ -template<typename S1, typename S2>                                                              \ -void ll_convert_units(LLUnit<S1, unit_name> in, LLUnit<S2, base_unit_name>& out)                \ -{                                                                                               \ -	out = (S2)(LLUnitLinearOps<S1>(in.value()) conversion_operation).mValue;                    \ -}                                                                                               \ -                                                                                                \ -template<typename S1, typename S2>                                                              \ -void ll_convert_units(LLUnit<S1, base_unit_name> in, LLUnit<S2, unit_name>& out)                \ -{                                                                                               \ -	out = (S2)(LLUnitInverseLinearOps<S1>(in.value()) conversion_operation).mValue;             \ +#define LL_DECLARE_BASE_UNIT(base_unit_name, unit_label)                                             \ +struct base_unit_name                                                                                \ +{                                                                                                    \ +	typedef base_unit_name base_unit_t;                                                              \ +	static const char* getUnitLabel() { return unit_label; }                                         \ +	template<typename T>                                                                             \ +	static LLUnit<T, base_unit_name> fromValue(T value) { return LLUnit<T, base_unit_name>(value); } \ +	template<typename STORAGE_T, typename UNIT_T>                                                    \ +	static LLUnit<STORAGE_T, base_unit_name> fromValue(LLUnit<STORAGE_T, UNIT_T> value)              \ +	{ return LLUnit<STORAGE_T, base_unit_name>(value); }                                             \ +};                                                                                                   \ +template<typename T> std::ostream& operator<<(std::ostream& s, const LLUnit<T, base_unit_name>& val) \ +{ s << val.value() << base_unit_name::getUnitLabel; return s; } + + +#define LL_DECLARE_DERIVED_UNIT(unit_name, unit_label, base_unit_name, conversion_operation)	 \ +struct unit_name                                                                                 \ +{                                                                                                \ +	typedef base_unit_name base_unit_t;                                                          \ +	static const char* getUnitLabel() { return unit_label; }									 \ +	template<typename T>                                                                         \ +	static LLUnit<T, unit_name> fromValue(T value) { return LLUnit<T, unit_name>(value); }		 \ +	template<typename STORAGE_T, typename UNIT_T>                                                \ +	static LLUnit<STORAGE_T, unit_name> fromValue(LLUnit<STORAGE_T, UNIT_T> value)				 \ +	{ return LLUnit<STORAGE_T, unit_name>(value); }												 \ +};                                                                                               \ +template<typename T> std::ostream& operator<<(std::ostream& s, const LLUnit<T, unit_name>& val)  \ +{ s << val.value() << unit_name::getUnitLabel; return s; }                                       \ +	                                                                                             \ +template<typename S1, typename S2>                                                               \ +void ll_convert_units(LLUnit<S1, unit_name> in, LLUnit<S2, base_unit_name>& out)                 \ +{                                                                                                \ +	out = (S2)(LLUnitLinearOps<S1>(in.value()) conversion_operation).mValue;                     \ +}                                                                                                \ +                                                                                                 \ +template<typename S1, typename S2>                                                               \ +void ll_convert_units(LLUnit<S1, base_unit_name> in, LLUnit<S2, unit_name>& out)                 \ +{                                                                                                \ +	out = (S2)(LLUnitInverseLinearOps<S1>(in.value()) conversion_operation).mValue;              \  }                                                                                                 // diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 50df2ebe55..8477e62db7 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -159,9 +159,8 @@ void LLImageBase::sanityCheck()  void LLImageBase::deleteData()  {  	FREE_MEM(sPrivatePoolp, mData) ; -	memDisclaimAmount(mDataSize); +	memDisclaimAmount(mDataSize) = 0;  	mData = NULL; -	mDataSize = 0;  }  // virtual @@ -225,9 +224,7 @@ U8* LLImageBase::reallocateData(S32 size)  		FREE_MEM(sPrivatePoolp, mData) ;  	}  	mData = new_datap; -	memDisclaimAmount(mDataSize); -	mDataSize = size; -	memClaimAmount(mDataSize); +	memClaimAmount(memDisclaimAmount(mDataSize) = size);  	return mData;  } @@ -1612,9 +1609,8 @@ static void avg4_colors2(const U8* a, const U8* b, const U8* c, const U8* d, U8*  void LLImageBase::setDataAndSize(U8 *data, S32 size)  {   	ll_assert_aligned(data, 16); -	memDisclaimAmount(mDataSize); -	mData = data; mDataSize = size;  -	memClaimAmount(mDataSize); +	mData = data;  +	memClaimAmount(memDisclaimAmount(mDataSize) = size);   }	  //static diff --git a/indra/llimage/tests/llimageworker_test.cpp b/indra/llimage/tests/llimageworker_test.cpp index b6f2694742..aba7883974 100755 --- a/indra/llimage/tests/llimageworker_test.cpp +++ b/indra/llimage/tests/llimageworker_test.cpp @@ -115,17 +115,14 @@ namespace tut  	{  		// Instance to be tested  		LLImageDecodeThread* mThread; -  		// Constructor and destructor of the test wrapper  		imagedecodethread_test()  		{ -			LLTrace::init();  			mThread = NULL;  		}  		~imagedecodethread_test()  		{  			delete mThread; -			LLTrace::cleanup();  		}  	}; @@ -143,7 +140,6 @@ namespace tut  		imagerequest_test()  		{  			done = false; -			LLTrace::init();  			mRequest = new LLImageDecodeThread::ImageRequest(0, 0,  											 LLQueuedThread::PRIORITY_NORMAL, 0, FALSE, @@ -154,7 +150,6 @@ namespace tut  			// We should delete the object *but*, because its destructor is protected, that cannot be  			// done from outside an LLImageDecodeThread instance... So we leak memory here... It's fine...  			//delete mRequest; -			LLTrace::cleanup();  		}  	}; diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp index d3cc2733e6..fd88565de4 100755 --- a/indra/llui/llstatbar.cpp +++ b/indra/llui/llstatbar.cpp @@ -345,9 +345,9 @@ void LLStatBar::draw()  					else if (mSampleFloatp)  					{  						//rate isn't defined for sample stats, so use mean -						begin       = ((recording.getMean(*mEventFloatp)  - mMinBar) * value_scale); -						end         = ((recording.getMean(*mEventFloatp)  - mMinBar) * value_scale) + 1; -						num_samples = recording.getSampleCount(*mEventFloatp); +						begin       = ((recording.getMean(*mSampleFloatp)  - mMinBar) * value_scale); +						end         = ((recording.getMean(*mSampleFloatp)  - mMinBar) * value_scale) + 1; +						num_samples = recording.getSampleCount(*mSampleFloatp);  					}  				}  				else @@ -366,9 +366,9 @@ void LLStatBar::draw()  					}  					else if (mSampleFloatp)  					{ -						begin       = ((recording.getMean(*mEventFloatp)  - mMinBar) * value_scale); -						end         = ((recording.getMean(*mEventFloatp)  - mMinBar) * value_scale) + 1; -						num_samples = recording.getSampleCount(*mEventFloatp); +						begin       = ((recording.getMean(*mSampleFloatp)  - mMinBar) * value_scale); +						end         = ((recording.getMean(*mSampleFloatp)  - mMinBar) * value_scale) + 1; +						num_samples = recording.getSampleCount(*mSampleFloatp);  					}   				} diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 733c9cc9df..e77f793a43 100755 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1297,7 +1297,7 @@ bool LLAppViewer::mainLoop()  		LLTrace::get_frame_recording().nextPeriod();  		LLTrace::TimeBlock::logStats(); -		LLTrace::getUIThreadRecorder().pullFromSlaveThreads(); +		LLTrace::get_master_thread_recorder()->pullFromChildren();  		//clear call stack records  		llclearcallstacks; @@ -5617,6 +5617,6 @@ void LLAppViewer::metricsSend(bool enable_reporting)  	// Reset even if we can't report.  Rather than gather up a huge chunk of  	// data, we'll keep to our sampling interval and retain the data  	// resolution in time. -	gViewerAssetStats->reset(); +	gViewerAssetStats->restart();  } diff --git a/indra/newview/llclassifiedstatsresponder.cpp b/indra/newview/llclassifiedstatsresponder.cpp index e3cd83e174..1e1c9039fb 100755 --- a/indra/newview/llclassifiedstatsresponder.cpp +++ b/indra/newview/llclassifiedstatsresponder.cpp @@ -38,10 +38,8 @@  #include "message.h"  LLClassifiedStatsResponder::LLClassifiedStatsResponder(LLUUID classified_id) -: -mClassifiedID(classified_id) -{ -} +:	mClassifiedID(classified_id) +{}  /*virtual*/  void LLClassifiedStatsResponder::result(const LLSD& content) @@ -53,12 +51,11 @@ void LLClassifiedStatsResponder::result(const LLSD& content)  	S32 search_map = content["search_map_clicks"].asInteger();  	S32 search_profile = content["search_profile_clicks"].asInteger(); -	LLPanelClassifiedInfo::setClickThrough( -		mClassifiedID,  -		teleport + search_teleport,  -		map + search_map, -		profile + search_profile, -		true); +	LLPanelClassifiedInfo::setClickThrough(	mClassifiedID,  +											teleport + search_teleport,  +											map + search_map, +											profile + search_profile, +											true);  }  /*virtual*/ diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index d3a97fde0e..d922659435 100755 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -430,18 +430,18 @@ void LLFastTimerView::draw()  					}  void LLFastTimerView::onOpen(const LLSD& key) -				{ +{  	setPauseState(false);  	mRecording.reset();  	mRecording.appendPeriodicRecording(LLTrace::get_frame_recording());  	for(std::deque<TimerBarRow>::iterator it = mTimerBarRows.begin(), end_it = mTimerBarRows.end();  		it != end_it;  -				++it) -			{ +		++it) +	{  		delete []it->mBars;  		it->mBars = NULL; -					} -					} +	} +}  void saveChart(const std::string& label, const char* suffix, LLImageRaw* scratch) @@ -1101,7 +1101,7 @@ void LLFastTimerView::drawLineGraph()  			j--)  		{  			LLTrace::Recording& recording = mRecording.getPrevRecording(j); -			LLUnit<F32, LLUnits::Seconds> time = llmax(recording.getSum(*idp), LLUnit<F64, LLUnits::Seconds>(0.000001)); +			LLUnit<F32, LLUnits::Seconds> time = llmax(recording.getSum(*idp), LLUnits::Seconds::fromValue(0.000001));  			U32 calls = recording.getSum(idp->callCount());  			if (is_hover_timer) @@ -1126,7 +1126,7 @@ void LLFastTimerView::drawLineGraph()  			}  			gGL.vertex2f(x,y);  			gGL.vertex2f(x,mGraphRect.mBottom); -} +		}  		gGL.end();  		if (mHoverID == idp) @@ -1146,7 +1146,7 @@ void LLFastTimerView::drawLineGraph()  	max_time = lerp(max_time.value(), cur_max.value(), LLSmoothInterpolation::getInterpolant(0.1f));  	if (llabs((max_time - cur_max).value()) <= 1)  	{ -		max_time = llmax(LLUnit<F32, LLUnits::Microseconds>(1), LLUnit<F32, LLUnits::Microseconds>(cur_max)); +		max_time = llmax(LLUnits::Microseconds::fromValue(1.f), LLUnits::Microseconds::fromValue(cur_max));  	}  	max_calls = llround(lerp((F32)max_calls, (F32) cur_max_calls, LLSmoothInterpolation::getInterpolant(0.1f))); @@ -1423,11 +1423,11 @@ void LLFastTimerView::updateTotalTime()  		mTotalTimeDisplay = mRecording.getPeriodMax(FTM_FRAME, 20);  		break;  	default: -		mTotalTimeDisplay = LLUnit<F32, LLUnits::Milliseconds>(100); +		mTotalTimeDisplay = LLUnits::Milliseconds::fromValue(100);  		break;  	} -	mTotalTimeDisplay = LLUnit<F32, LLUnits::Milliseconds>(llceil(mTotalTimeDisplay.getAs<LLUnits::Milliseconds>() / 20.f) * 20.f); +	mTotalTimeDisplay = LLUnits::Milliseconds::fromValue(llceil(mTotalTimeDisplay.valueAs<LLUnits::Milliseconds>() / 20.f) * 20.f);  }  void LLFastTimerView::drawBars() diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp index ed9eeb9330..342b45863a 100644 --- a/indra/newview/llscenemonitor.cpp +++ b/indra/newview/llscenemonitor.cpp @@ -260,14 +260,7 @@ void LLSceneMonitor::capture()  	static LLCachedControl<bool> monitor_enabled(gSavedSettings, "SceneLoadingMonitorEnabled");  	static LLCachedControl<F32>  scene_load_sample_time(gSavedSettings, "SceneLoadingMonitorSampleTime");  	static LLFrameTimer timer;	 - -	if (mEnabled  -		&&	(mMonitorRecording.getSum(*LLViewerCamera::getVelocityStat()) > 0.1f -			|| mMonitorRecording.getSum(*LLViewerCamera::getAngularVelocityStat()) > 0.05f)) -	{ -		reset(); -		freezeScene(); -	} +	static bool force_capture = true;  	bool enabled = monitor_enabled || mDebugViewerVisible;  	if(mEnabled != enabled) @@ -275,6 +268,7 @@ void LLSceneMonitor::capture()  		if(mEnabled)  		{  			unfreezeScene(); +			force_capture = true;  		}  		else  		{ @@ -285,11 +279,23 @@ void LLSceneMonitor::capture()  		mEnabled = enabled;  	} -	if(timer.getElapsedTimeF32() > scene_load_sample_time() +	if (mEnabled  +		&&	(mMonitorRecording.getSum(*LLViewerCamera::getVelocityStat()) > 0.1f +		|| mMonitorRecording.getSum(*LLViewerCamera::getAngularVelocityStat()) > 0.05f)) +	{ +		reset(); +		freezeScene(); +		force_capture = true; +	} + +	if((timer.getElapsedTimeF32() > scene_load_sample_time()  +			|| force_capture)  		&& mEnabled  		&& LLGLSLShader::sNoFixedFunction  		&& last_capture_time != gFrameCount)  	{ +		force_capture = false; +  		mSceneLoadRecording.resume();  		mMonitorRecording.resume(); @@ -479,12 +485,10 @@ void LLSceneMonitor::fetchQueryResult()  			if(mDiffResult > diff_threshold())  			{  				mSceneLoadRecording.extend(); -				llassert(mSceneLoadRecording.getAcceptedRecording().getLastRecording().getSum(LLStatViewer::FPS));  			}  			else  			{  				mSceneLoadRecording.getPotentialRecording().nextPeriod(); -				llassert(mSceneLoadRecording.getPotentialRecording().getLastRecording().getSum(LLStatViewer::FPS));  			}  		}  	} @@ -620,7 +624,7 @@ void LLSceneMonitor::dumpToFile(std::string file_name)  		for (S32 frame = 1; frame <= frame_count; frame++)  		{ -			os << ", " << scene_load_recording.getPrevRecording(frame_count - frame).getMax(*it).getAs<LLUnits::Kibibytes>(); +			os << ", " << scene_load_recording.getPrevRecording(frame_count - frame).getMax(*it).valueAs<LLUnits::Kibibytes>();  		}  		os << '\n'; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index de8d549055..097ea7cc8d 100755 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2054,6 +2054,7 @@ bool idle_startup()  		const F32 wearables_time = wearables_timer.getElapsedTimeF32();  		static LLCachedControl<F32> max_wearables_time(gSavedSettings, "ClothingLoadingDelay"); +		display_startup();  		if (!gAgent.isGenderChosen() && isAgentAvatarValid())  		{  			// No point in waiting for clothing, we don't even @@ -2067,50 +2068,39 @@ bool idle_startup()  			LLNotificationsUtil::add("WelcomeChooseSex", LLSD(), LLSD(),  				callback_choose_gender);  			LLStartUp::setStartupState( STATE_CLEANUP ); -			return TRUE;  		} -		 -		display_startup(); - -		if (wearables_time > max_wearables_time()) +		else if (wearables_time >= max_wearables_time())  		{  			LLNotificationsUtil::add("ClothingLoading");  			record(LLStatViewer::LOADING_WEARABLES_LONG_DELAY, wearables_time);  			LLStartUp::setStartupState( STATE_CLEANUP ); -			return TRUE;  		} - -		if (gAgent.isFirstLogin()) +		else if (gAgent.isFirstLogin() +				&& isAgentAvatarValid() +				&& gAgentAvatarp->isFullyLoaded())  		{  			// wait for avatar to be completely loaded -			if (isAgentAvatarValid() -				&& gAgentAvatarp->isFullyLoaded()) -			{ -				//llinfos << "avatar fully loaded" << llendl; -				LLStartUp::setStartupState( STATE_CLEANUP ); -				return TRUE; -			} +			//llinfos << "avatar fully loaded" << llendl; +			LLStartUp::setStartupState( STATE_CLEANUP ); +		} +		// OK to just get the wearables +		else if (!gAgent.isFirstLogin() && gAgentWearables.areWearablesLoaded() ) +		{ +			// We have our clothing, proceed. +			//llinfos << "wearables loaded" << llendl; +			LLStartUp::setStartupState( STATE_CLEANUP );  		}  		else  		{ -			// OK to just get the wearables -			if ( gAgentWearables.areWearablesLoaded() ) -			{ -				// We have our clothing, proceed. -				//llinfos << "wearables loaded" << llendl; -				LLStartUp::setStartupState( STATE_CLEANUP ); -				return TRUE; -			} +			display_startup(); +			update_texture_fetch(); +			display_startup(); +			set_startup_status(0.9f + 0.1f * wearables_time / max_wearables_time(), +				LLTrans::getString("LoginDownloadingClothing").c_str(), +				gAgent.mMOTD.c_str()); +			display_startup();  		} - -		display_startup(); -		update_texture_fetch(); -		display_startup(); -		set_startup_status(0.9f + 0.1f * wearables_time / max_wearables_time(), -						 LLTrans::getString("LoginDownloadingClothing").c_str(), -						 gAgent.mMOTD.c_str()); -		display_startup(); -		return TRUE; +		//fall through this frame to STATE_CLEANUP  	}  	if (STATE_CLEANUP == LLStartUp::getStartupState()) diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 4b9a950b98..0390649a1c 100755 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -504,81 +504,85 @@ private:  	static const char* sStateDescs[];  	e_state mState;  	void setState(e_state new_state); -	e_write_to_cache_state mWriteToCacheState; -	LLTextureFetch* mFetcher; + +	e_write_to_cache_state		mWriteToCacheState; +	LLTextureFetch*             mFetcher;  	LLPointer<LLImageFormatted> mFormattedImage; -	LLPointer<LLImageRaw> mRawImage; -	LLPointer<LLImageRaw> mAuxImage; -	FTType mFTType; -	LLUUID mID; -	LLHost mHost; -	std::string mUrl; -	U8 mType; -	F32 mImagePriority; -	U32 mWorkPriority; -	F32 mRequestedPriority; -	S32 mDesiredDiscard; -	S32 mSimRequestedDiscard; -	S32 mRequestedDiscard; -	S32 mLoadedDiscard; -	S32 mDecodedDiscard; -	LLFrameTimer mRequestedTimer; -	LLFrameTimer mFetchTimer; -	LLTimer			mCacheReadTimer; -	F32				mCacheReadTime; -	LLTextureCache::handle_t mCacheReadHandle; -	LLTextureCache::handle_t mCacheWriteHandle; -	S32 mRequestedSize; -	S32 mRequestedOffset; -	S32 mDesiredSize; -	S32 mFileSize; -	S32 mCachedSize;	 -	e_request_state mSentRequest; -	handle_t mDecodeHandle; -	BOOL mLoaded; -	BOOL mDecoded; -	BOOL mWritten; -	BOOL mNeedsAux; -	BOOL mHaveAllData; -	BOOL mInLocalCache; -	BOOL mInCache; -	bool mCanUseHTTP ; -	bool mCanUseNET ; //can get from asset server. -	S32 mRetryAttempt; -	S32 mActiveCount; -	LLCore::HttpStatus mGetStatus; -	std::string mGetReason; +	LLPointer<LLImageRaw>       mRawImage, +								mAuxImage; +	FTType                      mFTType; +	LLUUID                      mID; +	LLHost                      mHost; +	std::string                 mUrl; +	U8                          mType; +	F32                         mImagePriority; +	U32                         mWorkPriority; +	F32                         mRequestedPriority; +	S32                         mDesiredDiscard, +								mSimRequestedDiscard, +								mRequestedDiscard, +								mLoadedDiscard, +								mDecodedDiscard; +	LLFrameTimer                mRequestedTimer, +								mFetchTimer; +	LLTimer						mCacheReadTimer; +	F32							mCacheReadTime; +	LLTextureCache::handle_t    mCacheReadHandle, +								mCacheWriteHandle; +	S32                         mRequestedSize, +								mRequestedOffset, +								mDesiredSize, +								mFileSize, +								mCachedSize; +	e_request_state             mSentRequest; +	handle_t                    mDecodeHandle; +	BOOL                        mLoaded; +	BOOL                        mDecoded; +	BOOL                        mWritten; +	BOOL                        mNeedsAux; +	BOOL                        mHaveAllData; +	BOOL                        mInLocalCache; +	BOOL                        mInCache; +	bool                        mCanUseHTTP, +								mCanUseNET ; //can get from asset server. +	S32                         mRetryAttempt; +	S32                         mActiveCount; +	LLCore::HttpStatus          mGetStatus; +	std::string                 mGetReason;  	// Work Data -	LLMutex mWorkMutex; +	LLMutex						mWorkMutex;  	struct PacketData  	{ -		PacketData(U8* data, S32 size) { mData = data; mSize = size; } +		PacketData(U8* data, S32 size)  +		:	mData(data), mSize(size)  +		{}  		~PacketData() { clearData(); }  		void clearData() { delete[] mData; mData = NULL; } -		U8* mData; -		U32 mSize; + +		U8*		mData; +		U32		mSize;  	}; -	std::vector<PacketData*> mPackets; -	S32 mFirstPacket; -	S32 mLastPacket; -	U16 mTotalPackets; -	U8 mImageCodec; +	std::vector<PacketData*>	mPackets; +	S32							mFirstPacket; +	S32							mLastPacket; +	U16							mTotalPackets; +	U8							mImageCodec;  	LLViewerAssetStats::duration_t mMetricsStartTime; -	LLCore::HttpHandle		mHttpHandle;				// Handle of any active request -	LLCore::BufferArray	*	mHttpBufferArray;			// Refcounted pointer to response data  -	int						mHttpPolicyClass; -	bool					mHttpActive;				// Active request to http library -	unsigned int			mHttpReplySize;				// Actual received data size -	unsigned int			mHttpReplyOffset;			// Actual received data offset -	bool					mHttpHasResource;			// Counts against Fetcher's mHttpSemaphore +	LLCore::HttpHandle			mHttpHandle;				// Handle of any active request +	LLCore::BufferArray	*		mHttpBufferArray;			// Refcounted pointer to response data  +	S32							mHttpPolicyClass; +	bool						mHttpActive;				// Active request to http library +	U32							mHttpReplySize,				// Actual received data size +								mHttpReplyOffset;			// Actual received data offset +	bool						mHttpHasResource;			// Counts against Fetcher's mHttpSemaphore  	// State history -	U32						mCacheReadCount; -	U32						mCacheWriteCount; -	U32						mResourceWaitCount;			// Requests entering WAIT_HTTP_RESOURCE2 +	U32							mCacheReadCount, +								mCacheWriteCount, +								mResourceWaitCount;			// Requests entering WAIT_HTTP_RESOURCE2  };  ////////////////////////////////////////////////////////////////////////////// @@ -2390,7 +2394,7 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image  	  mFetcherLocked(FALSE)  {  	mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS"); -	mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold")); +	mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), LLUnits::Bytes::fromValue(gSavedSettings.getU32("TextureLoggingThreshold")));  	LLTextureFetchDebugger::sDebuggerEnabled = gSavedSettings.getBOOL("TextureFetchDebuggerEnabled");  	if(LLTextureFetchDebugger::isEnabled()) @@ -3369,7 +3373,7 @@ bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U1  		if (log_to_viewer_log || log_to_sim)  		{ -			U64 timeNow = LLTimer::getTotalTime(); +			LLUnit<U64, LLUnits::Microseconds> timeNow = LLTimer::getTotalTime();  			mTextureInfo.setRequestSize(id, worker->mFileSize);  			mTextureInfo.setRequestCompleteTimeAndLog(id, timeNow);  		} diff --git a/indra/newview/lltextureinfo.cpp b/indra/newview/lltextureinfo.cpp index adfdbc997e..3ae85d56da 100755 --- a/indra/newview/lltextureinfo.cpp +++ b/indra/newview/lltextureinfo.cpp @@ -29,26 +29,28 @@  #include "lltextureinfo.h"  #include "lltexturestats.h"  #include "llviewercontrol.h" +#include "lltrace.h" + +static LLTrace::CountStatHandle<S32> sTextureDownloadsStarted("texture_downloads_started", "number of texture downloads initiated"); +static LLTrace::CountStatHandle<S32> sTextureDownloadsCompleted("texture_downloads_completed", "number of texture downloads completed"); +static LLTrace::CountStatHandle<LLUnit<S32, LLUnits::Bytes> > sTextureDataDownloaded("texture_data_downloaded", "amount of texture data downloaded"); +static LLTrace::CountStatHandle<LLUnit<U32, LLUnits::Milliseconds> > sTexureDownloadTime("texture_download_time", "amount of time spent fetching textures");  LLTextureInfo::LLTextureInfo() :   	mLogTextureDownloadsToViewerLog(false),  	mLogTextureDownloadsToSimulator(false), -	mTotalBytes(0), -	mTotalMilliseconds(0), -	mTextureDownloadsStarted(0), -	mTextureDownloadsCompleted(0),  	mTextureDownloadProtocol("NONE"), -	mTextureLogThreshold(100 * 1024), -	mCurrentStatsBundleStartTime(0) +	mTextureLogThreshold(LLUnits::Kibibytes::fromValue(100))  {  	mTextures.clear(); +	mRecording.start();  } -void LLTextureInfo::setUpLogging(bool writeToViewerLog, bool sendToSim, U32 textureLogThreshold) +void LLTextureInfo::setUpLogging(bool writeToViewerLog, bool sendToSim, LLUnit<U32, LLUnits::Bytes> textureLogThreshold)  {  	mLogTextureDownloadsToViewerLog = writeToViewerLog;  	mLogTextureDownloadsToSimulator = sendToSim; -	mTextureLogThreshold = textureLogThreshold; +	mTextureLogThreshold = LLUnit<U32, LLUnits::Bytes>(textureLogThreshold);  }  LLTextureInfo::~LLTextureInfo() @@ -94,7 +96,7 @@ void LLTextureInfo::setRequestStartTime(const LLUUID& id, U64 startTime)  		addRequest(id);  	}  	mTextures[id]->mStartTime = startTime; -	mTextureDownloadsStarted++; +	add(sTextureDownloadsStarted, 1);  }  void LLTextureInfo::setRequestSize(const LLUUID& id, U32 size) @@ -124,16 +126,19 @@ void LLTextureInfo::setRequestType(const LLUUID& id, LLTextureInfoDetails::LLReq  	mTextures[id]->mType = type;  } -void LLTextureInfo::setRequestCompleteTimeAndLog(const LLUUID& id, U64 completeTime) +void LLTextureInfo::setRequestCompleteTimeAndLog(const LLUUID& id, LLUnit<U64, LLUnits::Microseconds> completeTime)  {  	if (!has(id))  	{  		addRequest(id);  	} -	mTextures[id]->mCompleteTime = completeTime; +	 +	LLTextureInfoDetails& details = *mTextures[id]; + +	details.mCompleteTime = completeTime;  	std::string protocol = "NONE"; -	switch(mTextures[id]->mType) +	switch(details.mType)  	{  	case LLTextureInfoDetails::REQUEST_TYPE_HTTP:  		protocol = "HTTP"; @@ -150,24 +155,23 @@ void LLTextureInfo::setRequestCompleteTimeAndLog(const LLUUID& id, U64 completeT  	if (mLogTextureDownloadsToViewerLog)  	{ -		llinfos << "texture=" << id  -			<< " start=" << mTextures[id]->mStartTime  -			<< " end=" << mTextures[id]->mCompleteTime -			<< " size=" << mTextures[id]->mSize -			<< " offset=" << mTextures[id]->mOffset -			<< " length_in_ms=" << (mTextures[id]->mCompleteTime - mTextures[id]->mStartTime) / 1000 -			<< " protocol=" << protocol -			<< llendl; +		llinfos << "texture="   << id  +			    << " start="    << details.mStartTime  +			    << " end="      << details.mCompleteTime +			    << " size="     << details.mSize +			    << " offset="   << details.mOffset +			    << " length="   << LLUnit<U32, LLUnits::Milliseconds>(details.mCompleteTime - details.mStartTime) +			    << " protocol=" << protocol +			    << llendl;  	}  	if(mLogTextureDownloadsToSimulator)  	{ -		S32 texture_stats_upload_threshold = mTextureLogThreshold; -		mTotalBytes += mTextures[id]->mSize; -		mTotalMilliseconds += mTextures[id]->mCompleteTime - mTextures[id]->mStartTime; -		mTextureDownloadsCompleted++; +		add(sTextureDataDownloaded, details.mSize); +		add(sTexureDownloadTime, details.mCompleteTime - details.mStartTime); +		add(sTextureDownloadsCompleted, 1);  		mTextureDownloadProtocol = protocol; -		if (mTotalBytes >= texture_stats_upload_threshold) +		if (mRecording.getSum(sTextureDataDownloaded) >= mTextureLogThreshold)  		{  			LLSD texture_data;  			std::stringstream startTime; @@ -189,35 +193,33 @@ LLSD LLTextureInfo::getAverages()  {  	LLSD averagedTextureData;  	S32 averageDownloadRate; -	if(mTotalMilliseconds == 0) +	LLUnit<U32, LLUnits::Milliseconds> download_time = mRecording.getSum(sTexureDownloadTime); +	if(download_time == 0)  	{  		averageDownloadRate = 0;  	}  	else  	{ -		averageDownloadRate = (mTotalBytes * 8) / mTotalMilliseconds; +		averageDownloadRate = mRecording.getSum(sTextureDataDownloaded).valueAs<LLUnits::Bits>() / download_time.valueAs<LLUnits::Seconds>();  	} -	averagedTextureData["bits_per_second"] = averageDownloadRate; -	averagedTextureData["bytes_downloaded"] = mTotalBytes; -	averagedTextureData["texture_downloads_started"] = mTextureDownloadsStarted; -	averagedTextureData["texture_downloads_completed"] = mTextureDownloadsCompleted; -	averagedTextureData["transport"] = mTextureDownloadProtocol; +	averagedTextureData["bits_per_second"]             = averageDownloadRate; +	averagedTextureData["bytes_downloaded"]            = mRecording.getSum(sTextureDataDownloaded).valueAs<LLUnits::Bytes>(); +	averagedTextureData["texture_downloads_started"]   = mRecording.getSum(sTextureDownloadsStarted); +	averagedTextureData["texture_downloads_completed"] = mRecording.getSum(sTextureDownloadsCompleted); +	averagedTextureData["transport"]                   = mTextureDownloadProtocol;  	return averagedTextureData;  }  void LLTextureInfo::resetTextureStatistics()  { -	mTotalMilliseconds = 0; -	mTotalBytes = 0; -	mTextureDownloadsStarted = 0; -	mTextureDownloadsCompleted = 0; +	mRecording.restart();  	mTextureDownloadProtocol = "NONE";  	mCurrentStatsBundleStartTime = LLTimer::getTotalTime();  } -U32 LLTextureInfo::getRequestStartTime(const LLUUID& id) +LLUnit<U32, LLUnits::Microseconds> LLTextureInfo::getRequestStartTime(const LLUUID& id)  {  	if (!has(id))  	{ @@ -230,7 +232,7 @@ U32 LLTextureInfo::getRequestStartTime(const LLUUID& id)  	}  } -U32 LLTextureInfo::getRequestSize(const LLUUID& id) +LLUnit<U32, LLUnits::Bytes> LLTextureInfo::getRequestSize(const LLUUID& id)  {  	if (!has(id))  	{ @@ -269,7 +271,7 @@ LLTextureInfoDetails::LLRequestType LLTextureInfo::getRequestType(const LLUUID&  	}  } -U32 LLTextureInfo::getRequestCompleteTime(const LLUUID& id) +LLUnit<U32, LLUnits::Microseconds> LLTextureInfo::getRequestCompleteTime(const LLUUID& id)  {  	if (!has(id))  	{ diff --git a/indra/newview/lltextureinfo.h b/indra/newview/lltextureinfo.h index 2ccbcc5fd2..a861a12668 100755 --- a/indra/newview/lltextureinfo.h +++ b/indra/newview/lltextureinfo.h @@ -29,6 +29,7 @@  #include "lluuid.h"  #include "lltextureinfodetails.h" +#include "lltracerecording.h"  #include <map>  class LLTextureInfo @@ -37,18 +38,18 @@ public:  	LLTextureInfo();  	~LLTextureInfo(); -	void setUpLogging(bool writeToViewerLog, bool sendToSim, U32 textureLogThreshold); +	void setUpLogging(bool writeToViewerLog, bool sendToSim, LLUnit<U32, LLUnits::Bytes> textureLogThreshold);  	bool has(const LLUUID& id);  	void setRequestStartTime(const LLUUID& id, U64 startTime);  	void setRequestSize(const LLUUID& id, U32 size);  	void setRequestOffset(const LLUUID& id, U32 offset);  	void setRequestType(const LLUUID& id, LLTextureInfoDetails::LLRequestType type); -	void setRequestCompleteTimeAndLog(const LLUUID& id, U64 completeTime); -	U32 getRequestStartTime(const LLUUID& id); -	U32 getRequestSize(const LLUUID& id); +	void setRequestCompleteTimeAndLog(const LLUUID& id, LLUnit<U64, LLUnits::Microseconds> completeTime); +	LLUnit<U32, LLUnits::Microseconds>getRequestStartTime(const LLUUID& id); +	LLUnit<U32, LLUnits::Bytes> getRequestSize(const LLUUID& id);  	U32 getRequestOffset(const LLUUID& id);  	LLTextureInfoDetails::LLRequestType getRequestType(const LLUUID& id); -	U32 getRequestCompleteTime(const LLUUID& id); +	LLUnit<U32, LLUnits::Microseconds> getRequestCompleteTime(const LLUUID& id);  	void resetTextureStatistics();  	U32 getTextureInfoMapSize();  	LLSD getAverages(); @@ -56,19 +57,14 @@ public:  private:  	void addRequest(const LLUUID& id); -	std::map<LLUUID, LLTextureInfoDetails *> mTextures; - -	LLSD mAverages; - -	bool mLogTextureDownloadsToViewerLog; -	bool mLogTextureDownloadsToSimulator; -	S32 mTotalBytes; -	S32 mTotalMilliseconds; -	S32 mTextureDownloadsStarted; -	S32 mTextureDownloadsCompleted; -	std::string mTextureDownloadProtocol; -	U32 mTextureLogThreshold; // in bytes -	U64 mCurrentStatsBundleStartTime; +	std::map<LLUUID, LLTextureInfoDetails *>	mTextures; +	LLSD										mAverages; +	bool										mLogTextureDownloadsToViewerLog, +												mLogTextureDownloadsToSimulator; +	std::string									mTextureDownloadProtocol; +	LLUnit<U32, LLUnits::Bytes>					mTextureLogThreshold;  +	LLUnit<U64, LLUnits::Microseconds>			mCurrentStatsBundleStartTime; +	LLTrace::Recording							mRecording;  };  #endif // LL_LLTEXTUREINFO_H diff --git a/indra/newview/lltextureinfodetails.cpp b/indra/newview/lltextureinfodetails.cpp index 0d750db3bf..cab16eb922 100755 --- a/indra/newview/lltextureinfodetails.cpp +++ b/indra/newview/lltextureinfodetails.cpp @@ -28,7 +28,9 @@  #include "lltextureinfodetails.h" -LLTextureInfoDetails::LLTextureInfoDetails() : mStartTime(0), mCompleteTime(0), mSize(0), mType(REQUEST_TYPE_NONE), mOffset(0) +LLTextureInfoDetails::LLTextureInfoDetails()  +:	mType(REQUEST_TYPE_NONE),  +	mOffset(0)  {  } diff --git a/indra/newview/lltextureinfodetails.h b/indra/newview/lltextureinfodetails.h index 4a3cd29084..28e957a7df 100755 --- a/indra/newview/lltextureinfodetails.h +++ b/indra/newview/lltextureinfodetails.h @@ -28,10 +28,10 @@  #define LL_LLTEXTUREINFODETAILS_H  #include "lluuid.h" +#include "llunit.h" -class LLTextureInfoDetails +struct LLTextureInfoDetails  { -public:  	enum LLRequestType  	{  		REQUEST_TYPE_NONE, @@ -39,11 +39,11 @@ public:  		REQUEST_TYPE_UDP  	}; -	U32 mStartTime; -	U32 mCompleteTime; -	U32 mOffset; -	U32 mSize; -	LLRequestType mType; +	LLUnit<U32, LLUnits::Microseconds>	mStartTime, +										mCompleteTime; +	U32									mOffset; +	LLUnit<U32, LLUnits::Bytes>			mSize; +	LLRequestType						mType;  	LLTextureInfoDetails();  }; diff --git a/indra/newview/lltexturestats.cpp b/indra/newview/lltexturestats.cpp index f820ae65df..52fe78abf3 100755 --- a/indra/newview/lltexturestats.cpp +++ b/indra/newview/lltexturestats.cpp @@ -48,8 +48,7 @@ void send_texture_stats_to_sim(const LLSD &texture_stats)  	texture_stats_report["stats_data"] = texture_stats;  	std::string texture_cap_url = gAgent.getRegion()->getCapability("TextureStats"); -	LLTextureStatsUploader tsu;  	llinfos << "uploading texture stats data to simulator" << llendl; -	tsu.uploadStatsToSimulator(texture_cap_url, texture_stats); +	LLTextureStatsUploader::uploadStatsToSimulator(texture_cap_url, texture_stats);  } diff --git a/indra/newview/lltexturestatsuploader.cpp b/indra/newview/lltexturestatsuploader.cpp index 23ba09cb91..92ec63a113 100755 --- a/indra/newview/lltexturestatsuploader.cpp +++ b/indra/newview/lltexturestatsuploader.cpp @@ -30,14 +30,8 @@  #include "llhttpclient.h" -LLTextureStatsUploader::LLTextureStatsUploader() -{ -} - -LLTextureStatsUploader::~LLTextureStatsUploader() -{ -} +// static  void LLTextureStatsUploader::uploadStatsToSimulator(const std::string texture_cap_url, const LLSD &texture_stats)  {  	if ( texture_cap_url != "" ) diff --git a/indra/newview/lltexturestatsuploader.h b/indra/newview/lltexturestatsuploader.h index 6b02aeb845..ac268c2516 100755 --- a/indra/newview/lltexturestatsuploader.h +++ b/indra/newview/lltexturestatsuploader.h @@ -34,9 +34,7 @@  class LLTextureStatsUploader  {  public: -	LLTextureStatsUploader(); -	~LLTextureStatsUploader(); -	void uploadStatsToSimulator(const std::string texture_cap_url, const LLSD &texture_stats); +	static void uploadStatsToSimulator(const std::string texture_cap_url, const LLSD &texture_stats);  };  #endif // LL_LLTEXTURESTATSUPLOADER_H diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp index 6ab2aefc34..80412c215f 100755 --- a/indra/newview/llviewerassetstats.cpp +++ b/indra/newview/llviewerassetstats.cpp @@ -314,9 +314,9 @@ void LLViewerAssetStats::handleStop()  }  void LLViewerAssetStats::handleReset() -	{ +{  	reset(); -	} +}  void LLViewerAssetStats::reset() @@ -328,6 +328,7 @@ void LLViewerAssetStats::reset()  	if (mRegionHandle)  	{  		mCurRecording = &mRegionRecordings[mRegionHandle]; +		mCurRecording->setPlayState(getPlayState());  	}  } @@ -346,7 +347,7 @@ void LLViewerAssetStats::setRegion(region_handle_t region_handle)  	if (region_handle)  	{  		mCurRecording = &mRegionRecordings[region_handle]; -		mCurRecording->start(); +		mCurRecording->setPlayState(getPlayState());  	}  	mRegionHandle = region_handle; @@ -493,19 +494,19 @@ void LLViewerAssetStats::getStats(AssetStats& stats, bool compact_output)  }  LLSD LLViewerAssetStats::asLLSD(bool compact_output) -		{ +{  	LLParamSDParser parser;  	LLSD sd;  	AssetStats stats;  	getStats(stats, compact_output);  	LLInitParam::predicate_rule_t rule = LLInitParam::default_parse_rules();  	if (!compact_output) -		{ +	{  		rule.allow(LLInitParam::EMPTY); -		} +	}  	parser.writeSD(sd, stats, rule);  	return sd; -	} +}  // ------------------------------------------------------  // Global free-function definitions (LLViewerAssetStatsFF namespace) diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp index ebc4f09edb..57a0195d23 100755 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -155,7 +155,7 @@ void LLViewerCamera::updateCameraLocation(const LLVector3 ¢er,  	setOriginAndLookAt(origin, up_direction, point_of_interest); -	mVelocityDir = center - last_position ;  +	mVelocityDir = origin - last_position ;   	F32 dpos = mVelocityDir.normVec() ;  	LLQuaternion rotation;  	rotation.shortestArc(last_axis, getAtAxis()); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 1de8493749..ee5793fe6a 100755 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -106,6 +106,7 @@ LLFrameTimer gRecentMemoryTime;  void pre_show_depth_buffer();  void post_show_depth_buffer();  void render_ui(F32 zoom_factor = 1.f, int subfield = 0); +void swap();  void render_hud_attachments();  void render_ui_3d();  void render_ui_2d(); @@ -344,7 +345,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)  	// Bail out if we're in the startup state and don't want to try to  	// render the world.  	// -	if (LLStartUp::getStartupState() < STATE_STARTED) +	if (LLStartUp::getStartupState() < STATE_WEARABLES_WAIT)  	{  		LLAppViewer::instance()->pingMainloopTimeout("Display:Startup");  		display_startup(); @@ -553,6 +554,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)  	{  		LLAppViewer::instance()->pingMainloopTimeout("Display:Disconnected");  		render_ui(); +		swap();  	}  	////////////////////////// @@ -1021,6 +1023,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)  		{  			LLFastTimer t(FTM_RENDER_UI);  			render_ui(); +			swap();  		} @@ -1244,8 +1247,6 @@ BOOL setup_hud_matrices(const LLRect& screen_region)  	return TRUE;  } -static LLFastTimer::DeclareTimer FTM_SWAP("Swap"); -  void render_ui(F32 zoom_factor, int subfield)  {  	LLGLState::checkStates(); @@ -1322,10 +1323,16 @@ void render_ui(F32 zoom_factor, int subfield)  		glh_set_current_modelview(saved_view);  		gGL.popMatrix();  	} +} + +static LLFastTimer::DeclareTimer FTM_SWAP("Swap"); + +void swap() +{ +	LLFastTimer t(FTM_SWAP);  	if (gDisplaySwapBuffers)  	{ -		LLFastTimer t(FTM_SWAP);  		gViewerWindow->getWindow()->swapBuffers();  	}  	gDisplaySwapBuffers = TRUE; diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 3d4c75cec3..244c150b29 100755 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -291,9 +291,9 @@ F32		gAveLandCompression = 0.f,  		gWorstWaterCompression = 0.f;  LLUnit<U32, LLUnits::Bytes>		gTotalWorldData = 0,  -						gTotalObjectData = 0,  -						gTotalTextureData = 0; -U32						gSimPingCount = 0; +								gTotalObjectData = 0,  +								gTotalTextureData = 0; +U32								gSimPingCount = 0;  LLUnit<U32, LLUnits::Bits>		gObjectData = 0;  F32		gAvgSimPing = 0.f;  LLUnit<U32, LLUnits::Bytes>		gTotalTextureBytesPerBoostLevel[LLViewerTexture::MAX_GL_IMAGE_CATEGORY] = {0}; @@ -353,7 +353,7 @@ void update_statistics()  	}  	else  	{ -		sample(LLStatViewer::SIM_PING, LLUnit<F64, LLUnits::Seconds>(10)); +		sample(LLStatViewer::SIM_PING, LLUnits::Seconds::fromValue(10));  	}  	if (LLViewerStats::instance().getRecording().getSum(LLStatViewer::FPS)) @@ -403,7 +403,7 @@ void update_statistics()  		static LLFrameTimer texture_stats_timer;  		if (texture_stats_timer.getElapsedTimeF32() >= texture_stats_freq)  		{ -			gTotalTextureData = LLUnit<F64, LLUnits::Bytes>(LLViewerStats::instance().getRecording().getSum(LLStatViewer::TEXTURE_KBIT)); +			gTotalTextureData = LLViewerStats::instance().getRecording().getSum(LLStatViewer::TEXTURE_KBIT);  			texture_stats_timer.reset();  		}  	} diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index f077ae1fe1..0248298eb5 100755 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -35,7 +35,6 @@  //---------------------------------------------------------------------------  // Cache entries -class LLVOCacheEntry;  class LLCamera;  class LLVOCacheEntry : public LLViewerOctreeEntryData diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp index b9712e5e9c..bd42b59df2 100755 --- a/indra/newview/tests/llviewerassetstats_test.cpp +++ b/indra/newview/tests/llviewerassetstats_test.cpp @@ -35,6 +35,7 @@  #include "lluuid.h"  #include "llsdutil.h"  #include "llregionhandle.h" +#include "lltracethreadrecorder.h"  #include "../llvoavatar.h"  namespace LLStatViewer @@ -231,14 +232,15 @@ namespace tut  	{  		tst_viewerassetstats_index()  		{ -			LLTrace::init(); +			LLTrace::set_master_thread_recorder(&mThreadRecorder);  		}  		~tst_viewerassetstats_index()  		{ -			LLTrace::cleanup(); +			LLTrace::set_master_thread_recorder(NULL);  		} +		LLTrace::ThreadRecorder mThreadRecorder;  	};  	typedef test_group<tst_viewerassetstats_index> tst_viewerassetstats_index_t;  	typedef tst_viewerassetstats_index_t::object tst_viewerassetstats_index_object_t; diff --git a/indra/test/test.cpp b/indra/test/test.cpp index 28de88201c..10f71a2843 100755 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -41,6 +41,7 @@  #include "stringize.h"  #include "namedtempfile.h"  #include "lltrace.h" +#include "lltracethreadrecorder.h"  #include "apr_pools.h"  #include "apr_getopt.h" @@ -483,6 +484,8 @@ void wouldHaveCrashed(const std::string& message)  	tut::fail("llerrs message: " + message);  } +static LLTrace::ThreadRecorder* sMasterThreadRecorder = NULL; +  int main(int argc, char **argv)  {  	// The following line must be executed to initialize Google Mock @@ -515,7 +518,11 @@ int main(int argc, char **argv)  	ll_init_apr(); -	LLTrace::init(); +	if (!sMasterThreadRecorder) +	{ +		sMasterThreadRecorder = new LLTrace::ThreadRecorder(); +		LLTrace::set_master_thread_recorder(sMasterThreadRecorder); +	}  	apr_getopt_t* os = NULL;  	if(APR_SUCCESS != apr_getopt_init(&os, gAPRPoolp, argc, argv))  	{ | 
