From 407e5013f3845208e0a60e26e8f0a7fad997df5d Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Mon, 3 Dec 2012 19:54:53 -0800
Subject: SH-3406 WIP convert fast timers to lltrace system converted fast
 timer view over to new lltrace mechanisms

---
 indra/llcommon/llfasttimer.cpp               | 538 ++++++++----------
 indra/llcommon/llfasttimer.h                 | 111 ++--
 indra/llcommon/llmetricperformancetester.cpp |   4 +-
 indra/llcommon/lltrace.h                     |  39 +-
 indra/llcommon/lltracerecording.cpp          |  21 +-
 indra/llcommon/lltracerecording.h            |   8 +-
 indra/llcommon/lltracethreadrecorder.cpp     |  12 +-
 indra/llcommon/lltracethreadrecorder.h       |   2 +-
 indra/llcommon/llunit.h                      |   8 +-
 indra/newview/llappviewer.cpp                |  33 +-
 indra/newview/llfasttimerview.cpp            | 778 +++++++++++++--------------
 indra/newview/llfasttimerview.h              |  32 +-
 indra/newview/llstartup.cpp                  |   2 +-
 indra/newview/llviewermenu.cpp               |   2 +-
 14 files changed, 737 insertions(+), 853 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index e33cb76eff..cf7655acf7 100644
--- a/indra/llcommon/llfasttimer.cpp
+++ b/indra/llcommon/llfasttimer.cpp
@@ -34,6 +34,7 @@
 #include "llsdserialize.h"
 #include "llunit.h"
 #include "llsd.h"
+#include "lltracerecording.h"
 
 #include <boost/bind.hpp>
 #include <queue>
@@ -58,22 +59,22 @@ namespace LLTrace
 //////////////////////////////////////////////////////////////////////////////
 // statics
 
-S32         BlockTimer::sCurFrameIndex   = -1;
-S32         BlockTimer::sLastFrameIndex  = -1;
-U64         BlockTimer::sLastFrameTime   = BlockTimer::getCPUClockCount64();
-bool        BlockTimer::sPauseHistory    = 0;
-bool        BlockTimer::sResetHistory    = 0;
-bool        BlockTimer::sLog		     = false;
-std::string BlockTimer::sLogName         = "";
-bool        BlockTimer::sMetricLog       = false;
+S32         TimeBlock::sCurFrameIndex   = -1;
+S32         TimeBlock::sLastFrameIndex  = -1;
+U64         TimeBlock::sLastFrameTime   = TimeBlock::getCPUClockCount64();
+bool        TimeBlock::sPauseHistory    = 0;
+bool        TimeBlock::sResetHistory    = 0;
+bool        TimeBlock::sLog		     = false;
+std::string TimeBlock::sLogName         = "";
+bool        TimeBlock::sMetricLog       = false;
 
 #if LL_LINUX || LL_SOLARIS
-U64         BlockTimer::sClockResolution = 1000000000; // Nanosecond resolution
+U64         TimeBlock::sClockResolution = 1000000000; // Nanosecond resolution
 #else
-U64         BlockTimer::sClockResolution = 1000000; // Microsecond resolution
+U64         TimeBlock::sClockResolution = 1000000; // Microsecond resolution
 #endif
 
-LLThreadLocalPointer<CurTimerData> BlockTimer::sCurTimerData;
+LLThreadLocalPointer<CurTimerData> TimeBlock::sCurTimerData;
 
 static LLMutex*			sLogLock = NULL;
 static std::queue<LLSD> sLogQueue;
@@ -82,13 +83,13 @@ static std::queue<LLSD> sLogQueue;
 // FIXME: move these declarations to the relevant modules
 
 // helper functions
-typedef LLTreeDFSPostIter<BlockTimer, BlockTimer::child_const_iter> timer_tree_bottom_up_iterator_t;
+typedef LLTreeDFSPostIter<TimeBlock, TimeBlock::child_const_iter> timer_tree_bottom_up_iterator_t;
 
-static timer_tree_bottom_up_iterator_t begin_timer_tree_bottom_up(BlockTimer& id) 
+static timer_tree_bottom_up_iterator_t begin_timer_tree_bottom_up(TimeBlock& id) 
 { 
 	return timer_tree_bottom_up_iterator_t(&id, 
-							boost::bind(boost::mem_fn(&BlockTimer::beginChildren), _1), 
-							boost::bind(boost::mem_fn(&BlockTimer::endChildren), _1));
+							boost::bind(boost::mem_fn(&TimeBlock::beginChildren), _1), 
+							boost::bind(boost::mem_fn(&TimeBlock::endChildren), _1));
 }
 
 static timer_tree_bottom_up_iterator_t end_timer_tree_bottom_up() 
@@ -96,14 +97,14 @@ static timer_tree_bottom_up_iterator_t end_timer_tree_bottom_up()
 	return timer_tree_bottom_up_iterator_t(); 
 }
 
-typedef LLTreeDFSIter<BlockTimer, BlockTimer::child_const_iter> timer_tree_dfs_iterator_t;
+typedef LLTreeDFSIter<TimeBlock, TimeBlock::child_const_iter> timer_tree_dfs_iterator_t;
 
 
-static timer_tree_dfs_iterator_t begin_timer_tree(BlockTimer& id) 
+static timer_tree_dfs_iterator_t begin_timer_tree(TimeBlock& id) 
 { 
 	return timer_tree_dfs_iterator_t(&id, 
-		boost::bind(boost::mem_fn(&BlockTimer::beginChildren), _1), 
-							boost::bind(boost::mem_fn(&BlockTimer::endChildren), _1));
+		boost::bind(boost::mem_fn(&TimeBlock::beginChildren), _1), 
+							boost::bind(boost::mem_fn(&TimeBlock::endChildren), _1));
 }
 
 static timer_tree_dfs_iterator_t end_timer_tree() 
@@ -112,20 +113,29 @@ static timer_tree_dfs_iterator_t end_timer_tree()
 }
 
 
-BlockTimer& BlockTimer::getRootTimer()
+// sort child timers by name
+struct SortTimerByName
 {
-	static BlockTimer root_timer("root", true, NULL);
+	bool operator()(const TimeBlock* i1, const TimeBlock* i2)
+	{
+		return i1->getName() < i2->getName();
+	}
+};
+
+TimeBlock& TimeBlock::getRootTimer()
+{
+	static TimeBlock root_timer("root", true, NULL);
 	return root_timer;
 }
 
-void BlockTimer::pushLog(LLSD log)
+void TimeBlock::pushLog(LLSD log)
 {
 	LLMutexLock lock(sLogLock);
 
 	sLogQueue.push(log);
 }
 
-void BlockTimer::setLogLock(LLMutex* lock)
+void TimeBlock::setLogLock(LLMutex* lock)
 {
 	sLogLock = lock;
 }
@@ -133,12 +143,12 @@ void BlockTimer::setLogLock(LLMutex* lock)
 
 //static
 #if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
-U64 BlockTimer::countsPerSecond() // counts per second for the *64-bit* timer
+U64 TimeBlock::countsPerSecond() // counts per second for the *64-bit* timer
 {
 	return sClockResolution;
 }
 #else // windows or x86-mac or x86-linux or x86-solaris
-U64 BlockTimer::countsPerSecond() // counts per second for the *64-bit* timer
+U64 TimeBlock::countsPerSecond() // counts per second for the *64-bit* timer
 {
 #if LL_FASTTIMER_USE_RDTSC || !LL_WINDOWS
 	//getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz
@@ -160,13 +170,10 @@ U64 BlockTimer::countsPerSecond() // counts per second for the *64-bit* timer
 }
 #endif
 
-BlockTimer::BlockTimer(const char* name, bool open, BlockTimer* parent)
+TimeBlock::TimeBlock(const char* name, bool open, TimeBlock* parent)
 :	TraceType(name),
 	mCollapsed(true),
 	mParent(NULL),
-	mTreeTimeCounter(0),
-	mCountAverage(0),
-	mCallAverage(0),
 	mNeedsSorting(false)
 {
 	setCollapsed(!open);
@@ -179,37 +186,26 @@ BlockTimer::BlockTimer(const char* name, bool open, BlockTimer* parent)
 	{
 		mParent = this;
 	}
-
-	mCountHistory = new U64[HISTORY_NUM];
-	memset(mCountHistory, 0, sizeof(U64) * HISTORY_NUM);
-	mCallHistory = new U32[HISTORY_NUM];
-	memset(mCallHistory, 0, sizeof(U32) * HISTORY_NUM);
 }
 
-BlockTimer::~BlockTimer()
-{
-	delete[] mCountHistory;
-	delete[] mCallHistory;
-}
-
-void BlockTimer::setParent(BlockTimer* parent)
+void TimeBlock::setParent(TimeBlock* parent)
 {
 	llassert_always(parent != this);
 	llassert_always(parent != NULL);
 
 	if (mParent)
 	{
-		// subtract our accumulated from previous parent
-		for (S32 i = 0; i < HISTORY_NUM; i++)
-		{
-			mParent->mCountHistory[i] -= mCountHistory[i];
-		}
+		//// subtract our accumulated from previous parent
+		//for (S32 i = 0; i < HISTORY_NUM; i++)
+		//{
+		//	mParent->mCountHistory[i] -= mCountHistory[i];
+		//}
 
-		// subtract average timing from previous parent
-		mParent->mCountAverage -= mCountAverage;
+		//// subtract average timing from previous parent
+		//mParent->mCountAverage -= mCountAverage;
 
-		std::vector<BlockTimer*>& children = mParent->getChildren();
-		std::vector<BlockTimer*>::iterator found_it = std::find(children.begin(), children.end(), this);
+		std::vector<TimeBlock*>& children = mParent->getChildren();
+		std::vector<TimeBlock*>::iterator found_it = std::find(children.begin(), children.end(), this);
 		if (found_it != children.end())
 		{
 			children.erase(found_it);
@@ -224,10 +220,10 @@ void BlockTimer::setParent(BlockTimer* parent)
 	}
 }
 
-S32 BlockTimer::getDepth()
+S32 TimeBlock::getDepth()
 {
 	S32 depth = 0;
-	BlockTimer* timerp = mParent;
+	TimeBlock* timerp = mParent;
 	while(timerp)
 	{
 		depth++;
@@ -238,291 +234,152 @@ S32 BlockTimer::getDepth()
 }
 
 // static
-void BlockTimer::processTimes()
+void TimeBlock::processTimes()
 {
-	if (getCurFrameIndex() < 0) return;
-
-	buildHierarchy();
-	accumulateTimings();
-}
-
-// sort child timers by name
-struct SortTimerByName
-{
-	bool operator()(const BlockTimer* i1, const BlockTimer* i2)
-	{
-		return i1->getName() < i2->getName();
-	}
-};
-
-//static
-void BlockTimer::buildHierarchy()
-{
-	if (getCurFrameIndex() < 0 ) return;
-
-	// set up initial tree
+	//void TimeBlock::buildHierarchy()
 	{
-		for (LLInstanceTracker<BlockTimer>::instance_iter it = LLInstanceTracker<BlockTimer>::beginInstances(), end_it = LLInstanceTracker<BlockTimer>::endInstances(); it != end_it; ++it)
+		// set up initial tree
 		{
-			BlockTimer& timer = *it;
-			if (&timer == &BlockTimer::getRootTimer()) continue;
-			
-			// bootstrap tree construction by attaching to last timer to be on stack
-			// when this timer was called
-			if (timer.mParent == &BlockTimer::getRootTimer())
+			for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances(); it != end_it; ++it)
 			{
-				TimerTreeNode& tree_node = sCurTimerData->mTimerTreeData[timer.getIndex()];
+				TimeBlock& timer = *it;
+				if (&timer == &TimeBlock::getRootTimer()) continue;
 
-				if (tree_node.mLastCaller)
+				// bootstrap tree construction by attaching to last timer to be on stack
+				// when this timer was called
+				if (timer.mParent == &TimeBlock::getRootTimer())
 				{
-					timer.setParent(tree_node.mLastCaller);
+					TimeBlockTreeNode& tree_node = sCurTimerData->mTimerTreeData[timer.getIndex()];
+
+					if (tree_node.mLastCaller)
+					{
+						timer.setParent(tree_node.mLastCaller);
+					}
+					// no need to push up tree on first use, flag can be set spuriously
+					tree_node.mMoveUpTree = false;
 				}
-				// no need to push up tree on first use, flag can be set spuriously
-				tree_node.mMoveUpTree = false;
 			}
 		}
-	}
-
-	// bump timers up tree if they have been flagged as being in the wrong place
-	// do this in a bottom up order to promote descendants first before promoting ancestors
-	// this preserves partial order derived from current frame's observations
-	for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(BlockTimer::getRootTimer());
-		it != end_timer_tree_bottom_up();
-		++it)
-	{
-		BlockTimer* timerp = *it;
-		// skip root timer
-		if (timerp == &BlockTimer::getRootTimer()) continue;
-		TimerTreeNode& tree_node = sCurTimerData->mTimerTreeData[timerp->getIndex()];
 
-		if (tree_node.mMoveUpTree)
+		// bump timers up tree if they have been flagged as being in the wrong place
+		// do this in a bottom up order to promote descendants first before promoting ancestors
+		// this preserves partial order derived from current frame's observations
+		for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(TimeBlock::getRootTimer());
+			it != end_timer_tree_bottom_up();
+			++it)
 		{
-			// since ancestors have already been visited, re-parenting won't affect tree traversal
-			//step up tree, bringing our descendants with us
-			LL_DEBUGS("FastTimers") << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() <<
-				" to child of " << timerp->getParent()->getParent()->getName() << LL_ENDL;
-			timerp->setParent(timerp->getParent()->getParent());
-			tree_node.mMoveUpTree = false;
+			TimeBlock* timerp = *it;
+			// skip root timer
+			if (timerp == &TimeBlock::getRootTimer()) continue;
+			TimeBlockTreeNode& tree_node = sCurTimerData->mTimerTreeData[timerp->getIndex()];
 
-			// don't bubble up any ancestors until descendants are done bubbling up
-			it.skipAncestors();
-		}
-	}
+			if (tree_node.mMoveUpTree)
+			{
+				// since ancestors have already been visited, re-parenting won't affect tree traversal
+				//step up tree, bringing our descendants with us
+				LL_DEBUGS("FastTimers") << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() <<
+					" to child of " << timerp->getParent()->getParent()->getName() << LL_ENDL;
+				timerp->setParent(timerp->getParent()->getParent());
+				tree_node.mMoveUpTree = false;
 
-	// sort timers by time last called, so call graph makes sense
-	for(timer_tree_dfs_iterator_t it = begin_timer_tree(BlockTimer::getRootTimer());
-		it != end_timer_tree();
-		++it)
-	{
-		BlockTimer* timerp = (*it);
-		if (timerp->mNeedsSorting)
-		{
-			std::sort(timerp->getChildren().begin(), timerp->getChildren().end(), SortTimerByName());
+				// don't bubble up any ancestors until descendants are done bubbling up
+				it.skipAncestors();
+			}
 		}
-		timerp->mNeedsSorting = false;
-	}
-}
-
-//static
-void BlockTimer::accumulateTimings()
-{
-	U64 cur_time = getCPUClockCount64();
-
-	// root defined by parent pointing to self
-	CurTimerData* cur_data = sCurTimerData.get();
-	// walk up stack of active timers and accumulate current time while leaving timing structures active
-	Time* cur_timer = cur_data->mCurTimer;
-	TimerAccumulator& accumulator = cur_data->mTimerData->getPrimaryAccumulator();
-	while(cur_timer && cur_timer->mLastTimerData.mCurTimer != cur_timer)
-	{
-		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;
-
-		cur_timer->mStartTime = cur_time;
 
-		cur_data = &cur_timer->mLastTimerData;
-		cur_data->mChildTime += cumulative_time_delta;
-		if (cur_data->mTimerData)
+		// sort timers by time last called, so call graph makes sense
+		for(timer_tree_dfs_iterator_t it = begin_timer_tree(TimeBlock::getRootTimer());
+			it != end_timer_tree();
+			++it)
 		{
-			accumulator = cur_data->mTimerData->getPrimaryAccumulator();
+			TimeBlock* timerp = (*it);
+			if (timerp->mNeedsSorting)
+			{
+				std::sort(timerp->getChildren().begin(), timerp->getChildren().end(), SortTimerByName());
+			}
+			timerp->mNeedsSorting = false;
 		}
-
-		cur_timer = cur_timer->mLastTimerData.mCurTimer;
 	}
-
-	// traverse tree in DFS post order, or bottom up
-	for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(BlockTimer::getRootTimer());
-		it != end_timer_tree_bottom_up();
-		++it)
+	
+	//void TimeBlock::accumulateTimings()
 	{
-		BlockTimer* timerp = (*it);
-		TimerAccumulator& accumulator = timerp->getPrimaryAccumulator();
-		timerp->mTreeTimeCounter = accumulator.mSelfTimeCounter;
-		for (child_const_iter child_it = timerp->beginChildren(); child_it != timerp->endChildren(); ++child_it)
-		{
-			timerp->mTreeTimeCounter += (*child_it)->mTreeTimeCounter;
-		}
-
-		S32 cur_frame = getCurFrameIndex();
-		if (cur_frame >= 0)
+		U64 cur_time = getCPUClockCount64();
+
+		// root defined by parent pointing to self
+		CurTimerData* cur_data = sCurTimerData.get();
+		// walk up stack of active timers and accumulate current time while leaving timing structures active
+		BlockTimer* cur_timer = cur_data->mCurTimer;
+		TimeBlockAccumulator& accumulator = cur_data->mTimerData->getPrimaryAccumulator();
+		while(cur_timer && cur_timer->mLastTimerData.mCurTimer != cur_timer)
 		{
-			// update timer history
-			int hidx = cur_frame % HISTORY_NUM;
+			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;
 
-			timerp->mCountHistory[hidx] = timerp->mTreeTimeCounter;
-			timerp->mCountAverage       = ((U64)timerp->mCountAverage * cur_frame + timerp->mTreeTimeCounter) / (cur_frame+1);
-			timerp->mCallHistory[hidx]  = accumulator.mCalls;
-			timerp->mCallAverage        = ((U64)timerp->mCallAverage * cur_frame + accumulator.mCalls) / (cur_frame+1);
-		}
-	}
-}
+			cur_timer->mStartTime = cur_time;
 
