diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index a6334e176b376f7b8117da8934ff9444448d2da8..0c618a2f4bfe00e429470d7fc3fffd506122bc05 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -101,16 +101,6 @@ namespace LLTrace
 			}
 		}
 
-		void addDeltas(const AccumulatorBuffer<ACCUMULATOR>& start, const AccumulatorBuffer<ACCUMULATOR>& finish)
-		{
-			llassert(mNextStorageSlot == start.mNextStorageSlot && mNextStorageSlot == finish.mNextStorageSlot);
-
-			for (size_t i = 0; i < mNextStorageSlot; i++)
-			{
-				mStorage[i].addDeltas(start.mStorage[i], finish.mStorage[i]);
-			}
-		}
-
 		void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other)
 		{
 			for (size_t i = 0; i < mNextStorageSlot; i++)
@@ -203,11 +193,12 @@ namespace LLTrace
 	public:
 		MeasurementAccumulator()
 		:	mSum(0),
-			mMin(0),
-			mMax(0),
+			mMin(std::numeric_limits<T>::max()),
+			mMax(std::numeric_limits<T>::min()),
 			mMean(0),
 			mVarianceSum(0),
-			mNumSamples(0)
+			mNumSamples(0),
+			mLastValue(0)
 		{}
 
 		LL_FORCE_INLINE void sample(T value)
@@ -251,20 +242,27 @@ namespace LLTrace
 				sd_2 = other.getStandardDeviation();
 			// 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
-			mVarianceSum =  (F32)mNumSamples
+			if (n_1 == 0)
+			{
+				mVarianceSum = other.mVarianceSum;
+			}
+			else if (n_2 == 0)
+			{
+				// don't touch variance
+				// mVarianceSum = mVarianceSum;
+			}
+			else
+			{
+				mVarianceSum =  (F32)mNumSamples
 							* ((((n_1 - 1.f) * sd_1 * sd_1)
 								+ ((n_2 - 1.f) * sd_2 * sd_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));
+			}
 			mLastValue = other.mLastValue;
 		}
 
-		void addDeltas(const MeasurementAccumulator<T>& start, const MeasurementAccumulator<T>& finish)
-		{
-			llerrs << "Delta merge invalid for measurement accumulators" << llendl;
-		}
-
 		void reset()
 		{
 			mNumSamples = 0;
@@ -313,12 +311,6 @@ namespace LLTrace
 			mNumSamples += other.mNumSamples;
 		}
 
-		void addDeltas(const RateAccumulator<T>& start, const RateAccumulator<T>& finish)
-		{
-			mSum += finish.mSum - start.mSum;
-			mNumSamples += finish.mNumSamples - start.mNumSamples;
-		}
-
 		void reset()
 		{
 			mNumSamples = 0;
@@ -464,13 +456,6 @@ namespace LLTrace
 			mCalls += other.mCalls;
 		}
 
-		void addDeltas(const TimerAccumulator& start, const TimerAccumulator& finish)
-		{
-			mTotalTimeCounter += finish.mTotalTimeCounter - start.mTotalTimeCounter;
-			mChildTimeCounter += finish.mChildTimeCounter - start.mChildTimeCounter;
-			mCalls += finish.mCalls - start.mCalls;
-		}
-
 		void reset()
 		{
 			mTotalTimeCounter = 0;
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
index 08839303190125171b0366cdd463f030f4493208..5d7b231b7de4109097951f27fafad8e02fd8e9c8 100644
--- a/indra/llcommon/lltracerecording.cpp
+++ b/indra/llcommon/lltracerecording.cpp
@@ -68,16 +68,16 @@ void Recording::handleReset()
 }
 
 void Recording::handleStart()
-	{
-		mSamplingTimer.reset();
-		LLTrace::get_thread_recorder()->activate(this);
+{
+	mSamplingTimer.reset();
+	LLTrace::get_thread_recorder()->activate(this);
 }
 
 void Recording::handleStop()
-	{
-		mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
-		LLTrace::get_thread_recorder()->deactivate(this);
-	}
+{
+	mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
+	LLTrace::get_thread_recorder()->deactivate(this);
+}
 
 void Recording::handleSplitTo(Recording& other)
 {
@@ -105,10 +105,204 @@ void Recording::mergeRecording( const Recording& other )
 	mStackTimers.write()->addSamples(*other.mStackTimers);
 }
 
-void Recording::mergeRecordingDelta(const Recording& baseline, const Recording& target)
+///////////////////////////////////////////////////////////////////////
+// Recording
+///////////////////////////////////////////////////////////////////////
+
+PeriodicRecording::PeriodicRecording( S32 num_periods ) 
+:	mNumPeriods(num_periods),
+	mCurPeriod(0),
+	mTotalValid(false),
+	mRecordingPeriods( new Recording[num_periods])
+{
+	llassert(mNumPeriods > 0);
+}
+
+PeriodicRecording::~PeriodicRecording()
+{
+	delete[] mRecordingPeriods;
+}
+
+
+void PeriodicRecording::nextPeriod()
+{
+	EPlayState play_state = getPlayState();
+	getCurRecordingPeriod().stop();
+	mCurPeriod = (mCurPeriod + 1) % mNumPeriods;
+	switch(play_state)
+	{
+	case STOPPED:
+		break;
+	case PAUSED:
+		getCurRecordingPeriod().pause();
+		break;
+	case STARTED:
+		getCurRecordingPeriod().start();
+		break;
+	}
+	// new period, need to recalculate total
+	mTotalValid = false;
+}
+
+Recording& PeriodicRecording::getTotalRecording()
+{
+	if (!mTotalValid)
+	{
+		mTotalRecording.reset();
+		for (S32 i = (mCurPeriod + 1) % mNumPeriods; i < mCurPeriod; i++)
+		{
+			mTotalRecording.mergeRecording(mRecordingPeriods[i]);
+		}
+	}
+	mTotalValid = true;
+	return mTotalRecording;
+}
+
+void PeriodicRecording::handleStart()
+{
+	getCurRecordingPeriod().handleStart();
+}
+
+void PeriodicRecording::handleStop()
+{
+	getCurRecordingPeriod().handleStop();
+}
+
+void PeriodicRecording::handleReset()
+{
+	getCurRecordingPeriod().handleReset();
+}
+
+void PeriodicRecording::handleSplitTo( PeriodicRecording& other )
+{
+	getCurRecordingPeriod().handleSplitTo(other.getCurRecordingPeriod());
+}
+
+///////////////////////////////////////////////////////////////////////
+// ExtendableRecording
+///////////////////////////////////////////////////////////////////////
+
+void ExtendableRecording::extend()
 {
-	mRates.write()->addDeltas(*baseline.mRates, *target.mRates);
-	mStackTimers.write()->addDeltas(*baseline.mStackTimers, *target.mStackTimers);
+	mAcceptedRecording.mergeRecording(mPotentialRecording);
+	mPotentialRecording.reset();
 }
 
+void ExtendableRecording::handleStart()
+{
+	mPotentialRecording.handleStart();
+}
+
+void ExtendableRecording::handleStop()
+{
+	mPotentialRecording.handleStop();
+}
+
+void ExtendableRecording::handleReset()
+{
+	mAcceptedRecording.handleReset();
+	mPotentialRecording.handleReset();
+}
+
+void ExtendableRecording::handleSplitTo( ExtendableRecording& other )
+{
+	mPotentialRecording.handleSplitTo(other.mPotentialRecording);
+}
+
+PeriodicRecording& get_frame_recording()
+{
+	static PeriodicRecording sRecording(64);
+	sRecording.start();
+	return sRecording;
+}
+
+}
+
+void LLVCRControlsMixinCommon::start()
+{
+	switch (mPlayState)
+	{
+	case STOPPED:
+		handleReset();
+		handleStart();
+		break;
+	case PAUSED:
+		handleStart();
+		break;
+	case STARTED:
+		handleReset();
+		break;
+	}
+	mPlayState = STARTED;
+}
+
+void LLVCRControlsMixinCommon::stop()
+{
+	switch (mPlayState)
+	{
+	case STOPPED:
+		break;
+	case PAUSED:
+		handleStop();
+		break;
+	case STARTED:
+		handleStop();
+		break;
+	}
+	mPlayState = STOPPED;
+}
+
+void LLVCRControlsMixinCommon::pause()
+{
+	switch (mPlayState)
+	{
+	case STOPPED:
+		break;
+	case PAUSED:
+		break;
+	case STARTED:
+		handleStop();
+		break;
+	}
+	mPlayState = PAUSED;
+}
+
+void LLVCRControlsMixinCommon::resume()
+{
+	switch (mPlayState)
+	{
+	case STOPPED:
+		handleStart();
+		break;
+	case PAUSED:
+		handleStart();
+		break;
+	case STARTED:
+		break;
+	}
+	mPlayState = STARTED;
+}
+
+void LLVCRControlsMixinCommon::restart()
+{
+	switch (mPlayState)
+	{
+	case STOPPED:
+		handleReset();
+		handleStart();
+		break;
+	case PAUSED:
+		handleReset();
+		handleStart();
+		break;
+	case STARTED:
+		handleReset();
+		break;
+	}
+	mPlayState = STARTED;
+}
+
+void LLVCRControlsMixinCommon::reset()
+{
+	handleReset();
 }
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h
index 0a1a02fa02199ab463746ebe7e7b28ad1132d9c2..924a7bffd5a79df204b1f541ea23a2fc743babe9 100644
--- a/indra/llcommon/lltracerecording.h
+++ b/indra/llcommon/lltracerecording.h
@@ -34,27 +34,11 @@
 #include "lltimer.h"
 #include "lltrace.h"
 
-template<typename DERIVED>
-class LL_COMMON_API LLVCRControlsMixinInterface
+class LL_COMMON_API LLVCRControlsMixinCommon
 {
 public:
-	virtual ~LLVCRControlsMixinInterface() {}
-	// trigger data accumulation (without reset)
-	virtual void handleStart() = 0;
-	// stop data accumulation, should put object in queryable state
-	virtual void handleStop() = 0;
-	// clear accumulated values, can be called while started
-	virtual void handleReset() = 0;
-	// atomically stop this object while starting the other
-	// no data can be missed in between stop and start
-	virtual void handleSplitTo(DERIVED& other) = 0;
-};
+	virtual ~LLVCRControlsMixinCommon() {}
 
-template<typename DERIVED>
-class LL_COMMON_API LLVCRControlsMixin
-:	private LLVCRControlsMixinInterface<DERIVED>
-{
-public:
 	enum EPlayState
 	{
 		STOPPED,
@@ -62,94 +46,39 @@ class LL_COMMON_API LLVCRControlsMixin
 		STARTED
 	};
 
-	void start()
-	{
-		switch (mPlayState)
-		{
-		case STOPPED:
-			handleReset();
-			handleStart();
-			break;
-		case PAUSED:
-			handleStart();
-			break;
-		case STARTED:
-			handleReset();
-			break;
-		}
-		mPlayState = STARTED;
-	}
+	void start();
+	void stop();
+	void pause();
+	void resume();
+	void restart();
+	void reset();
 
-	void stop()
-	{
-		switch (mPlayState)
-		{
-		case STOPPED:
-			break;
-		case PAUSED:
-			handleStop();
-			break;
-		case STARTED:
-			break;
-		}
-		mPlayState = STOPPED;
-	}
-
-	void pause()
-	{
-		switch (mPlayState)
-		{
-		case STOPPED:
-			break;
-		case PAUSED:
-			break;
-		case STARTED:
-			handleStop();
-			break;
-		}
-		mPlayState = PAUSED;
-	}
+	bool isStarted() { return mPlayState == STARTED; }
+	bool isPaused()  { return mPlayState == PAUSED; }
+	bool isStopped() { return mPlayState == STOPPED; }
+	EPlayState getPlayState() { return mPlayState; }
 
-	void resume()
-	{
-		switch (mPlayState)
-		{
-		case STOPPED:
-			handleStart();
-			break;
-		case PAUSED:
-			handleStart();
-			break;
-		case STARTED:
-			break;
-		}
-		mPlayState = STARTED;
-	}
+protected:
+	LLVCRControlsMixinCommon()
+	:	mPlayState(STOPPED)
+	{}
 
-	void restart()
-	{
-		switch (mPlayState)
-		{
-		case STOPPED:
-			handleReset();
-			handleStart();
-			break;
-		case PAUSED:
-			handleReset();
-			handleStart();
-			break;
-		case STARTED:
-			handleReset();
-			break;
-		}
-		mPlayState = STARTED;
-	}
+private:
+	// trigger data accumulation (without reset)
+	virtual void handleStart() = 0;
+	// stop data accumulation, should put object in queryable state
+	virtual void handleStop() = 0;
+	// clear accumulated values, can be called while started
+	virtual void handleReset() = 0;
 
-	void reset()
-	{
-		handleReset();
-	}
+	EPlayState mPlayState;
+};
 
+template<typename DERIVED>
+class LLVCRControlsMixin
+:	public LLVCRControlsMixinCommon
+{
+public:
 	void splitTo(DERIVED& other)
 	{
 		onSplitTo(other);
@@ -159,32 +88,15 @@ class LL_COMMON_API LLVCRControlsMixin
 	{
 		other.onSplitTo(*this);
 	}
-
-	bool isStarted() { return mPlayState == STARTED; }
-	bool isPaused()  { return mPlayState == PAUSED; }
-	bool isStopped() { return mPlayState == STOPPED; }
-	EPlayState getPlayState() { return mPlayState; }
-
-protected:
-
-	LLVCRControlsMixin()
-	:	mPlayState(STOPPED)
-	{}
-
 private:
-	EPlayState mPlayState;
+	// atomically stop this object while starting the other
+	// no data can be missed in between stop and start
+	virtual void handleSplitTo(DERIVED& other) = 0;
+
 };
 
 namespace LLTrace
 {
-	//template<typename T, typename IS_UNIT> class Rate;
-	//template<typename T, typename IS_UNIT> class Measurement;
-	//template<typename T> class Count;
-	//template<typename T> class AccumulatorBuffer;
-	//template<typename T> class RateAccumulator;
-	//template<typename T> class MeasurementAccumulator;
-	//class TimerAccumulator;
-
 	class LL_COMMON_API Recording : public LLVCRControlsMixin<Recording>
 	{
 	public:
@@ -196,7 +108,6 @@ namespace LLTrace
 		bool isPrimary() const;
 
 		void mergeRecording(const Recording& other);
-		void mergeRecordingDelta(const Recording& baseline, const Recording& target);
 
 		void update();
 
@@ -308,15 +219,13 @@ namespace LLTrace
 
 		F64 getSampleTime() const { return mElapsedSeconds; }
 
-	private:
-		friend class PeriodicRecording;
 		// implementation for LLVCRControlsMixin
 		/*virtual*/ void handleStart();
 		/*virtual*/ void handleStop();
 		/*virtual*/ void handleReset();
 		/*virtual*/ void handleSplitTo(Recording& other);
 
-
+	private:
 		friend class ThreadRecorder;
 		// returns data for current thread
 		class ThreadRecorder* getThreadRecorder(); 
@@ -333,38 +242,19 @@ namespace LLTrace
 	:	public LLVCRControlsMixin<PeriodicRecording>
 	{
 	public:
-		PeriodicRecording(S32 num_periods)
-		:	mNumPeriods(num_periods),
-			mCurPeriod(0),
-			mTotalValid(false),
-			mRecordingPeriods(new Recording[num_periods])
-	{
-			llassert(mNumPeriods > 0);
-		}
+		PeriodicRecording(S32 num_periods);
+		~PeriodicRecording();
+
+		void nextPeriod();
 
-		~PeriodicRecording()
+		Recording& getLastRecordingPeriod()
 		{
-			delete[] mRecordingPeriods;
+			return mRecordingPeriods[(mCurPeriod + mNumPeriods - 1) % mNumPeriods];
 		}
 
-		void nextPeriod()
+		const Recording& getLastRecordingPeriod() const
 		{
-			EPlayState play_state = getPlayState();
-			getCurRecordingPeriod().stop();
-			mCurPeriod = (mCurPeriod + 1) % mNumPeriods;
-			switch(play_state)
-			{
-			case STOPPED:
-				break;
-			case PAUSED:
-				getCurRecordingPeriod().pause();
-				break;
-			case STARTED:
-				getCurRecordingPeriod().start();
-				break;
-			}
-			// new period, need to recalculate total
-			mTotalValid = false;
+			return mRecordingPeriods[(mCurPeriod + mNumPeriods - 1) % mNumPeriods];
 		}
 
 		Recording& getCurRecordingPeriod()
@@ -377,41 +267,16 @@ namespace LLTrace
 			return mRecordingPeriods[mCurPeriod];
 		}
 
-		Recording& getTotalRecording()
-		{
-			if (!mTotalValid)
-			{
-				mTotalRecording.reset();
-				for (S32 i = (mCurPeriod + 1) % mNumPeriods; i < mCurPeriod; i++)
-				{
-					mTotalRecording.mergeRecording(mRecordingPeriods[i]);
-				}
-			}
-			mTotalValid = true;
-			return mTotalRecording;
-		}
+		Recording& getTotalRecording();
 
 	private:
-		// implementation for LLVCRControlsMixin
-		/*virtual*/ void handleStart()
-		{
-			getCurRecordingPeriod().handleStart();
-		}
-
-		/*virtual*/ void handleStop()
-		{
-			getCurRecordingPeriod().handleStop();
-		}
 
-		/*virtual*/ void handleReset()
-		{
-			getCurRecordingPeriod().handleReset();
-		}
+		// implementation for LLVCRControlsMixin
+		/*virtual*/ void handleStart();
+		/*virtual*/ void handleStop();
+		/*virtual*/ void handleReset();
 
-		/*virtual*/ void handleSplitTo(PeriodicRecording& other)
-		{
-			getCurRecordingPeriod().handleSplitTo(other.getCurRecordingPeriod());
-		}
+		/*virtual*/ void handleSplitTo(PeriodicRecording& other);
 
 		Recording*	mRecordingPeriods;
 		Recording	mTotalRecording;
@@ -419,6 +284,24 @@ namespace LLTrace
 		S32			mNumPeriods,
 					mCurPeriod;
 	};
+
+	PeriodicRecording& get_frame_recording();
+
+	class ExtendableRecording
+	:	public LLVCRControlsMixin<ExtendableRecording>
+	{
+		void extend();
+
+	private:
+		// implementation for LLVCRControlsMixin
+		/*virtual*/ void handleStart();
+		/*virtual*/ void handleStop();
+		/*virtual*/ void handleReset();
+		/*virtual*/ void handleSplitTo(ExtendableRecording& other);
+
+		Recording mAcceptedRecording;
+		Recording mPotentialRecording;
+	};
 }
 
 #endif // LL_LLTRACERECORDING_H
diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp
index 3acd06d553e724d4aea1e530374d52d9a8108f6c..48aa1a42f2e116adc9abe99c0216040b89d6cad3 100644
--- a/indra/llcommon/lltracethreadrecorder.cpp
+++ b/indra/llcommon/lltracethreadrecorder.cpp
@@ -36,15 +36,13 @@ namespace LLTrace
 ///////////////////////////////////////////////////////////////////////
 
 ThreadRecorder::ThreadRecorder()
-:	mPrimaryRecording(NULL)
 {
 	get_thread_recorder() = this;
 	mFullRecording.start();
 }
 
 ThreadRecorder::ThreadRecorder( const ThreadRecorder& other ) 
-:	mFullRecording(other.mFullRecording),
-	mPrimaryRecording(NULL)
+:	mFullRecording(other.mFullRecording)
 {
 	get_thread_recorder() = this;
 	mFullRecording.start();
@@ -55,45 +53,40 @@ ThreadRecorder::~ThreadRecorder()
 	get_thread_recorder() = NULL;
 }
 
-//TODO: remove this and use llviewerstats recording
-Recording* ThreadRecorder::getPrimaryRecording()
-{
-	return mPrimaryRecording;
-}
-
 void ThreadRecorder::activate( Recording* recording )
 {
-	mActiveRecordings.push_front(ActiveRecording(mPrimaryRecording, recording));
+	mActiveRecordings.push_front(ActiveRecording(recording));
 	mActiveRecordings.front().mBaseline.makePrimary();
-	mPrimaryRecording = &mActiveRecordings.front().mBaseline;
 }
 
 std::list<ThreadRecorder::ActiveRecording>::iterator ThreadRecorder::update( Recording* recording )
 {
-	for (std::list<ActiveRecording>::iterator it = mActiveRecordings.begin(), end_it = mActiveRecordings.end();
+	std::list<ActiveRecording>::iterator it, end_it;
+	for (it = mActiveRecordings.begin(), end_it = mActiveRecordings.end();
 		it != end_it;
 		++it)
 	{
 		std::list<ActiveRecording>::iterator next_it = it;
-		if (++next_it != mActiveRecordings.end())
+		++next_it;
+
+		// if we have another recording further down in the stack...
+		if (next_it != mActiveRecordings.end())
 		{
-			next_it->mergeMeasurements((*it));
+			// ...push our gathered data down to it
+			next_it->mBaseline.mergeRecording(it->mBaseline);
 		}
 
-		it->flushAccumulators(mPrimaryRecording);
+		// copy accumulated measurements into result buffer and clear accumulator (mBaseline)
+		it->moveBaselineToTarget();
 
 		if (it->mTargetRecording == recording)
 		{
-			if (next_it != mActiveRecordings.end())
-			{
-				next_it->mBaseline.makePrimary();
-				mPrimaryRecording = &next_it->mBaseline;
-			}
-			return it;
+			// found the recording, so return it
+			break;
 		}
 	}
 
-	return mActiveRecordings.end();
+	return it;
 }
 
 void ThreadRecorder::deactivate( Recording* recording )
@@ -101,38 +94,34 @@ void ThreadRecorder::deactivate( Recording* recording )
 	std::list<ActiveRecording>::iterator it = update(recording);
 	if (it != mActiveRecordings.end())
 	{
+		// and if we've found the recording we wanted to update
+		std::list<ActiveRecording>::iterator next_it = it;
+		++next_it;
+		if (next_it != mActiveRecordings.end())
+		{
+			next_it->mTargetRecording->makePrimary();
+		}
+
 		mActiveRecordings.erase(it);
 	}
 }
 
-ThreadRecorder::ActiveRecording::ActiveRecording( Recording* source, Recording* target ) 
+ThreadRecorder::ActiveRecording::ActiveRecording( Recording* target ) 
 :	mTargetRecording(target)
 {
-	// take snapshots of current values rates and timers
-	if (source)
-	{
-		mBaseline.mRates.write()->copyFrom(*source->mRates);
-		mBaseline.mStackTimers.write()->copyFrom(*source->mStackTimers);
-	}
 }
 
-void ThreadRecorder::ActiveRecording::mergeMeasurements(ThreadRecorder::ActiveRecording& other)
+void ThreadRecorder::ActiveRecording::moveBaselineToTarget()
 {
-	mBaseline.mMeasurements.write()->addSamples(*other.mBaseline.mMeasurements);
-}
-
-void ThreadRecorder::ActiveRecording::flushAccumulators(Recording* current)
-{
-	// accumulate statistics-like measurements
 	mTargetRecording->mMeasurements.write()->addSamples(*mBaseline.mMeasurements);
-	// for rate-like measurements, merge total change since baseline
-	mTargetRecording->mRates.write()->addDeltas(*mBaseline.mRates, *current->mRates);
-	mTargetRecording->mStackTimers.write()->addDeltas(*mBaseline.mStackTimers, *current->mStackTimers);
-	// reset baselines
-	mBaseline.mRates.write()->copyFrom(*current->mRates);
-	mBaseline.mStackTimers.write()->copyFrom(*current->mStackTimers);
+	mTargetRecording->mRates.write()->addSamples(*mBaseline.mRates);
+	mTargetRecording->mStackTimers.write()->addSamples(*mBaseline.mStackTimers);
+	mBaseline.mMeasurements.write()->reset();
+	mBaseline.mRates.write()->reset();
+	mBaseline.mStackTimers.write()->reset();
 }
 
+
 ///////////////////////////////////////////////////////////////////////
 // SlaveThreadRecorder
 ///////////////////////////////////////////////////////////////////////
diff --git a/indra/llcommon/lltracethreadrecorder.h b/indra/llcommon/lltracethreadrecorder.h
index 42230087c04d080e2d493533c560de0868593b0a..678b1a89f0437660bdba6f1b54840f8241f2667d 100644
--- a/indra/llcommon/lltracethreadrecorder.h
+++ b/indra/llcommon/lltracethreadrecorder.h
@@ -51,19 +51,16 @@ namespace LLTrace
 
 		virtual void pushToMaster() = 0;
 
-		Recording* getPrimaryRecording();
 	protected:
 		struct ActiveRecording
 		{
-			ActiveRecording(Recording* source, Recording* target);
+			ActiveRecording(Recording* target);
 
 			Recording*	mTargetRecording;
 			Recording	mBaseline;
 
-			void mergeMeasurements(ActiveRecording& other);
-			void flushAccumulators(Recording* current);
+			void moveBaselineToTarget();
 		};
-		Recording*					mPrimaryRecording;
 		Recording					mFullRecording;
 		std::list<ActiveRecording>	mActiveRecordings;
 	};
diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp
index 4cbf6950597ca61327f2bfa3217a7f0acd7f72c8..b73007e10776910e0d66616e0e4b839c760fed38 100644
--- a/indra/llui/llstatbar.cpp
+++ b/indra/llui/llstatbar.cpp
@@ -37,7 +37,6 @@
 #include "llstat.h"
 #include "lluictrlfactory.h"
 #include "lltracerecording.h"
-#include "lltracethreadrecorder.h"
 
 ///////////////////////////////////////////////////////////////////////////////////
 
@@ -112,17 +111,17 @@ void LLStatBar::draw()
 	}
 	else if (mFloatStatp)
 	{
-		LLTrace::Recording* recording = LLTrace::get_thread_recorder()->getPrimaryRecording();
+		LLTrace::Recording& recording = LLTrace::get_frame_recording().getLastRecordingPeriod();
 		if (mPerSec)
 		{
-			current = recording->getSum(*mFloatStatp) / recording->getSampleTime();
+			current = recording.getPerSec(*mFloatStatp);
 			//min = recording->getMin(*mFloatStatp) / recording->getSampleTime();
 			//max = recording->getMax(*mFloatStatp) / recording->getSampleTime();
 			//mean = recording->getMean(*mFloatStatp) / recording->getSampleTime();
 		}
 		else
 		{
-			current = recording->getSum(*mFloatStatp);
+			current = recording.getSum(*mFloatStatp);
 			//min = recording->getMin(*mFloatStatp);
 			//max = recording->getMax(*mFloatStatp);
 			//mean = recording->getMean(*mFloatStatp);
diff --git a/indra/llui/llstatbar.h b/indra/llui/llstatbar.h
index c735e7045b4261d7b19c9c81ab11327cc2f45508..bfc49b920476e872b28884ab8f6bf18043d346ec 100644
--- a/indra/llui/llstatbar.h
+++ b/indra/llui/llstatbar.h
@@ -29,8 +29,7 @@
 
 #include "llview.h"
 #include "llframetimer.h"
-#include "lltrace.h"
-
+#include "lltracerecording.h"
 class LLStat;
 
 class LLStatBar : public LLView
@@ -39,19 +38,24 @@ class LLStatBar : public LLView
 
 	struct Params : public LLInitParam::Block<Params, LLView::Params>
 	{
-		Optional<std::string> label;
-		Optional<std::string> unit_label;
-		Optional<F32> bar_min;
-		Optional<F32> bar_max;
-		Optional<F32> tick_spacing;
-		Optional<F32> label_spacing;
-		Optional<U32> precision;
-		Optional<F32> update_rate;
-		Optional<bool> show_per_sec;
-		Optional<bool> show_bar;
-		Optional<bool> show_history;
-		Optional<bool> show_mean;
-		Optional<std::string> stat;
+		Optional<std::string>	label,
+								unit_label;
+
+		Optional<F32>			bar_min,
+								bar_max,
+								tick_spacing,
+								label_spacing,
+								update_rate;
+
+		Optional<U32>			precision;
+
+		Optional<bool>			show_per_sec,
+								show_bar,
+								show_history,
+								show_mean;
+
+		Optional<std::string>	stat;
+
 		Params()
 			: label("label"),
 			  unit_label("unit_label"),
@@ -92,6 +96,7 @@ class LLStatBar : public LLView
 	BOOL mDisplayBar;			// Display the bar graph.
 	BOOL mDisplayHistory;
 	BOOL mDisplayMean;			// If true, display mean, if false, display current value
+	LLTrace::PeriodicRecording* mFrameRecording;
 
 	LLStat* mStatp;
 	LLTrace::Rate<F32>* mFloatStatp;
diff --git a/indra/llui/llstatgraph.cpp b/indra/llui/llstatgraph.cpp
index 1d4527aaa3378fa69e56d02310f0c5c0c4c3b65c..21b55c7c5afced3bd07ec059cd89cf3cc578d5bb 100644
--- a/indra/llui/llstatgraph.cpp
+++ b/indra/llui/llstatgraph.cpp
@@ -86,15 +86,15 @@ void LLStatGraph::draw()
 	}
 	else if (mF32Statp)
 	{
-		LLTrace::Recording* recording = LLTrace::get_thread_recorder()->getPrimaryRecording();
+		LLTrace::Recording& recording = LLTrace::get_frame_recording().getLastRecordingPeriod();
 
 		if (mPerSec)
 		{
-			mValue = recording->getSum(*mF32Statp) / recording->getSampleTime();
+			mValue = recording.getPerSec(*mF32Statp);
 		}
 		else
 		{
-			mValue = recording->getSum(*mF32Statp);
+			mValue = recording.getSum(*mF32Statp);
 		}
 
 	}
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 11d9f5e1eccffae9a161db278a937de8913a4b7b..bed2dffb14f4e3c6142e474899953cc620847e25 100755
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -497,6 +497,8 @@ void update_statistics()
 			texture_stats_timer.reset();
 		}
 	}
