From 62c8844414b84ee9e8cc488f4e02cbaed5f67a14 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Sun, 21 Apr 2013 23:10:03 -0700
Subject: SH-3931 WIP Interesting: Add graphs to visualize scene load metrics
 added ExtendablePeriodicRecording and ability to append periodic recordings
 to each other

---
 indra/llcommon/llinstancetracker.h  |  10 ++-
 indra/llcommon/lltracerecording.cpp | 136 ++++++++++++++++++++++++++++++++++++
 indra/llcommon/lltracerecording.h   |  28 +++++++-
 3 files changed, 170 insertions(+), 4 deletions(-)

(limited to 'indra/llcommon')

diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h
index 596bea548d..a79ddd088d 100644
--- a/indra/llcommon/llinstancetracker.h
+++ b/indra/llcommon/llinstancetracker.h
@@ -67,6 +67,7 @@ protected:
 /// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
 /// If KEY is not provided, then instances are stored in a simple set
 /// @NOTE: see explicit specialization below for default KEY==void case
+/// @NOTE: this class is not thread-safe unless used as read-only
 template<typename T, typename KEY = void>
 class LLInstanceTracker : public LLInstanceTrackerBase
 {
@@ -120,13 +121,13 @@ public:
 		typedef boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag> super_t;
 
 		key_iter(typename InstanceMap::iterator it)
-			:	mIterator(it)
+		:	mIterator(it)
 		{
 			getStatic().incrementDepth();
 		}
 
 		key_iter(const key_iter& other)
-			:	mIterator(other.mIterator)
+		:	mIterator(other.mIterator)
 		{
 			getStatic().incrementDepth();
 		}
@@ -171,7 +172,10 @@ public:
 		return instance_iter(getMap_().end());
 	}
 
-	static S32 instanceCount() { return getMap_().size(); }
+	static S32 instanceCount() 
+	{ 
+		return getMap_().size(); 
+	}
 
 	static key_iter beginKeys()
 	{
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
index 21156b4d61..2917c217d7 100644
--- a/indra/llcommon/lltracerecording.cpp
+++ b/indra/llcommon/lltracerecording.cpp
@@ -396,6 +396,76 @@ void PeriodicRecording::nextPeriod()
 	}
 }
 
+
+void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
+{
+	if (other.mRecordingPeriods.size() < 2) return;
+
+	EPlayState play_state = getPlayState();
+	pause();
+
+	EPlayState other_play_state = other.getPlayState();
+	other.pause();
+
+	if (mAutoResize)
+	{
+		// copy everything after current period of other recording to end of buffer
+		// this will only apply if other recording is using a fixed circular buffer
+		if (other.mCurPeriod < other.mRecordingPeriods.size() - 1)
+		{
+			std::copy(	other.mRecordingPeriods.begin() + other.mCurPeriod + 1,
+						other.mRecordingPeriods.end(),
+						std::back_inserter(mRecordingPeriods));
+		}
+
+		// copy everything from beginning of other recording's buffer up to, but not including
+		// current period
+		std::copy(	other.mRecordingPeriods.begin(),
+					other.mRecordingPeriods.begin() + other.mCurPeriod,
+					std::back_inserter(mRecordingPeriods));
+
+		mCurPeriod = mRecordingPeriods.size() - 1;
+	}
+	else
+	{
+		size_t num_to_copy = llmin(	mRecordingPeriods.size(), other.mRecordingPeriods.size() );
+		std::vector<Recording>::iterator src_it = other.mRecordingPeriods.begin() 
+													+ (	(other.mCurPeriod + 1)									// cur period
+															+ (other.mRecordingPeriods.size() - num_to_copy)	// minus room for copy
+														% other.mRecordingPeriods.size());
+		std::vector<Recording>::iterator dest_it = mRecordingPeriods.begin() + ((mCurPeriod + 1) % mRecordingPeriods.size());
+
+		for(S32 i = 0; i < num_to_copy; i++)
+		{
+			*dest_it = *src_it;
+
+			if (++src_it == other.mRecordingPeriods.end())
+			{
+				src_it = other.mRecordingPeriods.begin();
+			}
+
+			if (++dest_it == mRecordingPeriods.end())
+			{
+				dest_it = mRecordingPeriods.begin();
+			}
+		}
+		
+		mCurPeriod = (mCurPeriod + num_to_copy) % mRecordingPeriods.size();
+	}
+
+	// if copying from periodic recording that wasn't active advance our period to the next available one
+	// otherwise continue recording on top of the last period of data received from the other recording
+	if (other_play_state != STARTED)
+	{
+		nextPeriod();
+	}
+
+	setPlayState(play_state);
+	other.setPlayState(other_play_state);
+}
+
+
+
 void PeriodicRecording::start()
 {
 	getCurRecording().start();
@@ -503,6 +573,72 @@ void ExtendableRecording::splitFrom(ExtendableRecording& other)
 	mPotentialRecording.splitFrom(other.mPotentialRecording);
 }
 
