diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index e1549b4bff11ee5e88d6ae6910f3dbc69fe1307c..16dd21332c6868bb83be706a605fe6a9619e6b33 100644
--- a/indra/llcommon/llfasttimer.cpp
+++ b/indra/llcommon/llfasttimer.cpp
@@ -177,8 +177,8 @@ BlockTimer::BlockTimer(const char* name, bool open, BlockTimer* parent)
 		mParent = this;
 	}
 
-	mCountHistory = new U32[HISTORY_NUM];
-	memset(mCountHistory, 0, sizeof(U32) * HISTORY_NUM);
+	mCountHistory = new U64[HISTORY_NUM];
+	memset(mCountHistory, 0, sizeof(U64) * HISTORY_NUM);
 	mCallHistory = new U32[HISTORY_NUM];
 	memset(mCallHistory, 0, sizeof(U32) * HISTORY_NUM);
 }
@@ -266,9 +266,12 @@ void BlockTimer::buildHierarchy()
 			
 			// bootstrap tree construction by attaching to last timer to be on stack
 			// when this timer was called
-			if (timer.getPrimaryAccumulator().mLastCaller && timer.mParent == &BlockTimer::getRootTimer())
+			if (timer.mParent == &BlockTimer::getRootTimer())
 			{
-				timer.setParent(timer.getPrimaryAccumulator().mLastCaller);
+				if (timer.getPrimaryAccumulator().mLastCaller)
+				{
+					timer.setParent(timer.getPrimaryAccumulator().mLastCaller);
+				}
 				// no need to push up tree on first use, flag can be set spuriously
 				timer.getPrimaryAccumulator().mMoveUpTree = false;
 			}
@@ -317,7 +320,7 @@ void BlockTimer::buildHierarchy()
 //static
 void BlockTimer::accumulateTimings()
 {
-	U32 cur_time = getCPUClockCount32();
+	U64 cur_time = getCPUClockCount64();
 
 	// walk up stack of active timers and accumulate current time while leaving timing structures active
 	Time* cur_timer = sCurTimerData->mCurTimer;
@@ -326,8 +329,8 @@ void BlockTimer::accumulateTimings()
 	TimerAccumulator& accumulator = sCurTimerData->mTimerData->getPrimaryAccumulator();
 	while(cur_timer && cur_timer->mLastTimerData.mCurTimer != cur_timer)
 	{
-		U32 cumulative_time_delta = cur_time - cur_timer->mStartTime;
-		U32 self_time_delta = cumulative_time_delta - cur_data->mChildTime;
+		U64 cumulative_time_delta = cur_time - cur_timer->mStartTime;
+		U64 self_time_delta = cumulative_time_delta - cur_data->mChildTime;
 		cur_data->mChildTime = 0;
 		accumulator.mSelfTimeCounter += self_time_delta;
 		accumulator.mTotalTimeCounter += cumulative_time_delta;
@@ -429,6 +432,7 @@ void BlockTimer::resetFrame()
 		BlockTimer& timer = *it;
 		TimerAccumulator& accumulator = timer.getPrimaryAccumulator();
 		accumulator.mSelfTimeCounter = 0;
+		accumulator.mTotalTimeCounter = 0;
 		accumulator.mCalls = 0;
 		accumulator.mLastCaller = NULL;
 		accumulator.mMoveUpTree = false;
@@ -442,7 +446,7 @@ void BlockTimer::reset()
 
 	// walk up stack of active timers and reset start times to current time
 	// effectively zeroing out any accumulated time
-	U32 cur_time = getCPUClockCount32();
+	U64 cur_time = getCPUClockCount64();
 
 	// root defined by parent pointing to self
 	CurTimerData* cur_data = sCurTimerData.get();
@@ -471,7 +475,7 @@ void BlockTimer::reset()
 			
 			timer.mCountAverage = 0;
 			timer.mCallAverage = 0;
-			memset(timer.mCountHistory, 0, sizeof(U32) * HISTORY_NUM);
+			memset(timer.mCountHistory, 0, sizeof(U64) * HISTORY_NUM);
 			memset(timer.mCallHistory, 0, sizeof(U32) * HISTORY_NUM);
 		}
 	}
