From 808d3eff198d65e5a870abb670786935fc8356bd Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Thu, 27 Jun 2013 00:07:21 -0700
Subject: [PATCH] SH-4299 WIP: Interesting: High fps shown temporarily off
 scale in statistics console fixed some lltrace logic errors more consistent
 syncing of timestamps of sample values in recording stack selection of
 primary buffers was completely incorrect assignment of recordings got wrong
 play state due to implicit operator = defined in base class fixed asset stats
 only working up to the first send

---
 indra/llcommon/llfasttimer.h             |  7 ---
 indra/llcommon/lltraceaccumulators.cpp   | 15 ++++++-
 indra/llcommon/lltraceaccumulators.h     | 37 ++++++++++-----
 indra/llcommon/lltracerecording.cpp      |  7 ++-
 indra/llcommon/lltracerecording.h        |  6 +++
 indra/llcommon/lltracethreadrecorder.cpp | 57 +++++++++++++++---------
 indra/llcommon/lltracethreadrecorder.h   |  2 +-
 indra/newview/llappviewer.cpp            |  4 +-
 indra/newview/llviewerassetstats.cpp     | 15 ++++---
 9 files changed, 95 insertions(+), 55 deletions(-)

diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 642c99ccce1..ab8612a8ade 100755
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -38,13 +38,6 @@ class LLMutex;
 namespace LLTrace
 {
 
-struct BlockTimerStackRecord
-{
-	class BlockTimer*	mActiveTimer;
-	class TimeBlock*	mTimeBlock;
-	U64					mChildTime;
-};
-
 class ThreadTimerStack 
 :	public BlockTimerStackRecord, 
 	public LLThreadLocalSingleton<ThreadTimerStack>
diff --git a/indra/llcommon/lltraceaccumulators.cpp b/indra/llcommon/lltraceaccumulators.cpp
index 59486964182..950c1d97d11 100644
--- a/indra/llcommon/lltraceaccumulators.cpp
+++ b/indra/llcommon/lltraceaccumulators.cpp
@@ -69,6 +69,16 @@ void AccumulatorBufferGroup::makePrimary()
 	}
 }
 
+//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();
@@ -102,11 +112,12 @@ void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other)
 	mMemStats.reset(other ? &other->mMemStats : NULL);
 }
 
-void AccumulatorBufferGroup::flush()
+void AccumulatorBufferGroup::sync()
 {
 	LLUnitImplicit<F64, LLUnits::Seconds> time_stamp = LLTimer::getTotalSeconds();
 
-	mSamples.flush(time_stamp);
+	mSamples.sync(time_stamp);
+	mMemStats.sync(time_stamp);
 }
 
 }
diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h
index 7994dcc217a..825cc9e3a8e 100644
--- a/indra/llcommon/lltraceaccumulators.h
+++ b/indra/llcommon/lltraceaccumulators.h
@@ -109,12 +109,12 @@ namespace LLTrace
 			}
 		}
 
-		void flush(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp)
+		void sync(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp)
 		{
 			llassert(mStorageSize >= sNextStorageSlot);
 			for (size_t i = 0; i < sNextStorageSlot; i++)
 			{
-				mStorage[i].flush(time_stamp);
+				mStorage[i].sync(time_stamp);
 			}
 		}
 
@@ -128,6 +128,11 @@ namespace LLTrace
 			return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage;
 		}
 
+		static void clearPrimary()
+		{
+			LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
+		}
+
 		LL_FORCE_INLINE static ACCUMULATOR* getPrimaryStorage() 
 		{ 
 			ACCUMULATOR* accumulator = LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance();
@@ -302,7 +307,7 @@ namespace LLTrace
 			mLastValue = other ? other->mLastValue : 0;
 		}
 
-		void flush(LLUnitImplicit<F64, LLUnits::Seconds>) {}
+		void sync(LLUnitImplicit<F64, LLUnits::Seconds>) {}
 
 		F64	getSum() const { return mSum; }
 		F64	getMin() const { return mMin; }
@@ -434,7 +439,7 @@ namespace LLTrace
 			mHasValue = other ? other->mHasValue : false;
 		}
 
-		void flush(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp)
+		void sync(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp)
 		{
 			LLUnitImplicit<F64, LLUnits::Seconds> delta_time = time_stamp - mLastSampleTimeStamp;
 
@@ -500,7 +505,7 @@ namespace LLTrace
 			mSum = 0;
 		}
 