+///////////////////////////////////////////////////////////////////////
+// ExtendablePeriodicRecording
+///////////////////////////////////////////////////////////////////////
+
+void ExtendablePeriodicRecording::extend()
+{
+	// stop recording to get latest data
+	mPotentialRecording.stop();
+	// push the data back to accepted recording
+	mAcceptedRecording.appendPeriodicRecording(mPotentialRecording);
+	// flush data, so we can start from scratch
+	mPotentialRecording.reset();
+	// go back to play state we were in initially
+	mPotentialRecording.setPlayState(getPlayState());
+}
+
+void ExtendablePeriodicRecording::start()
+{
+	LLStopWatchControlsMixin<ExtendablePeriodicRecording>::start();
+	mPotentialRecording.start();
+}
+
+void ExtendablePeriodicRecording::stop()
+{
+	LLStopWatchControlsMixin<ExtendablePeriodicRecording>::stop();
+	mPotentialRecording.stop();
+}
+
+void ExtendablePeriodicRecording::pause()
+{
+	LLStopWatchControlsMixin<ExtendablePeriodicRecording>::pause();
+	mPotentialRecording.pause();
+}
+
+void ExtendablePeriodicRecording::resume()
+{
+	LLStopWatchControlsMixin<ExtendablePeriodicRecording>::resume();
+	mPotentialRecording.resume();
+}
+
+void ExtendablePeriodicRecording::restart()
+{
+	LLStopWatchControlsMixin<ExtendablePeriodicRecording>::restart();
+	mAcceptedRecording.reset();
+	mPotentialRecording.restart();
+}
+
+void ExtendablePeriodicRecording::reset()
+{
+	LLStopWatchControlsMixin<ExtendablePeriodicRecording>::reset();
+	mAcceptedRecording.reset();
+	mPotentialRecording.reset();
+}
+
+void ExtendablePeriodicRecording::splitTo(ExtendablePeriodicRecording& other)
+{
+	LLStopWatchControlsMixin<ExtendablePeriodicRecording>::splitTo(other);
+	mPotentialRecording.splitTo(other.mPotentialRecording);
+}
+
+void ExtendablePeriodicRecording::splitFrom(ExtendablePeriodicRecording& other)
+{
+	LLStopWatchControlsMixin<ExtendablePeriodicRecording>::splitFrom(other);
+	mPotentialRecording.splitFrom(other.mPotentialRecording);
+}
+
 PeriodicRecording& get_frame_recording()
 {
 	static LLThreadLocalPointer<PeriodicRecording> sRecording(new PeriodicRecording(1000, PeriodicRecording::STARTED));
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h
index 7c4113dbf0..23b031b49b 100644
--- a/indra/llcommon/lltracerecording.h
+++ b/indra/llcommon/lltracerecording.h
@@ -254,6 +254,8 @@ namespace LLTrace
 		void nextPeriod();
 		U32 getNumPeriods() { return mRecordingPeriods.size(); }
 
+		void appendPeriodicRecording(PeriodicRecording& other);
+
 		Recording& getLastRecording()
 		{
 			U32 num_periods = mRecordingPeriods.size();
@@ -424,6 +426,7 @@ namespace LLTrace
 		void extend();
 
 		Recording& getAcceptedRecording() { return mAcceptedRecording; }
+		const Recording& getAcceptedRecording() const {return mAcceptedRecording;}
 
 		// implementation for LLStopWatchControlsMixin
 		/*virtual*/ void start();
@@ -435,11 +438,34 @@ namespace LLTrace
 		/*virtual*/ void splitTo(ExtendableRecording& other);
 		/*virtual*/ void splitFrom(ExtendableRecording& other);
 
-		const Recording& getAcceptedRecording() const {return mAcceptedRecording;}
 	private:
 		Recording mAcceptedRecording;
 		Recording mPotentialRecording;
 	};
+
+	class ExtendablePeriodicRecording
+	:	public LLStopWatchControlsMixin<ExtendablePeriodicRecording>
+	{
+	public:
+		void extend();
+
+		PeriodicRecording& getAcceptedRecording() { return mAcceptedRecording; }
+		const PeriodicRecording& getAcceptedRecording() const {return mAcceptedRecording;}
+
+		// implementation for LLStopWatchControlsMixin
+		/*virtual*/ void start();
+		/*virtual*/ void stop();
+		/*virtual*/ void pause();
+		/*virtual*/ void resume();
+		/*virtual*/ void restart();
+		/*virtual*/ void reset();
+		/*virtual*/ void splitTo(ExtendablePeriodicRecording& other);
+		/*virtual*/ void splitFrom(ExtendablePeriodicRecording& other);
+
+	private:
+		PeriodicRecording mAcceptedRecording;
+		PeriodicRecording mPotentialRecording;
+	};
 }
 
 #endif // LL_LLTRACERECORDING_H
-- 
cgit v1.2.3