@@ -480,7 +484,7 @@ void BlockTimer::reset()
 	sCurFrameIndex = 0;
 }
 
-U32 BlockTimer::getHistoricalCount(S32 history_index) const
+U64 BlockTimer::getHistoricalCount(S32 history_index) const
 {
 	S32 history_idx = (getLastFrameIndex() + history_index) % HISTORY_NUM;
 	return mCountHistory[history_idx];
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index af9b360e01eb12fa911cce373a7709d85bbc6f78..cfe2cf5371a5f14c844d9c880f09c7cab9fd0ba5 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -93,7 +93,7 @@ class BlockTimer
 	U32 getCountAverage() const { return mCountAverage; }
 	U32 getCallAverage() const	{ return mCallAverage; }
 
-	U32 getHistoricalCount(S32 history_index = 0) const;
+	U64 getHistoricalCount(S32 history_index = 0) const;
 	U32 getHistoricalCalls(S32 history_index = 0) const;
 
 	static BlockTimer& getRootTimer();
@@ -258,12 +258,12 @@ class BlockTimer
 
 
 	// sum of recorded self time and tree time of all children timers (might not match actual recorded time of children if topology is incomplete
-	U32 						mTreeTimeCounter; 
+	U64 						mTreeTimeCounter; 
 
-	U32 						mCountAverage;
+	U64 						mCountAverage;
 	U32							mCallAverage;
 
-	U32*						mCountHistory;
+	U64*						mCountHistory;
 	U32*						mCallHistory;
 
 	// tree structure
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index 61d14569cd5b8e25d58132e862a6691dd3498854..11651ef9531018af0a32e89453a001d6cda1b578 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -107,6 +107,7 @@ namespace LLTrace
 				//TODO pick another primary?
 				sPrimaryStorage = NULL;
 			}
+			delete[] mStorage;
 		}
 
 		LL_FORCE_INLINE ACCUMULATOR& operator[](size_t index) 
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
index 4252ed57dc54b519c3d8727cf449b5fbe77c4ba3..e7ed55e8aef242ab4710d452ef9ffaf868d371ae 100644
--- a/indra/llcommon/lltracerecording.cpp
+++ b/indra/llcommon/lltracerecording.cpp
@@ -66,7 +66,10 @@ Recording::Recording( const Recording& other )
 
 
 Recording::~Recording()