-		void flush(LLUnitImplicit<F64, LLUnits::Seconds>) {}
+		void sync(LLUnitImplicit<F64, LLUnits::Seconds>) {}
 
 		F64	getSum() const { return mSum; }
 
@@ -535,7 +540,7 @@ namespace LLTrace
 		TimeBlockAccumulator();
 		void addSamples(const self_t& other, bool /*append*/);
 		void reset(const self_t* other);
-		void flush(LLUnitImplicit<F64, LLUnits::Seconds>) {}
+		void sync(LLUnitImplicit<F64, LLUnits::Seconds>) {}
 
 		//
 		// members
@@ -566,6 +571,13 @@ namespace LLTrace
 		bool						mCollapsed;
 		bool						mNeedsSorting;
 	};
+	
+	struct BlockTimerStackRecord
+	{
+		class BlockTimer*	mActiveTimer;
+		class TimeBlock*	mTimeBlock;
+		U64					mChildTime;
+	};
 
 	struct MemStatAccumulator
 	{
@@ -611,16 +623,16 @@ namespace LLTrace
 			mDeallocatedCount = 0;
 		}
 
-		void flush(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp) 
+		void sync(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp) 
 		{
-			mSize.flush(time_stamp);
-			mChildSize.flush(time_stamp);
+			mSize.sync(time_stamp);
+			mChildSize.sync(time_stamp);
 		}
 
 		SampleAccumulator	mSize,
-			mChildSize;
+							mChildSize;
 		int					mAllocatedCount,
-			mDeallocatedCount;
+							mDeallocatedCount;
 	};
 
 	struct AccumulatorBufferGroup : public LLRefCount
@@ -630,11 +642,12 @@ namespace LLTrace
 		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 flush();
+		void sync();
 
 		AccumulatorBuffer<CountAccumulator>	 			mCounts;
 		AccumulatorBuffer<SampleAccumulator>			mSamples;
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
index c30f204fa46..0938317eaaa 100644
--- a/indra/llcommon/lltracerecording.cpp
+++ b/indra/llcommon/lltracerecording.cpp
@@ -59,11 +59,12 @@ Recording& Recording::operator = (const Recording& other)
 
 	mBuffers = other.mBuffers;
 
-	LLStopWatchControlsMixin<Recording>::setPlayState(other_play_state);
-
 	// 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;
 }
 
