diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp
index 6b4c3aeb06ee556884ea68468d6ff78852b31e6a..6d928721de99157f60cd14759f8c6964ee07f40d 100644
--- a/indra/llcommon/lltrace.cpp
+++ b/indra/llcommon/lltrace.cpp
@@ -66,18 +66,17 @@ MasterThreadRecorder& getMasterThreadRecorder()
 ///////////////////////////////////////////////////////////////////////
 
 ThreadRecorder::ThreadRecorder()
+:	mPrimaryRecording(NULL)
 {
 	get_thread_recorder() = this;
-	mPrimaryRecording.makePrimary();
 	mFullRecording.start();
 }
 
 ThreadRecorder::ThreadRecorder( const ThreadRecorder& other ) 
-:	mPrimaryRecording(other.mPrimaryRecording),
-	mFullRecording(other.mFullRecording)
+:	mFullRecording(other.mFullRecording),
+	mPrimaryRecording(NULL)
 {
 	get_thread_recorder() = this;
-	mPrimaryRecording.makePrimary();
 	mFullRecording.start();
 }
 
@@ -89,39 +88,74 @@ ThreadRecorder::~ThreadRecorder()
 //TODO: remove this and use llviewerstats recording
 Recording* ThreadRecorder::getPrimaryRecording()
 {
-	return &mPrimaryRecording;
+	return mPrimaryRecording;
 }
 
-void ThreadRecorder::activate( Recording* recorder )
+void ThreadRecorder::activate( Recording* recording )
 {
-	for (std::list<Recording*>::iterator it = mActiveRecordings.begin(), end_it = mActiveRecordings.end();
+	mActiveRecordings.push_front(ActiveRecording(mPrimaryRecording, recording));
+	mActiveRecordings.front().mBaseline.makePrimary();
+	mPrimaryRecording = &mActiveRecordings.front().mBaseline;
+}
+
+//TODO: consider merging results down the list to one past the buffered item.
+// this would require 2 buffers per sampler, to separate current total from running total
+
+void ThreadRecorder::deactivate( Recording* recording )
+{
+	for (std::list<ActiveRecording>::iterator it = mActiveRecordings.begin(), end_it = mActiveRecordings.end();
 		it != end_it;
 		++it)
 	{
-		(*it)->mMeasurements.write()->mergeSamples(*mPrimaryRecording.mMeasurements);
-	}
-	mPrimaryRecording.mMeasurements.write()->reset();
+		std::list<ActiveRecording>::iterator next_it = it;
+		if (++next_it != mActiveRecordings.end())
+		{
+			next_it->mergeMeasurements((*it));
+		}
 
-	recorder->initDeltas(mPrimaryRecording);
+		it->flushAccumulators(mPrimaryRecording);
 
-	mActiveRecordings.push_front(recorder);
+		if (it->mTargetRecording == recording)
+		{
+			if (next_it != mActiveRecordings.end())
+			{
+				next_it->mBaseline.makePrimary();
+				mPrimaryRecording = &next_it->mBaseline;
+			}
+			mActiveRecordings.erase(it);
+			break;
+		}
+	}
 }
 
-//TODO: consider merging results down the list to one past the buffered item.
-// this would require 2 buffers per sampler, to separate current total from running total
-
-void ThreadRecorder::deactivate( Recording* recorder )
+ThreadRecorder::ActiveRecording::ActiveRecording( Recording* source, Recording* target ) 
+:	mTargetRecording(target)
 {
-	recorder->mergeDeltas(mPrimaryRecording);
-
-	// TODO: replace with intrusive list
-	std::list<Recording*>::iterator found_it = std::find(mActiveRecordings.begin(), mActiveRecordings.end(), recorder);
-	if (found_it != mActiveRecordings.end())
+	// take snapshots of current values rates and timers
+	if (source)
 	{
-		mActiveRecordings.erase(found_it);
+		mBaseline.mRates.write()->copyFrom(*source->mRates);
+		mBaseline.mStackTimers.write()->copyFrom(*source->mStackTimers);
 	}
 }
 
+void ThreadRecorder::ActiveRecording::mergeMeasurements(ThreadRecorder::ActiveRecording& other)
+{
+	mBaseline.mMeasurements.write()->mergeSamples(*other.mBaseline.mMeasurements);
+}
+
+void ThreadRecorder::ActiveRecording::flushAccumulators(Recording* current)
+{
+	// accumulate statistics-like measurements
+	mTargetRecording->mMeasurements.write()->mergeSamples(*mBaseline.mMeasurements);
+	// for rate-like measurements, merge total change since baseline
+	mTargetRecording->mRates.write()->mergeDeltas(*mBaseline.mRates, *current->mRates);
+	mTargetRecording->mStackTimers.write()->mergeDeltas(*mBaseline.mStackTimers, *current->mStackTimers);
+	// reset baselines
+	mBaseline.mRates.write()->copyFrom(*current->mRates);
+	mBaseline.mStackTimers.write()->copyFrom(*current->mStackTimers);
+}
+
 ///////////////////////////////////////////////////////////////////////
 // SlaveThreadRecorder
 ///////////////////////////////////////////////////////////////////////
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index c5356777aed7941aaa863849bcd68866f8abf8b1..39de79e4c173134e6d54c31b7e6a87e983e4b5d9 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -497,9 +497,19 @@ namespace LLTrace
 
 		Recording* getPrimaryRecording();
 	protected:
-		Recording					mPrimaryRecording;
+		struct ActiveRecording
+		{
+			ActiveRecording(Recording* source, Recording* target);
+
+			Recording*	mTargetRecording;
+			Recording	mBaseline;
+
+			void mergeMeasurements(ActiveRecording& other);
+			void flushAccumulators(Recording* current);
+		};
+		Recording*					mPrimaryRecording;
 		Recording					mFullRecording;
-		std::list<Recording*>		mActiveRecordings;
+		std::list<ActiveRecording>	mActiveRecordings;
 	};
 
 	class LL_COMMON_API MasterThreadRecorder : public ThreadRecorder
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
index a792d40f9d692284412d89c0abc3fddf0d18de52..95cdb44e4be9d705749a5613d1cf0813db6608f7 100644
--- a/indra/llcommon/lltracerecording.cpp
+++ b/indra/llcommon/lltracerecording.cpp
@@ -39,17 +39,13 @@ namespace LLTrace
 Recording::Recording() 
 :	mElapsedSeconds(0),
 	mIsStarted(false),
-	mRatesStart(new AccumulatorBuffer<RateAccumulator<F32> >()),
 	mRates(new AccumulatorBuffer<RateAccumulator<F32> >()),
 	mMeasurements(new AccumulatorBuffer<MeasurementAccumulator<F32> >()),
-	mStackTimers(new AccumulatorBuffer<TimerAccumulator>()),
-	mStackTimersStart(new AccumulatorBuffer<TimerAccumulator>())
-{
-}
+	mStackTimers(new AccumulatorBuffer<TimerAccumulator>())
+{}
 
 Recording::~Recording()
-{
-}
+{}
 
 void Recording::start()
 {
@@ -107,18 +103,10 @@ void Recording::mergeSamples( const Recording& other )
 	mStackTimers.write()->mergeSamples(*other.mStackTimers);
 }
 
-void Recording::initDeltas( const Recording& other )
+void Recording::mergeDeltas(const Recording& baseline, const Recording& target)
 {
-	mRatesStart.write()->copyFrom(*other.mRates);
-	mStackTimersStart.write()->copyFrom(*other.mStackTimers);
-}
-
-
-void Recording::mergeDeltas( const Recording& other )
-{
-	mRates.write()->mergeDeltas(*mRatesStart, *other.mRates);
-	mStackTimers.write()->mergeDeltas(*mStackTimersStart, *other.mStackTimers);
-	mMeasurements.write()->mergeSamples(*other.mMeasurements);
+	mRates.write()->mergeDeltas(*baseline.mRates, *target.mRates);
+	mStackTimers.write()->mergeDeltas(*baseline.mStackTimers, *target.mStackTimers);
 }
 
 
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h
index 83dc503ea6ae2d423e06e9e89e74ba82f47ea7e9..0a54e4cedfc94a0fbcddda6228a40d42b5c6c640 100644
--- a/indra/llcommon/lltracerecording.h
+++ b/indra/llcommon/lltracerecording.h
@@ -57,8 +57,7 @@ namespace LLTrace
 		void resume();
 
 		void mergeSamples(const Recording& other);
-		void initDeltas(const Recording& other);
-		void mergeDeltas(const Recording& other);
+		void mergeDeltas(const Recording& baseline, const Recording& target);
 
 		void reset();
 
@@ -80,10 +79,8 @@ namespace LLTrace
 		// returns data for current thread
 		class ThreadRecorder* getThreadRecorder(); 
 
-		LLCopyOnWritePointer<AccumulatorBuffer<RateAccumulator<F32> > >			mRatesStart;
 		LLCopyOnWritePointer<AccumulatorBuffer<RateAccumulator<F32> > >			mRates;
 		LLCopyOnWritePointer<AccumulatorBuffer<MeasurementAccumulator<F32> > >	mMeasurements;
-		LLCopyOnWritePointer<AccumulatorBuffer<TimerAccumulator> >				mStackTimersStart;
 		LLCopyOnWritePointer<AccumulatorBuffer<TimerAccumulator> >				mStackTimers;
 
 		bool			mIsStarted;