+
+	LLTrace::get_frame_recording().nextPeriod();
 }
 
 class ViewerStatsResponder : public LLHTTPClient::Responder
diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h
index a14518f53633e8183fe7668d77408d7772fede62..a164a28a59e4345fdee3b729949b69f58e456495 100755
--- a/indra/newview/llviewerstats.h
+++ b/indra/newview/llviewerstats.h
@@ -412,14 +412,12 @@ class LLViewerStats : public LLSingleton<LLViewerStats>
 	};
 
 	LLTrace::Recording& getRecording() { return mRecording; }
-	LLTrace::Recording& getFrameRecording() { return mFrameRecording; }
 
 private:
-	F64	mStats[ST_COUNT];
-	LLTrace::Recording	mRecording;
-	LLTrace::Recording	mFrameRecording;
+	F64								mStats[ST_COUNT];
+	LLTrace::Recording				mRecording;
 
-	F64 mLastTimeDiff;  // used for time stat updates
+	F64								mLastTimeDiff;  // used for time stat updates
 };
 
 static const F32 SEND_STATS_PERIOD = 300.0f;
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 81c45cfb84a4a3d6bcbe0870198f3cab07033353..af28ea36eb82df089853a971e45a55909f7a9f83 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -58,7 +58,7 @@
 #include "pipeline.h"
 #include "llappviewer.h"
 #include "llxuiparser.h"
-#include "lltracethreadrecorder.h"
+#include "lltracerecording.h"
 #include "llviewerdisplay.h"
 
 ////////////////////////////////////////////////////////////////////////////
@@ -621,9 +621,9 @@ void LLViewerTextureList::updateImages(F32 max_time)
 	}
 	cleared = FALSE;
 
-	LLTrace::Recording* recording = LLTrace::get_thread_recorder()->getPrimaryRecording();
+	LLTrace::Recording& recording = LLTrace::get_frame_recording().getTotalRecording();
 
-	LLAppViewer::getTextureFetch()->setTextureBandwidth(recording->getPerSec(LLStatViewer::TEXTURE_KBIT).value());
+	LLAppViewer::getTextureFetch()->setTextureBandwidth(recording.getPerSec(LLStatViewer::TEXTURE_KBIT).value());
 
 	LLViewerStats::getInstance()->mNumImagesStat.addValue(sNumImages);
 	LLViewerStats::getInstance()->mNumRawImagesStat.addValue(LLImageRaw::sRawImageCount);