-// static
-void BlockTimer::resetFrame()
-{
-	if (sLog)
-	{ //output current frame counts to performance log
-
-		static S32 call_count = 0;
-		if (call_count % 100 == 0)
-		{
-			LL_DEBUGS("FastTimers") << "countsPerSecond: " << countsPerSecond() << LL_ENDL;
-			LL_DEBUGS("FastTimers") << "LLProcessorInfo().getCPUFrequency() " << LLProcessorInfo().getCPUFrequency() << LL_ENDL;
-			LL_DEBUGS("FastTimers") << "getCPUClockCount32() " << getCPUClockCount32() << LL_ENDL;
-			LL_DEBUGS("FastTimers") << "getCPUClockCount64() " << getCPUClockCount64() << LL_ENDL;
-			LL_DEBUGS("FastTimers") << "elapsed sec " << ((F64)getCPUClockCount64()) / (LLUnit<LLUnits::Hertz, F64>(LLProcessorInfo().getCPUFrequency())) << LL_ENDL;
-		}
-		call_count++;
-
-		F64 iclock_freq = 1000.0 / get_clock_count(); // good place to calculate clock frequency
-
-		F64 total_time = 0;
-		LLSD sd;
-
-		{
-			for (LLInstanceTracker<BlockTimer>::instance_iter it = LLInstanceTracker<BlockTimer>::beginInstances(), 
-					end_it = LLInstanceTracker<BlockTimer>::endInstances(); 
-				it != end_it; 
-				++it)
+			cur_data = &cur_timer->mLastTimerData;
+			cur_data->mChildTime += cumulative_time_delta;
+			if (cur_data->mTimerData)
 			{
-				BlockTimer& timer = *it;
-				TimerAccumulator& accumulator = timer.getPrimaryAccumulator();
-				sd[timer.getName()]["Time"] = (LLSD::Real) (accumulator.mSelfTimeCounter*iclock_freq);	
-				sd[timer.getName()]["Calls"] = (LLSD::Integer) accumulator.mCalls;
-				
-				// computing total time here because getting the root timer's getCountHistory
-				// doesn't work correctly on the first frame
-				total_time = total_time + accumulator.mSelfTimeCounter * iclock_freq;
+				accumulator = cur_data->mTimerData->getPrimaryAccumulator();
 			}
-		}
 
-		sd["Total"]["Time"] = (LLSD::Real) total_time;
-		sd["Total"]["Calls"] = (LLSD::Integer) 1;
-
-		{		
-			LLMutexLock lock(sLogLock);
-			sLogQueue.push(sd);
+			cur_timer = cur_timer->mLastTimerData.mCurTimer;
 		}
-	}
-
-	// reset for next frame
-	for (LLInstanceTracker<BlockTimer>::instance_iter it = LLInstanceTracker<BlockTimer>::beginInstances(),
-			end_it = LLInstanceTracker<BlockTimer>::endInstances();
-		it != end_it;
-		++it)
-	{
-		BlockTimer& timer = *it;
-		TimerAccumulator& accumulator = timer.getPrimaryAccumulator();
-		TimerTreeNode& tree_node = sCurTimerData->mTimerTreeData[timer.getIndex()];
-
-		accumulator.mSelfTimeCounter = 0;
-		accumulator.mTotalTimeCounter = 0;
-		accumulator.mCalls = 0;
-		tree_node.mLastCaller = NULL;
-		tree_node.mMoveUpTree = false;
-	}
-}
-
-//static
-void BlockTimer::reset()
-{
-	resetFrame(); // reset frame data
-
-	// walk up stack of active timers and reset start times to current time
-	// effectively zeroing out any accumulated time
-	U64 cur_time = getCPUClockCount64();
-
-	// root defined by parent pointing to self
-	CurTimerData* cur_data = sCurTimerData.get();
-	Time* cur_timer = cur_data->mCurTimer;
-	while(cur_timer && cur_timer->mLastTimerData.mCurTimer != cur_timer)
-	{
-		cur_timer->mStartTime = cur_time;
-		cur_data->mChildTime = 0;
-
-		cur_data = &cur_timer->mLastTimerData;
-		cur_timer = cur_data->mCurTimer;
-	}
 
-	// reset all history
-	{
-		for (LLInstanceTracker<BlockTimer>::instance_iter it = LLInstanceTracker<BlockTimer>::beginInstances(), 
-				end_it = LLInstanceTracker<BlockTimer>::endInstances(); 
-			it != end_it; 
-			++it)
-		{
-			BlockTimer& timer = *it;
-			if (&timer != &BlockTimer::getRootTimer()) 
-			{
-				timer.setParent(&BlockTimer::getRootTimer());
-			}
-			
-			timer.mCountAverage = 0;
-			timer.mCallAverage = 0;
-			memset(timer.mCountHistory, 0, sizeof(U64) * HISTORY_NUM);
-			memset(timer.mCallHistory, 0, sizeof(U32) * HISTORY_NUM);
-		}
+		// traverse tree in DFS post order, or bottom up
+		//for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(TimeBlock::getRootTimer());
+		//	it != end_timer_tree_bottom_up();
+		//	++it)
+		//{
+		//	TimeBlock* timerp = (*it);
+		//	TimeBlockAccumulator& accumulator = timerp->getPrimaryAccumulator();
+		//	timerp->mTreeTimeCounter = accumulator.mSelfTimeCounter;
+		//	for (child_const_iter child_it = timerp->beginChildren(); child_it != timerp->endChildren(); ++child_it)
+		//	{
+		//		timerp->mTreeTimeCounter += (*child_it)->mTreeTimeCounter;
+		//	}
+
+		//S32 cur_frame = getCurFrameIndex();
+		//if (cur_frame >= 0)
+		//{
+		//	// update timer history
+
+		//	int hidx = getCurFrameIndex() % HISTORY_NUM;
+
+		//	timerp->mCountHistory[hidx] = timerp->mTreeTimeCounter;
+		//	timerp->mCountAverage       = ((U64)timerp->mCountAverage * cur_frame + timerp->mTreeTimeCounter) / (cur_frame+1);
+		//	timerp->mCallHistory[hidx]  = accumulator.mCalls;
+		//	timerp->mCallAverage        = ((U64)timerp->mCallAverage * cur_frame + accumulator.mCalls) / (cur_frame+1);
+		//}
+		//}
 	}
-
-	sLastFrameIndex = 0;
-	sCurFrameIndex = 0;
 }
 
-U64 BlockTimer::getHistoricalCount(S32 history_index) const
-{
-	S32 history_idx = (getLastFrameIndex() + history_index) % HISTORY_NUM;
-	return mCountHistory[history_idx];
-}
-
-U32 BlockTimer::getHistoricalCalls(S32 history_index ) const
-{
-	S32 history_idx = (getLastFrameIndex() + history_index) % HISTORY_NUM;
-	return mCallHistory[history_idx];
-}
 
-std::vector<BlockTimer*>::const_iterator BlockTimer::beginChildren()
+std::vector<TimeBlock*>::const_iterator TimeBlock::beginChildren()
 { 
 	return mChildren.begin(); 
 }
 
-std::vector<BlockTimer*>::const_iterator BlockTimer::endChildren()
+std::vector<TimeBlock*>::const_iterator TimeBlock::endChildren()
 {
 	return mChildren.end();
 }
 
-std::vector<BlockTimer*>& BlockTimer::getChildren()
+std::vector<TimeBlock*>& TimeBlock::getChildren()
 {
 	return mChildren;
 }
 
 //static
