From ae355188327515d53b9c15c27ed576829fce3668 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Thu, 30 May 2013 18:30:11 -0700
Subject: [PATCH] SH-3931 WIP Interesting: Add graphs to visualize scene load
 metrics fixed LLTrace::ExtendablePeriodicRecording::extend() to include *all*
 frame extensions gated SlaveThreadRecorder pushing to master based on master
 update rate reverted changes to LLThreadLocalSingletonPointer to not use
 offset-from-default trick

---
 indra/llcommon/llthreadlocalstorage.h    |  8 ++------
 indra/llcommon/lltrace.h                 | 21 +++++++++++---------
 indra/llcommon/lltracerecording.cpp      |  5 +++--
 indra/llcommon/lltracerecording.h        |  6 +++---
 indra/llcommon/lltracethreadrecorder.cpp | 25 +++++++++++++++++-------
 indra/llcommon/lltracethreadrecorder.h   | 14 ++++++++-----
 6 files changed, 47 insertions(+), 32 deletions(-)

diff --git a/indra/llcommon/llthreadlocalstorage.h b/indra/llcommon/llthreadlocalstorage.h
index 471784749bd..cc672481249 100644
--- a/indra/llcommon/llthreadlocalstorage.h
+++ b/indra/llcommon/llthreadlocalstorage.h
@@ -313,11 +313,6 @@ template<typename DERIVED_TYPE>
 class LLThreadLocalSingletonPointer
 {
 public:
-	void operator =(DERIVED_TYPE* value)
-	{
-		setInstance(value);
-	}
-    
 	LL_FORCE_INLINE static DERIVED_TYPE* getInstance()
 	{
 #if LL_DARWIN
@@ -328,7 +323,7 @@ class LLThreadLocalSingletonPointer
 #endif
 	}
 
-	LL_FORCE_INLINE static void setInstance(DERIVED_TYPE* instance)
+	static void setInstance(DERIVED_TYPE* instance)
 	{
 #if LL_DARWIN
         createTLSKey();
@@ -339,6 +334,7 @@ class LLThreadLocalSingletonPointer
 	}
 
 private:
+
 #if LL_WINDOWS
 	static __declspec(thread) DERIVED_TYPE* sInstance;
 #elif LL_LINUX
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index e950a119d3a..00bab536ff9 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -35,6 +35,7 @@
 #include "llunit.h"
 #include "llapr.h"
 #include "llthreadlocalstorage.h"
+#include "lltimer.h"
 
 #include <list>
 
@@ -75,7 +76,6 @@ void set_thread_recorder(class ThreadRecorder*);
 
 class MasterThreadRecorder& getUIThreadRecorder();
 
-// one per thread per type
 template<typename ACCUMULATOR>
 class AccumulatorBuffer : public LLRefCount
 {
@@ -104,9 +104,9 @@ class AccumulatorBuffer : public LLRefCount
 
 	~AccumulatorBuffer()
 	{
-		if (LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage)
+		if (isPrimary())
 		{
-			LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(getDefaultBuffer()->mStorage);
+			LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
 		}
 		delete[] mStorage;
 	}
@@ -169,7 +169,8 @@ class AccumulatorBuffer : public LLRefCount
 
 	LL_FORCE_INLINE static ACCUMULATOR* getPrimaryStorage() 
 	{ 
-		return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance(); 
+		ACCUMULATOR* accumulator = LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance();
+		return accumulator ? accumulator : sDefaultBuffer->mStorage;
 	}
 
 	// NOTE: this is not thread-safe.  We assume that slots are reserved in the main thread before any child threads are spawned
@@ -222,25 +223,27 @@ class AccumulatorBuffer : public LLRefCount
 
 	static self_t* getDefaultBuffer()
 	{
-		// 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
-		static self_t* sBuffer = new AccumulatorBuffer(StaticAllocationMarker());
 		static bool sInitialized = false;
 		if (!sInitialized)
 		{
-			sBuffer->resize(DEFAULT_ACCUMULATOR_BUFFER_SIZE);
+			// 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 sBuffer;
+		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;
 
 template<typename ACCUMULATOR>
 class TraceType 
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
index 5b0b74524f4..86cdca3e10d 100644
--- a/indra/llcommon/lltracerecording.cpp
+++ b/indra/llcommon/lltracerecording.cpp
@@ -490,8 +490,9 @@ void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
 	{
 		if (mAutoResize)
 		{
-			for (S32 other_index = (other.mCurPeriod + 2) % other_recording_count; 
-				other_index != other.mCurPeriod; 
+			for (S32 other_index = (other.mCurPeriod + 2) % other_recording_count,
+				end_index = (other.mCurPeriod + 1) % other_recording_count; 
+				other_index != end_index; 
 				other_index = (other_index + 1) % other_recording_count)
 			{
 				llassert(other.mRecordingPeriods[other_index].getDuration() != 0.f 
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h
index 19a4fae7376..aaeb32e891d 100644
--- a/indra/llcommon/lltracerecording.h
+++ b/indra/llcommon/lltracerecording.h
@@ -336,12 +336,12 @@ namespace LLTrace
 		}
 
 		template <typename T>
-		typename T getPeriodMin(const TraceType<SampleAccumulator<T> >& stat, size_t num_periods = U32_MAX) const
+		T getPeriodMin(const TraceType<SampleAccumulator<T> >& stat, size_t num_periods = U32_MAX) const
 		{
 			size_t total_periods = mRecordingPeriods.size();
 			num_periods = llmin(num_periods, total_periods);
 
-			typename T min_val = std::numeric_limits<T>::max();
+			T min_val = std::numeric_limits<T>::max();
 			for (S32 i = 1; i <= num_periods; i++)
 			{
 				S32 index = (mCurPeriod + total_periods - i) % total_periods;
@@ -351,7 +351,7 @@ namespace LLTrace
 		}
 		
 		template <typename T>
-		typename T getPeriodMin(const TraceType<EventAccumulator<T> >& stat, size_t num_periods = U32_MAX) const
+		T getPeriodMin(const TraceType<EventAccumulator<T> >& stat, size_t num_periods = U32_MAX) const
 		{
 			size_t total_periods = mRecordingPeriods.size();
 			num_periods = llmin(num_periods, total_periods);
diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp
index 75c7cb2ff17..89b5df1f942 100644
--- a/indra/llcommon/lltracethreadrecorder.cpp
+++ b/indra/llcommon/lltracethreadrecorder.cpp
@@ -202,14 +202,21 @@ SlaveThreadRecorder::~SlaveThreadRecorder()
 	mMasterRecorder.removeSlaveThread(this);
 }
 
-void SlaveThreadRecorder::pushToMaster()
+bool SlaveThreadRecorder::pushToMaster()
 {
-	mThreadRecording.stop();
+	if (mPushCount != mMasterRecorder.getPullCount())
 	{
-		LLMutexLock(mMasterRecorder.getSlaveListMutex());
-		mSharedData.appendFrom(mThreadRecording);
+		mThreadRecording.stop();
+		{
+			LLMutexLock(mMasterRecorder.getSlaveListMutex());
+			mSharedData.appendFrom(mThreadRecording);
+		}
+		mThreadRecording.start();
+
+		mPushCount = mMasterRecorder.getPullCount();
+		return true;
 	}
-	mThreadRecording.start();
+	return false;
 }
 
 void SlaveThreadRecorder::SharedData::appendFrom( const Recording& source )
@@ -264,6 +271,8 @@ void MasterThreadRecorder::pullFromSlaveThreads()
 		(*it)->mSharedData.mergeTo(target_recording_buffers);
 		(*it)->mSharedData.reset();
 	}
+
+	mPullCount++;
 }
 
 void MasterThreadRecorder::addSlaveThread( class SlaveThreadRecorder* child )
@@ -289,8 +298,10 @@ void MasterThreadRecorder::removeSlaveThread( class SlaveThreadRecorder* child )
 	}
 }
 
-void MasterThreadRecorder::pushToMaster()
-{}
+bool MasterThreadRecorder::pushToMaster()
+{
+	return false;
+}
 
 MasterThreadRecorder::MasterThreadRecorder()
 {}
diff --git a/indra/llcommon/lltracethreadrecorder.h b/indra/llcommon/lltracethreadrecorder.h
index 17a2d4a9a96..a044757e625 100644
--- a/indra/llcommon/lltracethreadrecorder.h
+++ b/indra/llcommon/lltracethreadrecorder.h
@@ -49,7 +49,7 @@ namespace LLTrace
 		void deactivate(Recording* recording);
 		active_recording_list_t::reverse_iterator bringUpToDate(Recording* recording);
 
-		virtual void pushToMaster() = 0;
+		virtual bool pushToMaster() = 0;
 
 		TimeBlockTreeNode* getTimeBlockTreeNode(S32 index);
 
@@ -80,19 +80,22 @@ namespace LLTrace
 		void addSlaveThread(class SlaveThreadRecorder* child);
 		void removeSlaveThread(class SlaveThreadRecorder* child);
 
-		/*virtual */ void pushToMaster();
+		/*virtual */ bool pushToMaster();
 
 		// call this periodically to gather stats data from slave threads
 		void pullFromSlaveThreads();
 
 		LLMutex* getSlaveListMutex() { return &mSlaveListMutex; }
 
+		U32	getPullCount() { return mPullCount; }
+
 	private:
 
 		typedef std::list<class SlaveThreadRecorder*> slave_thread_recorder_list_t;
 
-		slave_thread_recorder_list_t	mSlaveThreadRecorders;
-		LLMutex							mSlaveListMutex;
+		slave_thread_recorder_list_t	mSlaveThreadRecorders;	// list of slave thread recorders associated with this master
+		LLMutex							mSlaveListMutex;		// protects access to slave list
+		LLAtomicU32						mPullCount;				// number of times data has been pulled from slaves
 	};
 
 	class LL_COMMON_API SlaveThreadRecorder : public ThreadRecorder
@@ -102,7 +105,7 @@ namespace LLTrace
 		~SlaveThreadRecorder();
 
 		// call this periodically to gather stats data for master thread to consume
-		/*virtual*/ void pushToMaster();
+		/*virtual*/ bool pushToMaster();
 
 		MasterThreadRecorder* 	mMaster;
 
@@ -119,6 +122,7 @@ namespace LLTrace
 		};
 		SharedData				mSharedData;
 		MasterThreadRecorder&	mMasterRecorder;
+		U32						mPushCount;
 	};
 }
 
-- 
GitLab