-{}
+{
+	stop();
+	llassert(isStopped());
+}
 
 void Recording::update()
 {
diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp
index c2fefe295732d7d71d2de8208c2a4465ac0ab9b1..faaab4c8e71618c68c2e6dba76e78654e45ebe17 100644
--- a/indra/llcommon/lltracethreadrecorder.cpp
+++ b/indra/llcommon/lltracethreadrecorder.cpp
@@ -53,6 +53,10 @@ ThreadRecorder::ThreadRecorder( const ThreadRecorder& other )
 
 ThreadRecorder::~ThreadRecorder()
 {
+	while(mActiveRecordings.size())
+	{
+		mActiveRecordings.front().mTargetRecording->stop();
+	}
 	get_thread_recorder() = NULL;
 	delete BlockTimer::sCurTimerData.get();
 	BlockTimer::sCurTimerData = NULL;
diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml
index 92a241857e02e055ce8c0ba7a71d06257b86e635..b9ae7ebf0bc2a3863fa62b88d12f82ba6a0a652f 100644
--- a/indra/newview/app_settings/logcontrol.xml
+++ b/indra/newview/app_settings/logcontrol.xml
@@ -42,6 +42,7 @@
 						</array>
 					<key>tags</key>
 						<array>
+              <string>FastTimers</string>
 						<!-- sample entry for debugging specific items	
 						     <string>Avatar</string>
 						     <string>Voice</string>		
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index f73fc4b990ad0d15d855295421c6fcda52af4aae..839094fc47b6f3397c12d07be6230f4a9ba4d88a 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -438,7 +438,7 @@ LLAppViewer::LLUpdaterInfo *LLAppViewer::sUpdaterInfo = NULL ;
 //----------------------------------------------------------------------------
 // Metrics logging control constants
 //----------------------------------------------------------------------------
-static const F32 METRICS_INTERVAL_DEFAULT = 600.0;
+static const F32 METRICS_INTERVAL_DEFAULT = 30.0;
 static const F32 METRICS_INTERVAL_QA = 30.0;
 static F32 app_metrics_interval = METRICS_INTERVAL_DEFAULT;
 static bool app_metrics_qa_mode = false;
@@ -5308,6 +5308,7 @@ void LLAppViewer::metricsSend(bool enable_reporting)
 			// Make a copy of the main stats to send into another thread.
 			// Receiving thread takes ownership.
 			LLViewerAssetStats * main_stats(new LLViewerAssetStats(*gViewerAssetStats));
+			main_stats->stop();
 
 			main_stats->updateStats();
 			
diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp
index 73a2e24424be0090650a7a38dce7159eb8af677a..d79d98aaaf025550f7e16349e0c7a10c4d42605e 100644
--- a/indra/newview/llviewerassetstats.cpp
+++ b/indra/newview/llviewerassetstats.cpp
@@ -239,7 +239,7 @@ LLViewerAssetStats::LLViewerAssetStats()
 :	mRegionHandle(U64(0)),
 	mCurRecording(NULL)
 {
-	reset();
+	start();
 }
 
 
@@ -252,6 +252,29 @@ LLViewerAssetStats::LLViewerAssetStats(const LLViewerAssetStats & src)
 	mRegionRecordings = src.mRegionRecordings;
 	
 	mCurRecording = &mRegionRecordings[mRegionHandle];
+	mCurRecording->stop();
+	LLStopWatchControlsMixin::initTo(src.getPlayState());
+}
+
+void LLViewerAssetStats::handleStart()
+{
+	if (mCurRecording)
+	{
+		mCurRecording->start();
+	}
+}
+
+void LLViewerAssetStats::handleStop()
+{
+	if (mCurRecording)
+	{
+		mCurRecording->stop();
+	}
+}
+
+void LLViewerAssetStats::handleReset()
+{
+	reset();
 }
 
 
diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h
index 835df891498ef3807aa5242b4e9eb033c23e1c59..5b25d791a9a6f9a82ccda22ed9dff31587f6ad7e 100644
--- a/indra/newview/llviewerassetstats.h
+++ b/indra/newview/llviewerassetstats.h
@@ -74,7 +74,7 @@
  * LLViewerAssetStatsFF is provided for conditional test-and-call
  * operations.
  */
-class LLViewerAssetStats
+class LLViewerAssetStats : public LLStopWatchControlsMixin<LLViewerAssetStats>
 {
 public:
 	/**
@@ -177,6 +177,7 @@ class LLViewerAssetStats
 public:
 	LLViewerAssetStats();
 	LLViewerAssetStats(const LLViewerAssetStats &);
+
 	// Default destructor is correct.
 	LLViewerAssetStats & operator=(const LLViewerAssetStats &);			// Not defined
 
@@ -202,6 +203,10 @@ class LLViewerAssetStats
 	LLSD asLLSD(bool compact_output);
 
 protected:
+	void handleStart();
+	void handleStop();
+	void handleReset();
+
 	typedef std::map<region_handle_t, LLTrace::Recording > PerRegionRecordingContainer;
 
 	// Region of the currently-active region.  Always valid but may