-void BlockTimer::nextFrame()
+void TimeBlock::nextFrame()
 {
 	get_clock_count(); // good place to calculate clock frequency
-	U64 frame_time = BlockTimer::getCPUClockCount64();
+	U64 frame_time = TimeBlock::getCPUClockCount64();
 	if ((frame_time - sLastFrameTime) >> 8 > 0xffffffff)
 	{
 		llinfos << "Slow frame, fast timers inaccurate" << llendl;
@@ -530,31 +387,88 @@ void BlockTimer::nextFrame()
 
 	if (!sPauseHistory)
 	{
-		BlockTimer::processTimes();
+		TimeBlock::processTimes();
 		sLastFrameIndex = sCurFrameIndex++;
 	}
 	
 	// get ready for next frame
-	BlockTimer::resetFrame();
+	//void TimeBlock::resetFrame()
+	{
+		if (sLog)
+		{ //output current frame counts to performance log
+
+			static S32 call_count = 0;
+			if (call_count % 100 == 0)
+			{
+				LL_DEBUGS("FastTimers") << "countsPerSecond: " << countsPerSecond() << LL_ENDL;
+				LL_DEBUGS("FastTimers") << "LLProcessorInfo().getCPUFrequency() " << LLProcessorInfo().getCPUFrequency() << LL_ENDL;
+				LL_DEBUGS("FastTimers") << "getCPUClockCount32() " << getCPUClockCount32() << LL_ENDL;
+				LL_DEBUGS("FastTimers") << "getCPUClockCount64() " << getCPUClockCount64() << LL_ENDL;
+				LL_DEBUGS("FastTimers") << "elapsed sec " << ((F64)getCPUClockCount64()) / (LLUnit<LLUnits::Hertz, F64>(LLProcessorInfo().getCPUFrequency())) << LL_ENDL;
+			}
+			call_count++;
+
+			LLUnit<LLUnits::Seconds, F64> total_time = 0;
+			LLSD sd;
+
+			{
+				for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(), 
+					end_it = LLInstanceTracker<TimeBlock>::endInstances(); 
+					it != end_it; 
+				++it)
+				{
+					TimeBlock& timer = *it;
+					LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording();
+					sd[timer.getName()]["Time"] = (LLSD::Real) (frame_recording.getLastRecordingPeriod().getSum(timer).value());	
+					sd[timer.getName()]["Calls"] = (LLSD::Integer) (frame_recording.getLastRecordingPeriod().getSum(timer.callCount()));
+
+					// computing total time here because getting the root timer's getCountHistory
+					// doesn't work correctly on the first frame
+					total_time += frame_recording.getLastRecordingPeriod().getSum(timer);
+				}
+			}
+
+			sd["Total"]["Time"] = (LLSD::Real) total_time.value();
+			sd["Total"]["Calls"] = (LLSD::Integer) 1;
+
+			{		
+				LLMutexLock lock(sLogLock);
+				sLogQueue.push(sd);
+			}
+		}
+
+		// reset for next frame
+		for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(),
+			end_it = LLInstanceTracker<TimeBlock>::endInstances();
+			it != end_it;
+		++it)
+		{
+			TimeBlock& timer = *it;
+			TimeBlockTreeNode& tree_node = sCurTimerData->mTimerTreeData[timer.getIndex()];
+
+			tree_node.mLastCaller = NULL;
+			tree_node.mMoveUpTree = false;
+		}
+	}
 	sLastFrameTime = frame_time;
 }
 
 //static
-void Time::dumpCurTimes()
+void TimeBlock::dumpCurTimes()
 {
 	// accumulate timings, etc.
-	BlockTimer::processTimes();
+	processTimes();
 	
-	F64 clock_freq = (F64)get_clock_count();
-	F64 iclock_freq = 1000.0 / clock_freq; // clock_ticks -> milliseconds
-
 	// walk over timers in depth order and output timings
-	for(timer_tree_dfs_iterator_t it = begin_timer_tree(BlockTimer::getRootTimer());
+	for(timer_tree_dfs_iterator_t it = begin_timer_tree(TimeBlock::getRootTimer());
 		it != end_timer_tree();
 		++it)
 	{
-		BlockTimer* timerp = (*it);
-		F64 total_time_ms = ((F64)timerp->getHistoricalCount(0) * iclock_freq);
+		LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording();
+		TimeBlock* timerp = (*it);
+		LLUnit<LLUnits::Seconds, F64> total_time_ms = frame_recording.getLastRecordingPeriod().getSum(*timerp);
+		U32 num_calls = frame_recording.getLastRecordingPeriod().getSum(timerp->callCount());
+
 		// Don't bother with really brief times, keep output concise
 		if (total_time_ms < 0.1) continue;
 
@@ -564,17 +478,16 @@ void Time::dumpCurTimes()
 			out_str << "\t";
 		}
 
-
 		out_str << timerp->getName() << " " 
-			<< std::setprecision(3) << total_time_ms << " ms, "
-			<< timerp->getHistoricalCalls(0) << " calls";
+			<< std::setprecision(3) << total_time_ms.as<LLUnits::Milliseconds, F32>() << " ms, "
+			<< num_calls << " calls";
 
 		llinfos << out_str.str() << llendl;
 	}
 }
 
 //static
-void Time::writeLog(std::ostream& os)
+void TimeBlock::writeLog(std::ostream& os)
 {
 	while (!sLogQueue.empty())
 	{
@@ -585,29 +498,34 @@ void Time::writeLog(std::ostream& os)
 	}
 }
 
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// TimeBlockAccumulator
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-TimerAccumulator::TimerAccumulator() :	mSelfTimeCounter(0),
+TimeBlockAccumulator::TimeBlockAccumulator() 
+:	mSelfTimeCounter(0),
 	mTotalTimeCounter(0),
 	mCalls(0)
 {}
 
-void TimerAccumulator::addSamples( const TimerAccumulator& other )
+void TimeBlockAccumulator::addSamples( const TimeBlockAccumulator& other )
 {
 	mSelfTimeCounter += other.mSelfTimeCounter;
 	mTotalTimeCounter += other.mTotalTimeCounter;
 	mCalls += other.mCalls;
 }
 
-void TimerAccumulator::reset( const TimerAccumulator* other )
+void TimeBlockAccumulator::reset( const TimeBlockAccumulator* other )
 {
 	mTotalTimeCounter = 0;
 	mSelfTimeCounter = 0;
 	mCalls = 0;
 }
 
-TimerTreeNode::TimerTreeNode()
+TimeBlockTreeNode::TimeBlockTreeNode()
 :	mLastCaller(NULL),
 	mActiveCount(0),
 	mMoveUpTree(false)
 {}
-}
+
+} // namespace LLTrace
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 9f981480f2..e3d99a9e4b 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -40,28 +40,21 @@ namespace LLTrace
 
 struct CurTimerData
 {
-	class Time*			mCurTimer;
-	class BlockTimer*	mTimerData;
+	class BlockTimer*	mCurTimer;
+	class TimeBlock*	mTimerData;
 	U64					mChildTime;
-	TimerTreeNode*		mTimerTreeData;
+	TimeBlockTreeNode*		mTimerTreeData;
 };
 
-class Time
+class BlockTimer
 {
 public:
-	friend class BlockTimer;
-	typedef Time self_t;
-	typedef class BlockTimer DeclareTimer;
+	friend class TimeBlock;
+	typedef BlockTimer self_t;
+	typedef class TimeBlock DeclareTimer;
 
-	Time(BlockTimer& timer);
-	~Time();
-
-public:
-	// dumps current cumulative frame stats to log
-	// call nextFrame() to reset timers
-	static void dumpCurTimes();
-
-	static void writeLog(std::ostream& os);
+	BlockTimer(TimeBlock& timer);
+	~BlockTimer();
 
 private:
 
@@ -69,40 +62,41 @@ private:
 	CurTimerData	mLastTimerData;
 };
 
-// stores a "named" timer instance to be reused via multiple Time stack instances
-class BlockTimer 
-:	public TraceType<TimerAccumulator>,
-	public LLInstanceTracker<BlockTimer>
+// stores a "named" timer instance to be reused via multiple BlockTimer stack instances
+class TimeBlock 
+:	public TraceType<TimeBlockAccumulator>,
+	public LLInstanceTracker<TimeBlock>
 {
 public:
-	BlockTimer(const char* name, bool open = false, BlockTimer* parent = &getRootTimer());
-	~BlockTimer();
+	TimeBlock(const char* name, bool open = false, TimeBlock* parent = &getRootTimer());
 
 	enum { HISTORY_NUM = 300 };
 
-	BlockTimer* getParent() const { return mParent; }
-	void setParent(BlockTimer* parent);
+	TimeBlock* getParent() const { return mParent; }
+	void setParent(TimeBlock* parent);
 	S32 getDepth();
 
-	typedef std::vector<BlockTimer*>::const_iterator child_const_iter;
+	typedef std::vector<TimeBlock*>::const_iterator child_const_iter;
 	child_const_iter beginChildren();
 	child_const_iter endChildren();
-	std::vector<BlockTimer*>& getChildren();
+	std::vector<TimeBlock*>& getChildren();
 
 	void setCollapsed(bool collapsed)	{ mCollapsed = collapsed; }
 	bool getCollapsed() const			{ return mCollapsed; }
 
-	U32 getCountAverage() const { return mCountAverage; }
-	U32 getCallAverage() const	{ return mCallAverage; }
-
-	U64 getHistoricalCount(S32 history_index = 0) const;
-	U32 getHistoricalCalls(S32 history_index = 0) const;
+	TraceType<TimeBlockAccumulator::CallCountAspect>& callCount() 
+	{ 
+		return static_cast<TraceType<TimeBlockAccumulator::CallCountAspect>&>(*(TraceType<TimeBlockAccumulator>*)this);
+	}
 
-	static BlockTimer& getRootTimer();
+	static TimeBlock& getRootTimer();
 	static void pushLog(LLSD sd);
 	static void setLogLock(LLMutex* mutex);
-	friend class Time;
+	static void writeLog(std::ostream& os);
 
+	// dumps current cumulative frame stats to log
+	// call nextFrame() to reset timers
+	static void dumpCurTimes();
 
 	//////////////////////////////////////////////////////////////////////////////
 	//
@@ -126,14 +120,14 @@ public:
 	//#undef _interlockedbittestandset
 	//#undef _interlockedbittestandreset
 
-	//inline U32 BlockTimer::getCPUClockCount32()
+	//inline U32 TimeBlock::getCPUClockCount32()
 	//{
 	//	U64 time_stamp = __rdtsc();
 	//	return (U32)(time_stamp >> 8);
 	//}
 	//
 	//// return full timer value, *not* shifted by 8 bits
-	//inline U64 BlockTimer::getCPUClockCount64()
+	//inline U64 TimeBlock::getCPUClockCount64()
 	//{
 	//	return __rdtsc();
 	//}
@@ -242,35 +236,16 @@ public:
 
 	static U64 countsPerSecond();
 
-	// recursive call to gather total time from children
-	static void accumulateTimings();
-
 	// updates cumulative times and hierarchy,
 	// can be called multiple times in a frame, at any point
 	static void processTimes();
 
-	static void buildHierarchy();
-	static void resetFrame();
-	static void reset();
 	// call this once a frame to reset timers
 	static void nextFrame();
-	static S32 getLastFrameIndex() { return sLastFrameIndex; }
-	static S32 getCurFrameIndex() { return sCurFrameIndex; }
-
-
-
-	// sum of recorded self time and tree time of all children timers (might not match actual recorded time of children if topology is incomplete
-	U64 						mTreeTimeCounter; 
-
-	U64 						mCountAverage;
-	U32							mCallAverage;
-
-	U64*						mCountHistory;
-	U32*						mCallHistory;
 
-	// tree structure
-	BlockTimer*					mParent;				// BlockTimer of caller(parent)
-	std::vector<BlockTimer*>	mChildren;
+	// tree structure, only updated from master trace thread
+	TimeBlock*					mParent;				// TimeBlock of caller(parent)
+	std::vector<TimeBlock*>	mChildren;
 	bool						mCollapsed,				// don't show children
 								mNeedsSorting;			// sort children whenever child added
 
@@ -288,13 +263,13 @@ public:
 
 };
 
-LL_FORCE_INLINE Time::Time(BlockTimer& timer)
+LL_FORCE_INLINE BlockTimer::BlockTimer(TimeBlock& timer)
 {
 #if FAST_TIMER_ON
-	mStartTime = BlockTimer::getCPUClockCount64();
+	mStartTime = TimeBlock::getCPUClockCount64();
 
-	CurTimerData* cur_timer_data = BlockTimer::sCurTimerData.get();
-	TimerTreeNode& tree_node = cur_timer_data->mTimerTreeData[timer.getIndex()];
+	CurTimerData* cur_timer_data = TimeBlock::sCurTimerData.get();
+	TimeBlockTreeNode& tree_node = cur_timer_data->mTimerTreeData[timer.getIndex()];
 	tree_node.mActiveCount++;
 	// keep current parent as long as it is active when we are
 	tree_node.mMoveUpTree |= (cur_timer_data->mTimerTreeData[timer.mParent->getIndex()].mActiveCount == 0);
@@ -308,13 +283,13 @@ LL_FORCE_INLINE Time::Time(BlockTimer& timer)
 #endif
 }
 
-LL_FORCE_INLINE Time::~Time()
+LL_FORCE_INLINE BlockTimer::~BlockTimer()
 {
 #if FAST_TIMER_ON
-	U64 total_time = BlockTimer::getCPUClockCount64() - mStartTime;
-	CurTimerData* cur_timer_data = BlockTimer::sCurTimerData.get();
-	TimerAccumulator& accumulator = cur_timer_data->mTimerData->getPrimaryAccumulator();
-	TimerTreeNode& tree_node = cur_timer_data->mTimerTreeData[cur_timer_data->mTimerData->getIndex()];
+	U64 total_time = TimeBlock::getCPUClockCount64() - mStartTime;
+	CurTimerData* cur_timer_data = TimeBlock::sCurTimerData.get();
+	TimeBlockAccumulator& accumulator = cur_timer_data->mTimerData->getPrimaryAccumulator();
+	TimeBlockTreeNode& tree_node = cur_timer_data->mTimerTreeData[cur_timer_data->mTimerData->getIndex()];
 
 	accumulator.mCalls++;
 	accumulator.mSelfTimeCounter += total_time - cur_timer_data->mChildTime;
@@ -328,12 +303,12 @@ LL_FORCE_INLINE Time::~Time()
 	// we are only tracking self time, so subtract our total time delta from parents
 	mLastTimerData.mChildTime += total_time;
 
-	*BlockTimer::sCurTimerData = mLastTimerData;
+	*TimeBlock::sCurTimerData = mLastTimerData;
 #endif
 }
 
 }
 
-typedef LLTrace::Time LLFastTimer; 
+typedef LLTrace::BlockTimer LLFastTimer; 
 
 #endif // LL_LLFASTTIMER_H
diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp
index 43d98be47b..aaacbfb599 100644
--- a/indra/llcommon/llmetricperformancetester.cpp
+++ b/indra/llcommon/llmetricperformancetester.cpp
@@ -91,7 +91,7 @@ LLMetricPerformanceTesterBasic* LLMetricPerformanceTesterBasic::getTester(std::s
 // Return TRUE if this metric is requested or if the general default "catch all" metric is requested
 BOOL LLMetricPerformanceTesterBasic::isMetricLogRequested(std::string name)
 {
-	return (LLTrace::BlockTimer::sMetricLog && ((LLTrace::BlockTimer::sLogName == name) || (LLTrace::BlockTimer::sLogName == DEFAULT_METRIC_NAME)));
+	return (LLTrace::TimeBlock::sMetricLog && ((LLTrace::TimeBlock::sLogName == name) || (LLTrace::TimeBlock::sLogName == DEFAULT_METRIC_NAME)));
 }
 
 /*static*/ 
@@ -194,7 +194,7 @@ void LLMetricPerformanceTesterBasic::preOutputTestResults(LLSD* sd)
 
 void LLMetricPerformanceTesterBasic::postOutputTestResults(LLSD* sd)
 {
-	LLTrace::BlockTimer::pushLog(*sd);
+	LLTrace::TimeBlock::pushLog(*sd);
 }
 
 void LLMetricPerformanceTesterBasic::outputTestResults() 
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index 3e43a85e80..9e275da647 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -37,7 +37,7 @@
 
 #include <list>
 
-#define LL_RECORD_BLOCK_TIME(block_timer) LLTrace::BlockTimer::Recorder LL_GLUE_TOKENS(block_time_recorder, __COUNTER__)(block_timer);
+#define LL_RECORD_BLOCK_TIME(block_timer) LLTrace::TimeBlock::Recorder LL_GLUE_TOKENS(block_time_recorder, __COUNTER__)(block_timer);
 
 namespace LLTrace
 {
@@ -213,10 +213,10 @@ namespace LLTrace
 	:	 public LLInstanceTracker<TraceType<ACCUMULATOR>, std::string>
 	{
 	public:
-		TraceType(const char* name, const char* description = NULL)
+		TraceType(const char* name, const char* description = "")
 		:	LLInstanceTracker(name),
 			mName(name),
-			mDescription(description ? description : "")
+			mDescription(description)	
 		{
 			mAccumulatorIndex = AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer().reserveSlot();
 		}
@@ -392,26 +392,43 @@ namespace LLTrace
 		U32	mNumSamples;
 	};
 
-	class TimerAccumulator
+	class TimeBlockAccumulator
 	{
 	public:
-		TimerAccumulator();
-		void addSamples(const TimerAccumulator& other);
-		void reset(const TimerAccumulator* other);
+		typedef LLUnit<LLUnits::Seconds, F64> value_t;
+
+		// fake class that allows us to view call count aspect of timeblock accumulator
+		struct CallCountAspect 
+		{
+			typedef U32 value_t;
+		};
+
+		TimeBlockAccumulator();
+		void addSamples(const TimeBlockAccumulator& other);
+		void reset(const TimeBlockAccumulator* other);
 
 		//
 		// members
 		//
 		U64 						mSelfTimeCounter,
 									mTotalTimeCounter;
-		U32 						mCalls;
+		U32 mCalls;
+	};
+
+	template<>
+	class TraceType<TimeBlockAccumulator::CallCountAspect>
+	:	public TraceType<TimeBlockAccumulator>
+	{
+		TraceType(const char* name, const char* description = "")
+		:	TraceType<TimeBlockAccumulator>(name, description)
+		{}
 	};
 
-	class TimerTreeNode
+	class TimeBlockTreeNode
 	{
 	public:
-		TimerTreeNode();
-		class BlockTimer*			mLastCaller;	// used to bootstrap tree construction
+		TimeBlockTreeNode();
+		class TimeBlock*			mLastCaller;	// used to bootstrap tree construction
 		U16							mActiveCount;	// number of timers with this ID active on stack
 		bool						mMoveUpTree;	// needs to be moved up the tree of timers at the end of frame
 	};
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
index ff3ae1e553..0d4d07faf6 100644
--- a/indra/llcommon/lltracerecording.cpp
+++ b/indra/llcommon/lltracerecording.cpp
@@ -44,7 +44,7 @@ Recording::Recording()
 	mMeasurementsFloat(new AccumulatorBuffer<MeasurementAccumulator<F64> >()),
 	mCounts(new AccumulatorBuffer<CountAccumulator<S64> >()),
 	mMeasurements(new AccumulatorBuffer<MeasurementAccumulator<S64> >()),
-	mStackTimers(new AccumulatorBuffer<TimerAccumulator>())
+	mStackTimers(new AccumulatorBuffer<TimeBlockAccumulator>())
 {}
 
 Recording::Recording( const Recording& other )
@@ -143,16 +143,27 @@ void Recording::appendRecording( const Recording& other )
 	mElapsedSeconds += other.mElapsedSeconds;
 }
 
-LLUnit<LLUnits::Seconds, F64> Recording::getSum(const TraceType<TimerAccumulator>& stat) const
+LLUnit<LLUnits::Seconds, F64> Recording::getSum(const TraceType<TimeBlockAccumulator>& stat) const
 {
-	return (F64)(*mStackTimers)[stat.getIndex()].mSelfTimeCounter / (F64)LLTrace::BlockTimer::countsPerSecond();
+	return (F64)(*mStackTimers)[stat.getIndex()].mSelfTimeCounter / (F64)LLTrace::TimeBlock::countsPerSecond();
 }
 
-LLUnit<LLUnits::Seconds, F64> Recording::getPerSec(const TraceType<TimerAccumulator>& stat) const
+U32 Recording::getSum(const TraceType<TimeBlockAccumulator::CallCountAspect>& stat) const
 {
-	return (F64)(*mStackTimers)[stat.getIndex()].mSelfTimeCounter / ((F64)LLTrace::BlockTimer::countsPerSecond() * mElapsedSeconds);
+	return (*mStackTimers)[stat.getIndex()].mCalls;
 }
 
+LLUnit<LLUnits::Seconds, F64> Recording::getPerSec(const TraceType<TimeBlockAccumulator>& stat) const
+{
+	return (F64)(*mStackTimers)[stat.getIndex()].mSelfTimeCounter / ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds);
+}
+
+F32 Recording::getPerSec(const TraceType<TimeBlockAccumulator::CallCountAspect>& stat) const
+{
+	return (F32)(*mStackTimers)[stat.getIndex()].mCalls / mElapsedSeconds;
+}
+
+
 F64 Recording::getSum( const TraceType<CountAccumulator<F64> >& stat ) const
 {
 	return (*mCountsFloat)[stat.getIndex()].getSum();
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h
index 0adea2663b..efed3f662e 100644
--- a/indra/llcommon/lltracerecording.h
+++ b/indra/llcommon/lltracerecording.h
@@ -119,8 +119,10 @@ namespace LLTrace
 		void update();
 
 		// Timer accessors
-		LLUnit<LLUnits::Seconds, F64> getSum(const TraceType<TimerAccumulator>& stat) const;
-		LLUnit<LLUnits::Seconds, F64> getPerSec(const TraceType<TimerAccumulator>& stat) const;
+		LLUnit<LLUnits::Seconds, F64> getSum(const TraceType<TimeBlockAccumulator>& stat) const;
+		U32 getSum(const TraceType<TimeBlockAccumulator::CallCountAspect>& stat) const;
+		LLUnit<LLUnits::Seconds, F64> getPerSec(const TraceType<TimeBlockAccumulator>& stat) const;
+		F32 getPerSec(const TraceType<TimeBlockAccumulator::CallCountAspect>& stat) const;
 
 		// Count accessors
 		F64 getSum(const TraceType<CountAccumulator<F64> >& stat) const;
@@ -221,7 +223,7 @@ namespace LLTrace
 		LLCopyOnWritePointer<AccumulatorBuffer<MeasurementAccumulator<F64> > >	mMeasurementsFloat;
 		LLCopyOnWritePointer<AccumulatorBuffer<CountAccumulator<S64> > >		mCounts;
 		LLCopyOnWritePointer<AccumulatorBuffer<MeasurementAccumulator<S64> > >	mMeasurements;
-		LLCopyOnWritePointer<AccumulatorBuffer<TimerAccumulator> >				mStackTimers;
+		LLCopyOnWritePointer<AccumulatorBuffer<TimeBlockAccumulator> >				mStackTimers;
 
 		LLTimer			mSamplingTimer;
 		F64				mElapsedSeconds;
diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp
index 0a2d79cf3a..16235473ee 100644
--- a/indra/llcommon/lltracethreadrecorder.cpp
+++ b/indra/llcommon/lltracethreadrecorder.cpp
@@ -42,14 +42,14 @@ ThreadRecorder::ThreadRecorder()
 	mFullRecording.start();
 
 	mRootTimerData = new CurTimerData();
-	mRootTimerData->mTimerData = &BlockTimer::getRootTimer();
-	mRootTimerData->mTimerTreeData = new TimerTreeNode[AccumulatorBuffer<TimerAccumulator>::getDefaultBuffer().size()];
-	BlockTimer::sCurTimerData = mRootTimerData;
+	mRootTimerData->mTimerData = &TimeBlock::getRootTimer();
+	mRootTimerData->mTimerTreeData = new TimeBlockTreeNode[AccumulatorBuffer<TimeBlockAccumulator>::getDefaultBuffer().size()];
+	TimeBlock::sCurTimerData = mRootTimerData;
 
-	mRootTimer = new Time(BlockTimer::getRootTimer());
+	mRootTimer = new BlockTimer(TimeBlock::getRootTimer());
 	mRootTimerData->mCurTimer = mRootTimer;
 
-	mRootTimerData->mTimerTreeData[BlockTimer::getRootTimer().getIndex()].mActiveCount = 1;
+	mRootTimerData->mTimerTreeData[TimeBlock::getRootTimer().getIndex()].mActiveCount = 1;
 }
 
 ThreadRecorder::~ThreadRecorder()
@@ -61,7 +61,7 @@ ThreadRecorder::~ThreadRecorder()
 		mActiveRecordings.front().mTargetRecording->stop();
 	}
 	get_thread_recorder() = NULL;
-	BlockTimer::sCurTimerData = NULL;
+	TimeBlock::sCurTimerData = NULL;
 	delete [] mRootTimerData->mTimerTreeData;
 	delete mRootTimerData;
 }
diff --git a/indra/llcommon/lltracethreadrecorder.h b/indra/llcommon/lltracethreadrecorder.h
index 277a468a40..102b980e44 100644
--- a/indra/llcommon/lltracethreadrecorder.h
+++ b/indra/llcommon/lltracethreadrecorder.h
@@ -64,7 +64,7 @@ namespace LLTrace
 		std::list<ActiveRecording>	mActiveRecordings;
 
 		struct CurTimerData*	mRootTimerData;
-		class Time*				mRootTimer;
+		class BlockTimer*				mRootTimer;
 	};
 
 	class LL_COMMON_API MasterThreadRecorder : public ThreadRecorder
diff --git a/indra/llcommon/llunit.h b/indra/llcommon/llunit.h
index 54902b6322..01e9eb751d 100644
--- a/indra/llcommon/llunit.h
+++ b/indra/llcommon/llunit.h
@@ -180,23 +180,23 @@ struct LLUnitStrict : public LLUnit<UNIT_TYPE, STORAGE_TYPE>
 	typedef typename LLUnit<UNIT_TYPE, STORAGE_TYPE>::storage_t storage_t;
 
 	explicit LLUnitStrict(storage_t value = storage_t())
-	:	LLUnit(value)
+	:	LLUnit<UNIT_TYPE, STORAGE_TYPE>(value)
 	{}
 
 	template<typename OTHER_UNIT, typename OTHER_STORAGE>
 	LLUnitStrict(LLUnit<OTHER_UNIT, OTHER_STORAGE> other)
-	:	LLUnit(convert(other))
+	:	LLUnit<UNIT_TYPE, STORAGE_TYPE>(convert(other))
 	{}
 
 	LLUnitStrict(self_t& other)
-	:	LLUnit(other)
+	:	LLUnit<UNIT_TYPE, STORAGE_TYPE>(other)
 	{}
 
 
 private:
 	operator storage_t() const
 	{
-		return value();
+		return LLUnit<UNIT_TYPE, STORAGE_TYPE>::value();
 	}
 };
 
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index b9bdb7cd08..c986954867 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -592,7 +592,7 @@ public:
 		
 		while (!LLAppViewer::instance()->isQuitting())
 		{
-			LLFastTimer::writeLog(os);
+			LLTrace::TimeBlock::writeLog(os);
 			os.flush();
 			ms_sleep(32);
 		}
@@ -680,7 +680,6 @@ bool LLAppViewer::init()
 	// into the log files during normal startup until AFTER
 	// we run the "program crashed last time" error handler below.
 	//
-	LLTrace::BlockTimer::reset();
 
 	// initialize SSE options
 	LLVector4a::initClass();