@@ -82,7 +83,6 @@ void Recording::update()
 	{
 		mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
 		AccumulatorBufferGroup* buffers = mBuffers.write();
-		buffers->flush();
 		LLTrace::get_thread_recorder()->bringUpToDate(buffers);
 
 		mSamplingTimer.reset();
@@ -107,7 +107,6 @@ void Recording::handleStop()
 {
 	mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
 	AccumulatorBufferGroup* buffers = mBuffers.write();
-	buffers->flush();
 	LLTrace::get_thread_recorder()->deactivate(buffers);
 }
 
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h
index 38eaa47f9f9..355dbabb1c1 100644
--- a/indra/llcommon/lltracerecording.h
+++ b/indra/llcommon/lltracerecording.h
@@ -81,6 +81,7 @@ class LLStopWatchControlsMixin
 :	public LLStopWatchControlsMixinCommon
 {
 public:
+
 	typedef LLStopWatchControlsMixin<DERIVED> self_t;
 	virtual void splitTo(DERIVED& other)
 	{
@@ -98,6 +99,11 @@ class LLStopWatchControlsMixin
 		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) {};
diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp
index c571e013e19..7192564c948 100644
--- a/indra/llcommon/lltracethreadrecorder.cpp
+++ b/indra/llcommon/lltracethreadrecorder.cpp
@@ -87,7 +87,7 @@ ThreadRecorder::~ThreadRecorder()
 	delete[] mTimeBlockTreeNodes;
 }
 
-TimeBlockTreeNode* ThreadRecorder::getTimeBlockTreeNode(S32 index)
+TimeBlockTreeNode* ThreadRecorder::getTimeBlockTreeNode( S32 index )
 {
 	if (0 <= index && index < mNumTimeBlockTreeNodes)
 	{
@@ -99,10 +99,20 @@ TimeBlockTreeNode* ThreadRecorder::getTimeBlockTreeNode(S32 index)
 
 void ThreadRecorder::activate( AccumulatorBufferGroup* recording )
 {
+	active_recording_list_t::reverse_iterator it, end_it;
+	for (it = mActiveRecordings.rbegin(), end_it = mActiveRecordings.rend();
+		it != end_it;
+		++it)
+	{
+		llassert((*it)->mTargetRecording != 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);
 
@@ -113,7 +123,7 @@ ThreadRecorder::active_recording_list_t::reverse_iterator ThreadRecorder::bringU
 {
 	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;
@@ -156,18 +166,22 @@ 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();
+			}
+		}
 	}
 }
 
@@ -202,7 +216,6 @@ SlaveThreadRecorder::~SlaveThreadRecorder()
 void SlaveThreadRecorder::pushToMaster()
 { 
 	{ LLMutexLock lock(&mSharedRecordingMutex);	
-		mThreadRecordingBuffers.flush();
 		LLTrace::get_thread_recorder()->bringUpToDate(&mThreadRecordingBuffers);
 		mSharedRecordingBuffers.append(mThreadRecordingBuffers);
 	}
@@ -213,23 +226,25 @@ void SlaveThreadRecorder::pushToMaster()
 ///////////////////////////////////////////////////////////////////////
 
 static LLFastTimer::DeclareTimer FTM_PULL_TRACE_DATA_FROM_SLAVES("Pull slave trace data");
+
 void MasterThreadRecorder::pullFromSlaveThreads()
 {
-	LLFastTimer _(FTM_PULL_TRACE_DATA_FROM_SLAVES);
+	/*LLFastTimer _(FTM_PULL_TRACE_DATA_FROM_SLAVES);
 	if (mActiveRecordings.empty()) return;
 
 	{ LLMutexLock lock(&mSlaveListMutex);
 
-		AccumulatorBufferGroup& target_recording_buffers = mActiveRecordings.back()->mPartialRecording;
-		for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end();
-			it != end_it;
-			++it)
-		{ LLMutexLock lock(&(*it)->mSharedRecordingMutex);
+	AccumulatorBufferGroup& target_recording_buffers = mActiveRecordings.back()->mPartialRecording;
+	target_recording_buffers.sync();
+	for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end();
+	it != end_it;
+	++it)
+	{ LLMutexLock lock(&(*it)->mSharedRecordingMutex);
 
-			target_recording_buffers.merge((*it)->mSharedRecordingBuffers);
-			(*it)->mSharedRecordingBuffers.reset();
-		}
+	target_recording_buffers.merge((*it)->mSharedRecordingBuffers);
+	(*it)->mSharedRecordingBuffers.reset();
 	}
+	}*/
 }
 
 // called by slave thread
diff --git a/indra/llcommon/lltracethreadrecorder.h b/indra/llcommon/lltracethreadrecorder.h
index 0680c2c590f..6b7a8e5865e 100644
--- a/indra/llcommon/lltracethreadrecorder.h
+++ b/indra/llcommon/lltracethreadrecorder.h
@@ -71,6 +71,7 @@ namespace LLTrace
 		class BlockTimer*			mRootTimer;
 		TimeBlockTreeNode*			mTimeBlockTreeNodes;
 		size_t						mNumTimeBlockTreeNodes;
+		BlockTimerStackRecord		mBlockTimerStackRecord;
 	};
 
 	class LL_COMMON_API MasterThreadRecorder : public ThreadRecorder
@@ -105,7 +106,6 @@ namespace LLTrace
 
 	private:
 		friend class MasterThreadRecorder;
-		MasterThreadRecorder* 	mMaster;
 		LLMutex					mSharedRecordingMutex;
 		AccumulatorBufferGroup	mSharedRecordingBuffers;
 		MasterThreadRecorder&	mMasterRecorder;
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 733c9cc9df8..7c5cd520dad 100755
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1294,6 +1294,8 @@ bool LLAppViewer::mainLoop()
 	{
 		LLFastTimer _(FTM_FRAME);
 		LLTrace::TimeBlock::processTimes();
+		llassert((LLTrace::get_frame_recording().getCurRecording().update(), 
+				LLTrace::get_frame_recording().getCurRecording().getSampleCount(LLStatViewer::FPS) <= 1));
 		LLTrace::get_frame_recording().nextPeriod();
 		LLTrace::TimeBlock::logStats();
 
@@ -5617,6 +5619,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/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp
index bada565d3d2..af82b61dc8d 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)
-- 
GitLab