@@ -1234,7 +1233,7 @@ bool LLAppViewer::mainLoop()
 	while (!LLApp::isExiting())
 	{
 		LLFastTimer _(FTM_FRAME);
-		LLTrace::BlockTimer::nextFrame(); 
+		LLTrace::TimeBlock::nextFrame(); 
 		LLTrace::get_frame_recording().nextPeriod();
 
 		LLTrace::getMasterThreadRecorder().pullFromSlaveThreads();
@@ -1565,9 +1564,9 @@ bool LLAppViewer::cleanup()
 	if (LLFastTimerView::sAnalyzePerformance)
 	{
 		llinfos << "Analyzing performance" << llendl;
-		std::string baseline_name = LLTrace::BlockTimer::sLogName + "_baseline.slp";
-		std::string current_name  = LLTrace::BlockTimer::sLogName + ".slp"; 
-		std::string report_name   = LLTrace::BlockTimer::sLogName + "_report.csv";
+		std::string baseline_name = LLTrace::TimeBlock::sLogName + "_baseline.slp";
+		std::string current_name  = LLTrace::TimeBlock::sLogName + ".slp"; 
+		std::string report_name   = LLTrace::TimeBlock::sLogName + "_report.csv";
 
 		LLFastTimerView::doAnalysis(
 			gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baseline_name),
@@ -1926,9 +1925,9 @@ bool LLAppViewer::cleanup()
 	{
 		llinfos << "Analyzing performance" << llendl;
 		
-		std::string baseline_name = LLTrace::BlockTimer::sLogName + "_baseline.slp";
-		std::string current_name  = LLTrace::BlockTimer::sLogName + ".slp"; 
-		std::string report_name   = LLTrace::BlockTimer::sLogName + "_report.csv";
+		std::string baseline_name = LLTrace::TimeBlock::sLogName + "_baseline.slp";
+		std::string current_name  = LLTrace::TimeBlock::sLogName + ".slp"; 
+		std::string report_name   = LLTrace::TimeBlock::sLogName + "_report.csv";
 
 		LLFastTimerView::doAnalysis(
 			gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baseline_name),
@@ -2051,10 +2050,10 @@ bool LLAppViewer::initThreads()
 													enable_threads && true,
 													app_metrics_qa_mode);	
 
-	if (LLTrace::BlockTimer::sLog || LLTrace::BlockTimer::sMetricLog)
+	if (LLTrace::TimeBlock::sLog || LLTrace::TimeBlock::sMetricLog)
 	{
-		LLTrace::BlockTimer::setLogLock(new LLMutex(NULL));
-		mFastTimerLogThread = new LLFastTimerLogThread(LLTrace::BlockTimer::sLogName);
+		LLTrace::TimeBlock::setLogLock(new LLMutex(NULL));
+		mFastTimerLogThread = new LLFastTimerLogThread(LLTrace::TimeBlock::sLogName);
 		mFastTimerLogThread->start();
 	}
 
@@ -2463,13 +2462,13 @@ bool LLAppViewer::initConfiguration()
 
 	if (clp.hasOption("logperformance"))
 	{
-		LLTrace::BlockTimer::sLog = true;
-		LLTrace::BlockTimer::sLogName = std::string("performance");		
+		LLTrace::TimeBlock::sLog = true;
+		LLTrace::TimeBlock::sLogName = std::string("performance");		
 	}
 	
 	if (clp.hasOption("logmetrics"))
  	{
- 		LLTrace::BlockTimer::sMetricLog = true ;
+ 		LLTrace::TimeBlock::sMetricLog = true ;
 		// '--logmetrics' can be specified with a named test metric argument so the data gathering is done only on that test
 		// In the absence of argument, every metric is gathered (makes for a rather slow run and hard to decipher report...)
 		std::string test_name = clp.getOption("logmetrics")[0];
@@ -2477,11 +2476,11 @@ bool LLAppViewer::initConfiguration()
 		if (test_name == "")
 		{
 			llwarns << "No '--logmetrics' argument given, will output all metrics to " << DEFAULT_METRIC_NAME << llendl;
-			LLTrace::BlockTimer::sLogName = DEFAULT_METRIC_NAME;
+			LLTrace::TimeBlock::sLogName = DEFAULT_METRIC_NAME;
 		}
 		else
 		{
-			LLTrace::BlockTimer::sLogName = test_name;
+			LLTrace::TimeBlock::sLogName = test_name;
 		}
  	}
 
diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp
index 6aca8f4426..acf3799f27 100644
--- a/indra/newview/llfasttimerview.cpp
+++ b/indra/newview/llfasttimerview.cpp
@@ -57,21 +57,19 @@
 static const S32 MAX_VISIBLE_HISTORY = 10;
 static const S32 LINE_GRAPH_HEIGHT = 240;
 
-//static const int FTV_DISPLAY_NUM  = (sizeof(ft_display_table)/sizeof(ft_display_table[0]));
-static S32 FTV_NUM_TIMERS;
 const S32 FTV_MAX_DEPTH = 8;
 
-std::vector<LLTrace::BlockTimer*> ft_display_idx; // line of table entry for display purposes (for collapse)
+std::vector<LLTrace::TimeBlock*> ft_display_idx; // line of table entry for display purposes (for collapse)
 
-typedef LLTreeDFSIter<LLTrace::BlockTimer, LLTrace::BlockTimer::child_const_iter> timer_tree_iterator_t;
+typedef LLTreeDFSIter<LLTrace::TimeBlock, LLTrace::TimeBlock::child_const_iter> timer_tree_iterator_t;
 
 BOOL LLFastTimerView::sAnalyzePerformance = FALSE;
 
-static timer_tree_iterator_t begin_timer_tree(LLTrace::BlockTimer& id) 
+static timer_tree_iterator_t begin_timer_tree(LLTrace::TimeBlock& id) 
 { 
 	return timer_tree_iterator_t(&id, 
-							boost::bind(boost::mem_fn(&LLTrace::BlockTimer::beginChildren), _1), 
-							boost::bind(boost::mem_fn(&LLTrace::BlockTimer::endChildren), _1));
+							boost::bind(boost::mem_fn(&LLTrace::TimeBlock::beginChildren), _1), 
+							boost::bind(boost::mem_fn(&LLTrace::TimeBlock::endChildren), _1));
 }
 
 static timer_tree_iterator_t end_timer_tree() 
@@ -81,29 +79,25 @@ static timer_tree_iterator_t end_timer_tree()
 
 LLFastTimerView::LLFastTimerView(const LLSD& key)
 :	LLFloater(key),
-	mHoverTimer(NULL)
-{
-	mDisplayMode = 0;
-	mAvgCountTotal = 0;
-	mMaxCountTotal = 0;
-	mDisplayCenter = ALIGN_CENTER;
-	mDisplayCalls = 0;
-	mDisplayHz = 0;
-	mScrollIndex = 0;
-	mHoverID = NULL;
-	mHoverBarIndex = -1;
-	FTV_NUM_TIMERS = LLInstanceTracker<LLTrace::BlockTimer>::instanceCount();
-	mPrintStats = -1;	
-}
+	mHoverTimer(NULL),
+	mDisplayMode(0),
+	mDisplayCenter(ALIGN_CENTER),
+	mDisplayCalls(false),
+	mDisplayHz(false),
+	mScrollIndex(0),
+	mHoverID(NULL),
+	mHoverBarIndex(-1),
+	mPrintStats(-1)
+{}
 
 void LLFastTimerView::onPause()
 {
-	LLTrace::BlockTimer::sPauseHistory = !LLTrace::BlockTimer::sPauseHistory;
+	LLTrace::TimeBlock::sPauseHistory = !LLTrace::TimeBlock::sPauseHistory;
 	// reset scroll to bottom when unpausing
-	if (!LLTrace::BlockTimer::sPauseHistory)
+	if (!LLTrace::TimeBlock::sPauseHistory)
 	{
 		mScrollIndex = 0;
-		LLTrace::BlockTimer::sResetHistory = true;
+		LLTrace::TimeBlock::sResetHistory = true;
 		getChild<LLButton>("pause_btn")->setLabel(getString("pause"));
 	}
 	else
@@ -139,13 +133,13 @@ BOOL LLFastTimerView::handleRightMouseDown(S32 x, S32 y, MASK mask)
 	{
 		S32 bar_idx = MAX_VISIBLE_HISTORY - ((y - mBarRect.mBottom) * (MAX_VISIBLE_HISTORY + 2) / mBarRect.getHeight());
 		bar_idx = llclamp(bar_idx, 0, MAX_VISIBLE_HISTORY);
-		mPrintStats = LLTrace::BlockTimer::HISTORY_NUM - mScrollIndex - bar_idx;
+		mPrintStats = LLTrace::TimeBlock::HISTORY_NUM - mScrollIndex - bar_idx;
 		return TRUE;
 	}
 	return LLFloater::handleRightMouseDown(x, y, mask);
 }
 
-LLTrace::BlockTimer* LLFastTimerView::getLegendID(S32 y)
+LLTrace::TimeBlock* LLFastTimerView::getLegendID(S32 y)
 {
 	S32 idx = (getRect().getHeight() - y) / (LLFontGL::getFontMonospace()->getLineHeight()+2) - 5;
 
@@ -172,7 +166,7 @@ BOOL LLFastTimerView::handleMouseDown(S32 x, S32 y, MASK mask)
 {
 	if (x < mBarRect.mLeft) 
 	{
-		LLTrace::BlockTimer* idp = getLegendID(y);
+		LLTrace::TimeBlock* idp = getLegendID(y);
 		if (idp)
 		{
 			idp->setCollapsed(!idp->getCollapsed());
@@ -223,19 +217,21 @@ BOOL LLFastTimerView::handleMouseUp(S32 x, S32 y, MASK mask)
 
 BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask)
 {
+	LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording();
+
 	if (hasMouseCapture())
 	{
 		F32 lerp = llclamp(1.f - (F32) (x - mGraphRect.mLeft) / (F32) mGraphRect.getWidth(), 0.f, 1.f);
-		mScrollIndex = llround( lerp * (F32)(LLTrace::BlockTimer::HISTORY_NUM - MAX_VISIBLE_HISTORY));
-		mScrollIndex = llclamp(	mScrollIndex, 0, LLTrace::BlockTimer::getLastFrameIndex());
+		mScrollIndex = llround( lerp * (F32)(LLTrace::TimeBlock::HISTORY_NUM - MAX_VISIBLE_HISTORY));
+		mScrollIndex = llclamp(	mScrollIndex, 0, frame_recording.getNumPeriods());
 		return TRUE;
 	}
 	mHoverTimer = NULL;
 	mHoverID = NULL;
 
-	if(LLTrace::BlockTimer::sPauseHistory && mBarRect.pointInRect(x, y))
+	if(LLTrace::TimeBlock::sPauseHistory && mBarRect.pointInRect(x, y))
 	{
-		mHoverBarIndex = llmin(LLTrace::BlockTimer::getCurFrameIndex() - 1, 
+		mHoverBarIndex = llmin(LLTrace::get_frame_recording().getNumPeriods() - 1, 
 								MAX_VISIBLE_HISTORY - ((y - mBarRect.mBottom) * (MAX_VISIBLE_HISTORY + 2) / mBarRect.getHeight()));
 		if (mHoverBarIndex == 0)
 		{
@@ -279,7 +275,7 @@ BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask)
 	}
 	else if (x < mBarRect.mLeft) 
 	{
-		LLTrace::BlockTimer* timer_id = getLegendID(y);
+		LLTrace::TimeBlock* timer_id = getLegendID(y);
 		if (timer_id)
 		{
 			mHoverID = timer_id;
@@ -290,28 +286,28 @@ BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask)
 }
 
 
-static std::string get_tooltip(LLTrace::BlockTimer& timer, S32 history_index = -1)
+static std::string get_tooltip(LLTrace::TimeBlock& timer, S32 history_index = -1)
 {
-	F64 ms_multiplier = 1000.0 / (F64)LLTrace::BlockTimer::countsPerSecond();
+	F64 ms_multiplier = 1000.0 / (F64)LLTrace::TimeBlock::countsPerSecond();
 
-	LLTrace::PeriodicRecording& frame_stats = LLTrace::get_frame_recording();
+	LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording();
 
 	std::string tooltip;
 	if (history_index < 0)
 	{
 		// by default, show average number of call
-		tooltip = llformat("%s (%d ms, %d calls)", timer.getName().c_str(), (S32)(frame_stats.getPeriodMean(timer) * ms_multiplier), (S32)timer.getCallAverage());
+		tooltip = llformat("%s (%d ms, %d calls)", timer.getName().c_str(), (S32)(frame_recording.getPeriodMean(timer) * ms_multiplier), (S32)frame_recording.getPeriodMean(timer.callCount()));
 	}
 	else
 	{
-		tooltip = llformat("%s (%d ms, %d calls)", timer.getName().c_str(), (S32)(frame_stats.getPrevRecordingPeriod(history_index).getSum(timer) * ms_multiplier), (S32)timer.getHistoricalCalls(history_index));
+		tooltip = llformat("%s (%d ms, %d calls)", timer.getName().c_str(), (S32)(frame_recording.getPrevRecordingPeriod(history_index).getSum(timer) * ms_multiplier), (S32)frame_recording.getPrevRecordingPeriod(history_index).getSum(timer.callCount()));
 	}
 	return tooltip;
 }
 
 BOOL LLFastTimerView::handleToolTip(S32 x, S32 y, MASK mask)
 {
-	if(LLTrace::BlockTimer::sPauseHistory && mBarRect.pointInRect(x, y))
+	if(LLTrace::TimeBlock::sPauseHistory && mBarRect.pointInRect(x, y))
 	{
 		// tooltips for timer bars
 		if (mHoverTimer)
@@ -319,7 +315,7 @@ BOOL LLFastTimerView::handleToolTip(S32 x, S32 y, MASK mask)
 			LLRect screen_rect;
 			localRectToScreen(mToolTipRect, &screen_rect);
 
-			std::string tooltip = get_tooltip(*mHoverTimer, LLTrace::BlockTimer::HISTORY_NUM - mScrollIndex - mHoverBarIndex);
+			std::string tooltip = get_tooltip(*mHoverTimer, LLTrace::TimeBlock::HISTORY_NUM - mScrollIndex - mHoverBarIndex);
 
 			LLToolTipMgr::instance().show(LLToolTip::Params()
 				.message(tooltip)
@@ -334,7 +330,7 @@ BOOL LLFastTimerView::handleToolTip(S32 x, S32 y, MASK mask)
 		// tooltips for timer legend
 		if (x < mBarRect.mLeft) 
 		{
-			LLTrace::BlockTimer* idp = getLegendID(y);
+			LLTrace::TimeBlock* idp = getLegendID(y);
 			if (idp)
 			{
 				LLToolTipMgr::instance().show(get_tooltip(*idp));
@@ -349,26 +345,27 @@ BOOL LLFastTimerView::handleToolTip(S32 x, S32 y, MASK mask)
 
 BOOL LLFastTimerView::handleScrollWheel(S32 x, S32 y, S32 clicks)
 {
-	LLTrace::BlockTimer::sPauseHistory = TRUE;
+	LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording();
+
+	LLTrace::TimeBlock::sPauseHistory = TRUE;
 	mScrollIndex = llclamp(	mScrollIndex + clicks,
 							0,
-							llmin(LLTrace::BlockTimer::getLastFrameIndex(), (S32)LLTrace::BlockTimer::HISTORY_NUM - MAX_VISIBLE_HISTORY));
+							llmin(frame_recording.getNumPeriods(), (S32)LLTrace::TimeBlock::HISTORY_NUM - MAX_VISIBLE_HISTORY));
 	return TRUE;
 }
 
-static LLTrace::BlockTimer FTM_RENDER_TIMER("Timers", true);
+static LLTrace::TimeBlock FTM_RENDER_TIMER("Timers", true);
 
-static std::map<LLTrace::BlockTimer*, LLColor4> sTimerColors;
+static std::map<LLTrace::TimeBlock*, LLColor4> sTimerColors;
 
 void LLFastTimerView::draw()
 {
 	LLFastTimer t(FTM_RENDER_TIMER);
-	
+
+	LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording();
+
 	std::string tdesc;
 
-	F64 clock_freq = (F64)LLTrace::BlockTimer::countsPerSecond();
-	F64 iclock_freq = 1000.0 / clock_freq;
-	
 	S32 margin = 10;
 	S32 height = getRect().getHeight();
 	S32 width = getRect().getWidth();
@@ -422,7 +419,7 @@ void LLFastTimerView::draw()
 		y -= (texth + 2);
 	}
 
-	S32 histmax = llmin(LLTrace::BlockTimer::getLastFrameIndex()+1, MAX_VISIBLE_HISTORY);
+	S32 histmax = llmin(frame_recording.getNumPeriods()+1, MAX_VISIBLE_HISTORY);
 		
 	// Draw the legend
 	xleft = margin;
@@ -438,7 +435,7 @@ void LLFastTimerView::draw()
 		it != timer_tree_iterator_t();
 		++it)
 	{
-		LLTrace::BlockTimer* idp = (*it);
+		LLTrace::TimeBlock* idp = (*it);
 
 		const F32 HUE_INCREMENT = 0.23f;
 		hue = fmodf(hue + HUE_INCREMENT, 1.f);
@@ -458,12 +455,12 @@ void LLFastTimerView::draw()
 		LLLocalClipRect clip(LLRect(margin, y, LEGEND_WIDTH, margin));
 		S32 cur_line = 0;
 		ft_display_idx.clear();
-		std::map<LLTrace::BlockTimer*, S32> display_line;
+		std::map<LLTrace::TimeBlock*, S32> display_line;
 		for (timer_tree_iterator_t it = begin_timer_tree(getFrameTimer());
 			it != timer_tree_iterator_t();
 			++it)
 		{
-			LLTrace::BlockTimer* idp = (*it);
+			LLTrace::TimeBlock* idp = (*it);
 			display_line[idp] = cur_line;
 			ft_display_idx.push_back(idp);
 			cur_line++;
@@ -479,20 +476,18 @@ void LLFastTimerView::draw()
 			}
 			gl_rect_2d(left - scale_offset, top + scale_offset, right + scale_offset, bottom - scale_offset, sTimerColors[idp]);
 
-			F32 ms = 0;
+			LLUnit<LLUnits::Milliseconds, F32> ms = 0;
 			S32 calls = 0;
 			if (mHoverBarIndex > 0 && mHoverID)
 			{
-				S32 hidx = LLTrace::BlockTimer::HISTORY_NUM - mScrollIndex - mHoverBarIndex;
-				U64 ticks = idp->getHistoricalCount(hidx);
-				ms = (F32)((F64)ticks * iclock_freq);
-				calls = (S32)idp->getHistoricalCalls(hidx);
+				S32 hidx = LLTrace::TimeBlock::HISTORY_NUM - mScrollIndex - mHoverBarIndex;
+				ms = frame_recording.getPrevRecordingPeriod(hidx).getSum(*idp);
+				calls = frame_recording.getPrevRecordingPeriod(hidx).getSum(idp->callCount());
 			}
 			else
 			{
-				U64 ticks = idp->getCountAverage();
-				ms = (F32)((F64)ticks * iclock_freq);
-				calls = (S32)idp->getCallAverage();
+				ms = frame_recording.getPeriodMean(*idp);
+				calls = frame_recording.getPeriodMean(idp->callCount());
 			}
 
 			if (mDisplayCalls)
@@ -521,7 +516,7 @@ void LLFastTimerView::draw()
 
 			x += dx;
 			BOOL is_child_of_hover_item = (idp == mHoverID);
-			LLTrace::BlockTimer* next_parent = idp->getParent();
+			LLTrace::TimeBlock* next_parent = idp->getParent();
 			while(!is_child_of_hover_item && next_parent)
 			{
 				is_child_of_hover_item = (mHoverID == next_parent);
@@ -563,419 +558,386 @@ void LLFastTimerView::draw()
 	barw = width - xleft - margin;
 
 	// Draw the history bars
-	if (LLTrace::BlockTimer::getLastFrameIndex() >= 0)
-	{	
-		LLLocalClipRect clip(LLRect(xleft, ytop, getRect().getWidth() - margin, margin));
-
-		U64 totalticks;
-		if (!LLTrace::BlockTimer::sPauseHistory)
-		{
-			U64 ticks = getFrameTimer().getHistoricalCount(mScrollIndex);
-
-			if (LLTrace::BlockTimer::getCurFrameIndex() >= 10)
-			{
-				U64 framec = LLTrace::BlockTimer::getCurFrameIndex();
-				U64 avg = (U64)mAvgCountTotal;
-				mAvgCountTotal = (avg*framec + ticks) / (framec + 1);
-				if (ticks > mMaxCountTotal)
-				{
-					mMaxCountTotal = ticks;
-				}
-			}
-
-			if (ticks < mAvgCountTotal/100 || ticks > mAvgCountTotal*100)
-			{
-				LLTrace::BlockTimer::sResetHistory = true;
-			}
+	LLLocalClipRect clip(LLRect(xleft, ytop, getRect().getWidth() - margin, margin));
 
-			if (LLTrace::BlockTimer::getCurFrameIndex() < 10 || LLTrace::BlockTimer::sResetHistory)
-			{
-				mAvgCountTotal = ticks;
-				mMaxCountTotal = ticks;
-				LLTrace::BlockTimer::sResetHistory = false;
-			}
-		}
+	LLUnit<LLUnits::Seconds, F64> total_time;
 
-		if (mDisplayMode == 0)
-		{
-			totalticks = mAvgCountTotal*2;
-		}
-		else if (mDisplayMode == 1)
-		{
-			totalticks = mMaxCountTotal;
-		}
-		else if (mDisplayMode == 2)
-		{
-			// Calculate the max total ticks for the current history
-			totalticks = 0;
-			for (S32 j=0; j<histmax; j++)
-			{
-				U64 ticks = getFrameTimer().getHistoricalCount(j);
+	mAllTimeMax = llmax(mAllTimeMax, frame_recording.getLastRecordingPeriod().getSum(getFrameTimer()));
 
-				if (ticks > totalticks)
-					totalticks = ticks;
-			}
-		}
-		else
-		{
-			totalticks = (U64)(clock_freq * .1); // 100 ms
-		}
+	if (mDisplayMode == 0)
+	{
+		total_time = frame_recording.getPeriodMean(getFrameTimer())*2;
+	}
+	else if (mDisplayMode == 1)
+	{
+		total_time = mAllTimeMax;
+	}
+	else if (mDisplayMode == 2)
+	{
+		// Calculate the max total ticks for the current history
+		total_time = frame_recording.getPeriodMax(getFrameTimer());
+	}
+	else
+	{
+		total_time = LLUnit<LLUnits::Milliseconds, F32>(100);
+	}
 		
-		// Draw MS ticks
-		{
-			U32 ms = (U32)((F64)totalticks * iclock_freq) ;
+	// Draw MS ticks
+	{
+		LLUnit<LLUnits::Milliseconds, U32> ms = total_time;
 
-			tdesc = llformat("%.1f ms |", (F32)ms*.25f);
-			x = xleft + barw/4 - LLFontGL::getFontMonospace()->getWidth(tdesc);
-			LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
-										 LLFontGL::LEFT, LLFontGL::TOP);
+		tdesc = llformat("%.1f ms |", (F32)ms*.25f);
+		x = xleft + barw/4 - LLFontGL::getFontMonospace()->getWidth(tdesc);
+		LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
+										LLFontGL::LEFT, LLFontGL::TOP);
 			
-			tdesc = llformat("%.1f ms |", (F32)ms*.50f);
-			x = xleft + barw/2 - LLFontGL::getFontMonospace()->getWidth(tdesc);
-			LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
-										 LLFontGL::LEFT, LLFontGL::TOP);
+		tdesc = llformat("%.1f ms |", (F32)ms*.50f);
+		x = xleft + barw/2 - LLFontGL::getFontMonospace()->getWidth(tdesc);
+		LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
+										LLFontGL::LEFT, LLFontGL::TOP);
 			
-			tdesc = llformat("%.1f ms |", (F32)ms*.75f);
-			x = xleft + (barw*3)/4 - LLFontGL::getFontMonospace()->getWidth(tdesc);
-			LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
-										 LLFontGL::LEFT, LLFontGL::TOP);
+		tdesc = llformat("%.1f ms |", (F32)ms*.75f);
+		x = xleft + (barw*3)/4 - LLFontGL::getFontMonospace()->getWidth(tdesc);
+		LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
+										LLFontGL::LEFT, LLFontGL::TOP);
 			
-			tdesc = llformat( "%d ms |", ms);
-			x = xleft + barw - LLFontGL::getFontMonospace()->getWidth(tdesc);
-			LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
-										 LLFontGL::LEFT, LLFontGL::TOP);
-		}
+		tdesc = llformat( "%d ms |", (U32)ms);
+		x = xleft + barw - LLFontGL::getFontMonospace()->getWidth(tdesc);
+		LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
+										LLFontGL::LEFT, LLFontGL::TOP);
+	}
 
-		// Draw borders
-		{
-			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-			gGL.color4f(0.5f,0.5f,0.5f,0.5f);
+	// Draw borders
+	{
+		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+		gGL.color4f(0.5f,0.5f,0.5f,0.5f);
 
-			S32 by = y + 2;
+		S32 by = y + 2;
 			
-			y -= ((S32)LLFontGL::getFontMonospace()->getLineHeight() + 4);
+		y -= ((S32)LLFontGL::getFontMonospace()->getLineHeight() + 4);
 
-			//heading
-			gl_rect_2d(xleft-5, by, getRect().getWidth()-5, y+5, FALSE);
+		//heading
+		gl_rect_2d(xleft-5, by, getRect().getWidth()-5, y+5, FALSE);
 
-			//tree view
-			gl_rect_2d(5, by, xleft-10, 5, FALSE);
+		//tree view
+		gl_rect_2d(5, by, xleft-10, 5, FALSE);
 
-			by = y + 5;
-			//average bar
-			gl_rect_2d(xleft-5, by, getRect().getWidth()-5, by-barh-dy-5, FALSE);
+		by = y + 5;
+		//average bar
+		gl_rect_2d(xleft-5, by, getRect().getWidth()-5, by-barh-dy-5, FALSE);
 			
-			by -= barh*2+dy;
+		by -= barh*2+dy;
 			
-			//current frame bar
-			gl_rect_2d(xleft-5, by, getRect().getWidth()-5, by-barh-dy-2, FALSE);
+		//current frame bar
+		gl_rect_2d(xleft-5, by, getRect().getWidth()-5, by-barh-dy-2, FALSE);
 			
-			by -= barh+dy+1;
+		by -= barh+dy+1;
 			
-			//history bars
-			gl_rect_2d(xleft-5, by, getRect().getWidth()-5, LINE_GRAPH_HEIGHT-barh-dy-2, FALSE);			
+		//history bars
+		gl_rect_2d(xleft-5, by, getRect().getWidth()-5, LINE_GRAPH_HEIGHT-barh-dy-2, FALSE);			
 			
-			by = LINE_GRAPH_HEIGHT-barh-dy-7;
+		by = LINE_GRAPH_HEIGHT-barh-dy-7;
 			
-			//line graph
-			mGraphRect = LLRect(xleft-5, by, getRect().getWidth()-5, 5);
+		//line graph
+		mGraphRect = LLRect(xleft-5, by, getRect().getWidth()-5, 5);
 			
-			gl_rect_2d(mGraphRect, FALSE);
-		}
+		gl_rect_2d(mGraphRect, FALSE);
+	}
 		
-		mBarStart.clear();
-		mBarEnd.clear();
+	mBarStart.clear();
+	mBarEnd.clear();
 
-		// Draw bars for each history entry
-		// Special: -1 = show running average
-		gGL.getTexUnit(0)->bind(box_imagep->getImage());
-		for (S32 j=-1; j<histmax && y > LINE_GRAPH_HEIGHT; j++)
+	// Draw bars for each history entry
+	// Special: -1 = show running average
+	gGL.getTexUnit(0)->bind(box_imagep->getImage());
+	for (S32 j=-1; j<histmax && y > LINE_GRAPH_HEIGHT; j++)
+	{
+		mBarStart.push_back(std::vector<S32>());
+		mBarEnd.push_back(std::vector<S32>());
+		int sublevel_dx[FTV_MAX_DEPTH];
+		int sublevel_left[FTV_MAX_DEPTH];
+		int sublevel_right[FTV_MAX_DEPTH];
+		S32 tidx;
+		if (j >= 0)
 		{
-			mBarStart.push_back(std::vector<S32>());
-			mBarEnd.push_back(std::vector<S32>());
-			int sublevel_dx[FTV_MAX_DEPTH];
-			int sublevel_left[FTV_MAX_DEPTH];
-			int sublevel_right[FTV_MAX_DEPTH];
-			S32 tidx;
-			if (j >= 0)
-			{
-				tidx = LLTrace::BlockTimer::HISTORY_NUM - j - 1 - mScrollIndex;
-			}
-			else
-			{
-				tidx = -1;
-			}
+			tidx = LLTrace::TimeBlock::HISTORY_NUM - j - 1 - mScrollIndex;
+		}
+		else
+		{
+			tidx = -1;
+		}
 			
-			x = xleft;
+		x = xleft;
 			
-			// draw the bars for each stat
-			std::vector<S32> xpos;
-			std::vector<S32> deltax;
-			xpos.push_back(xleft);
+		// draw the bars for each stat
+		std::vector<S32> xpos;
+		std::vector<S32> deltax;
+		xpos.push_back(xleft);
 			
-			LLTrace::BlockTimer* prev_id = NULL;
+		LLTrace::TimeBlock* prev_id = NULL;
 
-			S32 i = 0;
-			for(timer_tree_iterator_t it = begin_timer_tree(getFrameTimer());
-				it != end_timer_tree();
-				++it, ++i)
-			{
-				LLTrace::BlockTimer* idp = (*it);
-				F32 frac = tidx == -1
-					? (F32)idp->getCountAverage() / (F32)totalticks 
-					: (F32)idp->getHistoricalCount(tidx) / (F32)totalticks;
+		S32 i = 0;
+		for(timer_tree_iterator_t it = begin_timer_tree(getFrameTimer());
+			it != end_timer_tree();
+			++it, ++i)
+		{
+			LLTrace::TimeBlock* idp = (*it);
+			F32 frac = tidx == -1
+				? (frame_recording.getPeriodMean(*idp) / total_time) 
+				: (frame_recording.getPrevRecordingPeriod(tidx).getSum(*idp).value() / total_time.value());
 		
-				dx = llround(frac * (F32)barw);
-				S32 prev_delta_x = deltax.empty() ? 0 : deltax.back();
-				deltax.push_back(dx);
+			dx = llround(frac * (F32)barw);
+			S32 prev_delta_x = deltax.empty() ? 0 : deltax.back();
+			deltax.push_back(dx);
+				
+			int level = idp->getDepth() - 1;
 				
-				int level = idp->getDepth() - 1;
+			while ((S32)xpos.size() > level + 1)
+			{
+				xpos.pop_back();
+			}
+			left = xpos.back();
 				
-				while ((S32)xpos.size() > level + 1)
+			if (level == 0)
+			{
+				sublevel_left[level] = xleft;
+				sublevel_dx[level] = dx;
+				sublevel_right[level] = sublevel_left[level] + sublevel_dx[level];
+			}
+			else if (prev_id && prev_id->getDepth() < idp->getDepth())
+			{
+				U64 sublevelticks = 0;
+
+				for (LLTrace::TimeBlock::child_const_iter it = prev_id->beginChildren();
+					it != prev_id->endChildren();
+					++it)
 				{
-					xpos.pop_back();
+					sublevelticks += (tidx == -1)
+						? frame_recording.getPeriodMean(**it)
+						: frame_recording.getPrevRecordingPeriod(tidx).getSum(**it);
 				}
-				left = xpos.back();
-				
-				if (level == 0)
+
+				F32 subfrac = (F32)sublevelticks / (F32)total_time;
+				sublevel_dx[level] = (int)(subfrac * (F32)barw + .5f);
+
+				if (mDisplayCenter == ALIGN_CENTER)
 				{
-					sublevel_left[level] = xleft;
-					sublevel_dx[level] = dx;
-					sublevel_right[level] = sublevel_left[level] + sublevel_dx[level];
+					left += (prev_delta_x - sublevel_dx[level])/2;
 				}
-				else if (prev_id && prev_id->getDepth() < idp->getDepth())
+				else if (mDisplayCenter == ALIGN_RIGHT)
 				{
-					U64 sublevelticks = 0;
-
-					for (LLTrace::BlockTimer::child_const_iter it = prev_id->beginChildren();
-						it != prev_id->endChildren();
-						++it)
-					{
-						sublevelticks += (tidx == -1)
-							? (*it)->getCountAverage() 
-							: (*it)->getHistoricalCount(tidx);
-					}
-
-					F32 subfrac = (F32)sublevelticks / (F32)totalticks;
-					sublevel_dx[level] = (int)(subfrac * (F32)barw + .5f);
-
-					if (mDisplayCenter == ALIGN_CENTER)
-					{
-						left += (prev_delta_x - sublevel_dx[level])/2;
-					}
-					else if (mDisplayCenter == ALIGN_RIGHT)
-					{
-						left += (prev_delta_x - sublevel_dx[level]);
-					}
-
-					sublevel_left[level] = left;
-					sublevel_right[level] = sublevel_left[level] + sublevel_dx[level];
-				}				
-
-				right = left + dx;
-				xpos.back() = right;
-				xpos.push_back(left);
+					left += (prev_delta_x - sublevel_dx[level]);
+				}
+
+				sublevel_left[level] = left;
+				sublevel_right[level] = sublevel_left[level] + sublevel_dx[level];
+			}				
+
+			right = left + dx;
+			xpos.back() = right;
+			xpos.push_back(left);
 				
-				mBarStart.back().push_back(left);
-				mBarEnd.back().push_back(right);
+			mBarStart.back().push_back(left);
+			mBarEnd.back().push_back(right);
 
-				top = y;
-				bottom = y - barh;
+			top = y;
+			bottom = y - barh;
 
-				if (right > left)
-				{
-					//U32 rounded_edges = 0;
-					LLColor4 color = sTimerColors[idp];//*ft_display_table[i].color;
-					S32 scale_offset = 0;
-
-					BOOL is_child_of_hover_item = (idp == mHoverID);
-					LLTrace::BlockTimer* next_parent = idp->getParent();
-					while(!is_child_of_hover_item && next_parent)
-					{
-						is_child_of_hover_item = (mHoverID == next_parent);
-						if (next_parent->getParent() == next_parent) break;
-						next_parent = next_parent->getParent();
-					}
-
-					if (idp == mHoverID)
-					{
-						scale_offset = llfloor(sinf(mHighlightTimer.getElapsedTimeF32() * 6.f) * 3.f);
-						//color = lerp(color, LLColor4::black, -0.4f);
-					}
-					else if (mHoverID != NULL && !is_child_of_hover_item)
-					{
-						color = lerp(color, LLColor4::grey, 0.8f);
-					}
-
-					gGL.color4fv(color.mV);
-					F32 start_fragment = llclamp((F32)(left - sublevel_left[level]) / (F32)sublevel_dx[level], 0.f, 1.f);
-					F32 end_fragment = llclamp((F32)(right - sublevel_left[level]) / (F32)sublevel_dx[level], 0.f, 1.f);
-					gl_segmented_rect_2d_fragment_tex(sublevel_left[level], top - level + scale_offset, sublevel_right[level], bottom + level - scale_offset, box_imagep->getTextureWidth(), box_imagep->getTextureHeight(), 16, start_fragment, end_fragment);
+			if (right > left)
+			{
+				//U32 rounded_edges = 0;
+				LLColor4 color = sTimerColors[idp];//*ft_display_table[i].color;
+				S32 scale_offset = 0;
 
+				BOOL is_child_of_hover_item = (idp == mHoverID);
+				LLTrace::TimeBlock* next_parent = idp->getParent();
+				while(!is_child_of_hover_item && next_parent)
+				{
+					is_child_of_hover_item = (mHoverID == next_parent);
+					if (next_parent->getParent() == next_parent) break;
+					next_parent = next_parent->getParent();
 				}
 
-				if ((*it)->getCollapsed())
+				if (idp == mHoverID)
 				{
-					it.skipDescendants();
+					scale_offset = llfloor(sinf(mHighlightTimer.getElapsedTimeF32() * 6.f) * 3.f);
+					//color = lerp(color, LLColor4::black, -0.4f);
 				}
-		
-				prev_id = idp;
+				else if (mHoverID != NULL && !is_child_of_hover_item)
+				{
+					color = lerp(color, LLColor4::grey, 0.8f);
+				}
+
+				gGL.color4fv(color.mV);
+				F32 start_fragment = llclamp((F32)(left - sublevel_left[level]) / (F32)sublevel_dx[level], 0.f, 1.f);
+				F32 end_fragment = llclamp((F32)(right - sublevel_left[level]) / (F32)sublevel_dx[level], 0.f, 1.f);
+				gl_segmented_rect_2d_fragment_tex(sublevel_left[level], top - level + scale_offset, sublevel_right[level], bottom + level - scale_offset, box_imagep->getTextureWidth(), box_imagep->getTextureHeight(), 16, start_fragment, end_fragment);
+
 			}
-			y -= (barh + dy);
-			if (j < 0)
-				y -= barh;
+
+			if ((*it)->getCollapsed())
+			{
+				it.skipDescendants();
+			}
+		
+			prev_id = idp;
 		}
+		y -= (barh + dy);
+		if (j < 0)
+			y -= barh;
+	}
 		
-		//draw line graph history
-		{
-			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-			LLLocalClipRect clip(mGraphRect);
+	//draw line graph history
+	{
+		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+		LLLocalClipRect clip(mGraphRect);
 			
-			//normalize based on last frame's maximum
-			static U64 last_max = 0;
-			static F32 alpha_interp = 0.f;
-			U64 max_ticks = llmax(last_max, (U64) 1);			
-			F32 ms = (F32)((F64)max_ticks * iclock_freq);
+		//normalize based on last frame's maximum
+		static LLUnit<LLUnits::Seconds, F32> max_time = 0.000001;
+		static U32 max_calls = 0;
+		static F32 alpha_interp = 0.f;
 			
-			//display y-axis range
-			std::string tdesc;
-			 if (mDisplayCalls)
-				tdesc = llformat("%d calls", (int)max_ticks);
-			else if (mDisplayHz)
-				tdesc = llformat("%d Hz", (int)max_ticks);
-			else
-				tdesc = llformat("%4.2f ms", ms);
+		//display y-axis range
+		std::string tdesc;
+		if (mDisplayCalls)
+			tdesc = llformat("%d calls", (int)max_calls);
+		else if (mDisplayHz)
+			tdesc = llformat("%d Hz", (int)(1.f / max_time.value()));
+		else
+			tdesc = llformat("%4.2f ms", LLUnit<LLUnits::Milliseconds, F32>(max_time).value());
 							
-			x = mGraphRect.mRight - LLFontGL::getFontMonospace()->getWidth(tdesc)-5;
-			y = mGraphRect.mTop - LLFontGL::getFontMonospace()->getLineHeight();
+		x = mGraphRect.mRight - LLFontGL::getFontMonospace()->getWidth(tdesc)-5;
+		y = mGraphRect.mTop - LLFontGL::getFontMonospace()->getLineHeight();
  
-			LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
-										 LLFontGL::LEFT, LLFontGL::TOP);
+		LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
+										LLFontGL::LEFT, LLFontGL::TOP);
 
-			//highlight visible range
-			{
-				S32 first_frame = LLTrace::BlockTimer::HISTORY_NUM - mScrollIndex;
-				S32 last_frame = first_frame - MAX_VISIBLE_HISTORY;
+		//highlight visible range
+		{
+			S32 first_frame = LLTrace::TimeBlock::HISTORY_NUM - mScrollIndex;
+			S32 last_frame = first_frame - MAX_VISIBLE_HISTORY;
 				
-				F32 frame_delta = ((F32) (mGraphRect.getWidth()))/(LLTrace::BlockTimer::HISTORY_NUM-1);
+			F32 frame_delta = ((F32) (mGraphRect.getWidth()))/(LLTrace::TimeBlock::HISTORY_NUM-1);
 				
-				F32 right = (F32) mGraphRect.mLeft + frame_delta*first_frame;
-				F32 left = (F32) mGraphRect.mLeft + frame_delta*last_frame;
+			F32 right = (F32) mGraphRect.mLeft + frame_delta*first_frame;
+			F32 left = (F32) mGraphRect.mLeft + frame_delta*last_frame;
 				
-				gGL.color4f(0.5f,0.5f,0.5f,0.3f);
-				gl_rect_2d((S32) left, mGraphRect.mTop, (S32) right, mGraphRect.mBottom);
+			gGL.color4f(0.5f,0.5f,0.5f,0.3f);
+			gl_rect_2d((S32) left, mGraphRect.mTop, (S32) right, mGraphRect.mBottom);
 				
-				if (mHoverBarIndex >= 0)
-				{
-					S32 bar_frame = first_frame - mHoverBarIndex;
-					F32 bar = (F32) mGraphRect.mLeft + frame_delta*bar_frame;
+			if (mHoverBarIndex >= 0)
+			{
+				S32 bar_frame = first_frame - mHoverBarIndex;
+				F32 bar = (F32) mGraphRect.mLeft + frame_delta*bar_frame;
 
-					gGL.color4f(0.5f,0.5f,0.5f,1);
+				gGL.color4f(0.5f,0.5f,0.5f,1);
 				
-					gGL.begin(LLRender::LINES);
-					gGL.vertex2i((S32)bar, mGraphRect.mBottom);
-					gGL.vertex2i((S32)bar, mGraphRect.mTop);
-					gGL.end();
-				}
+				gGL.begin(LLRender::LINES);
+				gGL.vertex2i((S32)bar, mGraphRect.mBottom);
+				gGL.vertex2i((S32)bar, mGraphRect.mTop);
+				gGL.end();
 			}
+		}
 			
-			U64 cur_max = 0;
-			for(timer_tree_iterator_t it = begin_timer_tree(getFrameTimer());
-				it != end_timer_tree();
-				++it)
-			{
-				LLTrace::BlockTimer* idp = (*it);
+		LLUnit<LLUnits::Seconds, F32> cur_max = 0;
+		U32 cur_max_calls = 0;
+		for(timer_tree_iterator_t it = begin_timer_tree(getFrameTimer());
+			it != end_timer_tree();
+			++it)
+		{
+			LLTrace::TimeBlock* idp = (*it);
 				
-				//fatten highlighted timer
-				if (mHoverID == idp)
-				{
-					gGL.flush();
-					glLineWidth(3);
-				}
+			//fatten highlighted timer
+			if (mHoverID == idp)
+			{
+				gGL.flush();
+				glLineWidth(3);
+			}
 			
-				const F32 * col = sTimerColors[idp].mV;// ft_display_table[idx].color->mV;
+			const F32 * col = sTimerColors[idp].mV;// ft_display_table[idx].color->mV;
 				
-				F32 alpha = 1.f;
+			F32 alpha = 1.f;
 				
-				if (mHoverID != NULL &&
-					idp != mHoverID)
-				{	//fade out non-highlighted timers
-					if (idp->getParent() != mHoverID)
-					{
-						alpha = alpha_interp;
-					}
-				}
-
-				gGL.color4f(col[0], col[1], col[2], alpha);				
-				gGL.begin(LLRender::TRIANGLE_STRIP);
-				for (U32 j = llmax(0, LLTrace::BlockTimer::HISTORY_NUM - LLTrace::BlockTimer::getLastFrameIndex());
-					j < LLTrace::BlockTimer::HISTORY_NUM;
-					j++)
+			if (mHoverID != NULL &&
+				idp != mHoverID)
+			{	//fade out non-highlighted timers
+				if (idp->getParent() != mHoverID)
 				{
-					U64 ticks = idp->getHistoricalCount(j);
-
-					if (mDisplayHz)
-					{
-						F64 tc = (F64) (ticks+1) * iclock_freq;
-						tc = 1000.f/tc;
-						ticks = llmin((U64) tc, (U64) 1024);
-					}
-					else if (mDisplayCalls)
-					{
-						ticks = (S32)idp->getHistoricalCalls(j);
-					}
-										
-					if (alpha == 1.f)
-					{ 
-						//normalize to highlighted timer
-						cur_max = llmax(cur_max, ticks);
-					}
-					F32 x = mGraphRect.mLeft + ((F32) (mGraphRect.getWidth()))/(LLTrace::BlockTimer::HISTORY_NUM-1)*j;
-					F32 y = mGraphRect.mBottom + (F32) mGraphRect.getHeight()/max_ticks*ticks;
-					gGL.vertex2f(x,y);
-					gGL.vertex2f(x,mGraphRect.mBottom);
-				}
-				gGL.end();
-				
-				if (mHoverID == idp)
-				{
-					gGL.flush();
-					glLineWidth(1);
+					alpha = alpha_interp;
 				}
+			}
 
-				if (idp->getCollapsed())
-				{	
-					//skip hidden timers
-					it.skipDescendants();
+			gGL.color4f(col[0], col[1], col[2], alpha);				
+			gGL.begin(LLRender::TRIANGLE_STRIP);
+			for (U32 j = frame_recording.getNumPeriods();
+				j < LLTrace::TimeBlock::HISTORY_NUM;
+				j++)
+			{
+				LLUnit<LLUnits::Seconds, F32> time = llmax(frame_recording.getPrevRecordingPeriod(j).getSum(*idp), LLUnit<LLUnits::Seconds, F64>(0.000001));
+				U32 calls = frame_recording.getPrevRecordingPeriod(j).getSum(idp->callCount());
+
+				if (alpha == 1.f)
+				{ 
+					//normalize to highlighted timer
+					cur_max = llmax(cur_max, time);
+					cur_max_calls = llmax(cur_max_calls, calls);
 				}
+				F32 x = mGraphRect.mLeft + j * (F32)(mGraphRect.getWidth())/(LLTrace::TimeBlock::HISTORY_NUM-1);
+				F32 y = mDisplayHz 
+					? mGraphRect.mBottom + (1.f / time.value()) * ((F32) mGraphRect.getHeight() / (1.f / max_time.value()))
+					: mGraphRect.mBottom + time * ((F32)mGraphRect.getHeight() / max_time);
+				gGL.vertex2f(x,y);
+				gGL.vertex2f(x,mGraphRect.mBottom);
 			}
-			
-			//interpolate towards new maximum
-			last_max = (U64) lerp((F32)last_max, (F32) cur_max, LLCriticalDamp::getInterpolant(0.1f));
-			if (last_max - cur_max <= 1 ||  cur_max - last_max  <= 1)
+			gGL.end();
+				
+			if (mHoverID == idp)
 			{
-				last_max = cur_max;
+				gGL.flush();
+				glLineWidth(1);
 			}
-			F32 alpha_target = last_max > cur_max ?
-								llmin((F32) last_max/ (F32) cur_max - 1.f,1.f) :
-								llmin((F32) cur_max/ (F32) last_max - 1.f,1.f);
-			alpha_interp = lerp(alpha_interp, alpha_target, LLCriticalDamp::getInterpolant(0.1f));
 
-			if (mHoverID != NULL)
-			{
-				x = (mGraphRect.mRight + mGraphRect.mLeft)/2;
-				y = mGraphRect.mBottom + 8;
-
-				LLFontGL::getFontMonospace()->renderUTF8(
-					mHoverID->getName(), 
-					0, 
-					x, y, 
-					LLColor4::white,
-					LLFontGL::LEFT, LLFontGL::BOTTOM);
-			}					
+			if (idp->getCollapsed())
+			{	
+				//skip hidden timers
+				it.skipDescendants();
+			}
+		}
+			
+		//interpolate towards new maximum
+		max_time = lerp((F32)max_time, (F32) cur_max, LLCriticalDamp::getInterpolant(0.1f));
+		if (max_time - cur_max <= 1 ||  cur_max - max_time  <= 1)
+		{
+			max_time = llmax(LLUnit<LLUnits::Microseconds, F32>(1), LLUnit<LLUnits::Microseconds, F32>(cur_max));
+		}
+
+		max_calls = lerp((F32)max_calls, (F32) cur_max_calls, LLCriticalDamp::getInterpolant(0.1f));
+		if (llabs(max_calls - cur_max) <= 1)
+		{
+			max_calls = cur_max_calls;
 		}
+
+		// TODO: make sure alpha is correct in DisplayHz mode
+		F32 alpha_target = (max_time > cur_max)
+			? llmin((F32) max_time/ (F32) cur_max - 1.f,1.f) 
+			: llmin((F32) cur_max/ (F32) max_time - 1.f,1.f);
+		alpha_interp = lerp(alpha_interp, alpha_target, LLCriticalDamp::getInterpolant(0.1f));
+
+		if (mHoverID != NULL)
+		{
+			x = (mGraphRect.mRight + mGraphRect.mLeft)/2;
+			y = mGraphRect.mBottom + 8;
+
+			LLFontGL::getFontMonospace()->renderUTF8(
+				mHoverID->getName(), 
+				0, 
+				x, y, 
+				LLColor4::white,
+				LLFontGL::LEFT, LLFontGL::BOTTOM);
+		}					
 	}
 
+
 	// Output stats for clicked bar to log
 	if (mPrintStats >= 0)
 	{
@@ -985,7 +947,7 @@ void LLFastTimerView::draw()
 			it != end_timer_tree();
 			++it)
 		{
-			LLTrace::BlockTimer* idp = (*it);
+			LLTrace::TimeBlock* idp = (*it);
 
 			if (!first)
 			{
@@ -1007,7 +969,7 @@ void LLFastTimerView::draw()
 			it != end_timer_tree();
 			++it)
 		{
-			LLTrace::BlockTimer* idp = (*it);
+			LLTrace::TimeBlock* idp = (*it);
 
 			if (!first)
 			{
@@ -1015,16 +977,16 @@ void LLFastTimerView::draw()
 			}
 			first = false;
 
-			U64 ticks;
+			LLUnit<LLUnits::Seconds, F32> ticks;
 			if (mPrintStats > 0)
 			{
-				ticks = idp->getHistoricalCount(mPrintStats);
+				ticks = frame_recording.getPrevRecordingPeriod(mPrintStats).getSum(*idp);
 			}
 			else
 			{
-				ticks = idp->getCountAverage();
+				ticks = frame_recording.getPeriodMean(*idp);
 			}
-			F32 ms = (F32)((F64)ticks * iclock_freq);
+			LLUnit<LLUnits::Milliseconds, F32> ms = ticks;
 
 			timer_stat += llformat("%.1f",ms);
 
@@ -1544,13 +1506,13 @@ void LLFastTimerView::outputAllMetrics()
 //static
 void LLFastTimerView::doAnalysis(std::string baseline, std::string target, std::string output)
 {
-	if(LLTrace::BlockTimer::sLog)
+	if(LLTrace::TimeBlock::sLog)
 	{
 		doAnalysisDefault(baseline, target, output) ;
 		return ;
 	}
 
-	if(LLTrace::BlockTimer::sMetricLog)
+	if(LLTrace::TimeBlock::sMetricLog)
 	{
 		LLMetricPerformanceTesterBasic::doAnalysisMetrics(baseline, target, output) ;
 		return ;
@@ -1561,7 +1523,7 @@ void	LLFastTimerView::onClickCloseBtn()
 	setVisible(false);
 }
 
-LLTrace::BlockTimer& LLFastTimerView::getFrameTimer()
+LLTrace::TimeBlock& LLFastTimerView::getFrameTimer()
 {
 	return FTM_FRAME;
 }
diff --git a/indra/newview/llfasttimerview.h b/indra/newview/llfasttimerview.h
index d7f7f27cd4..55adae4147 100644
--- a/indra/newview/llfasttimerview.h
+++ b/indra/newview/llfasttimerview.h
@@ -29,6 +29,7 @@
 
 #include "llfloater.h"
 #include "llfasttimer.h"
+#include "llunit.h"
 
 class LLFastTimerView : public LLFloater
 {
@@ -46,7 +47,7 @@ private:
 	static LLSD analyzePerformanceLogDefault(std::istream& is) ;
 	static void exportCharts(const std::string& base, const std::string& target);
 	void onPause();
-	LLTrace::BlockTimer& getFrameTimer();
+	LLTrace::TimeBlock& getFrameTimer();
 
 public:
 
@@ -59,7 +60,7 @@ public:
 	virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
 	virtual void draw();
 
-	LLTrace::BlockTimer* getLegendID(S32 y);
+	LLTrace::TimeBlock* getLegendID(S32 y);
 	F64 getTime(const std::string& name);
 
 protected:
@@ -78,20 +79,19 @@ private:
 		ALIGN_COUNT
 	} ChildAlignment;
 
-	ChildAlignment mDisplayCenter;
-	S32 mDisplayCalls;
-	S32 mDisplayHz;
-	U64 mAvgCountTotal;
-	U64 mMaxCountTotal;
-	LLRect mBarRect;
-	S32	mScrollIndex;
-	LLTrace::BlockTimer* mHoverID;
-	LLTrace::BlockTimer* mHoverTimer;
-	LLRect					mToolTipRect;
-	S32 mHoverBarIndex;
-	LLFrameTimer mHighlightTimer;
-	S32 mPrintStats;
-	LLRect mGraphRect;
+	ChildAlignment                mDisplayCenter;
+	bool                          mDisplayCalls,
+								  mDisplayHz;
+	LLUnit<LLUnits::Seconds, F64> mAllTimeMax;
+	LLRect                        mBarRect;
+	S32						      mScrollIndex;
+	LLTrace::TimeBlock*           mHoverID;
+	LLTrace::TimeBlock*           mHoverTimer;
+	LLRect						  mToolTipRect;
+	S32                           mHoverBarIndex;
+	LLFrameTimer                  mHighlightTimer;
+	S32                           mPrintStats;
+	LLRect                        mGraphRect;
 };
 
 #endif
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 511e6ec2ab..69999071e7 100755
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -2184,7 +2184,7 @@ bool idle_startup()
 		LLAppViewer::instance()->handleLoginComplete();
 
 		// reset timers now that we are running "logged in" logic
-		LLTrace::BlockTimer::reset();
+		LLTrace::TimeBlock::reset();
 
 		LLAgentPicksInfo::getInstance()->requestNumberOfPicks();
 
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 1ba78f18d3..781a420648 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -7296,7 +7296,7 @@ void handle_dump_avatar_local_textures(void*)
 
 void handle_dump_timers()
 {
-	LLFastTimer::dumpCurTimes();
+	LLTrace::TimeBlock::dumpCurTimes();
 }
 
 void handle_debug_avatar_textures(void*)
-- 
cgit v1.2.3