From a3e3e8b4ccd96e98da73acf1c584bbfa5a8b2b56 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Mon, 12 Nov 2012 19:08:14 -0800
Subject: [PATCH] SH-3406 WIP convert fast timers to lltrace system simplified
 llfasttimer code down to 2 classes llunit unit conversion now done in
 floating point or 64 bit integer precision, depending on source type

---
 indra/llcommon/llfasttimer.cpp    | 270 ++++++++++--------------------
 indra/llcommon/llfasttimer.h      | 121 +++++--------
 indra/llcommon/llprocessor.cpp    |   2 +-
 indra/llcommon/llprocessor.h      |   4 +-
 indra/llcommon/lltrace.cpp        |   1 +
 indra/llcommon/lltrace.h          |  39 +----
 indra/llcommon/lltracerecording.h |  18 +-
 indra/llcommon/llunit.h           | 127 ++++++++++----
 indra/newview/llfasttimerview.cpp |  98 ++++++-----
 indra/newview/llfasttimerview.h   |   8 +-
 indra/newview/pipeline.cpp        |   2 +-
 11 files changed, 307 insertions(+), 383 deletions(-)

diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index 4f67004773f..c4839fed773 100644
--- a/indra/llcommon/llfasttimer.cpp
+++ b/indra/llcommon/llfasttimer.cpp
@@ -32,6 +32,7 @@
 #include "llsingleton.h"
 #include "lltreeiterators.h"
 #include "llsdserialize.h"
+#include "llunit.h"
 
 #include <boost/bind.hpp>
 
@@ -73,13 +74,13 @@ U64 LLFastTimer::sClockResolution = 1000000; // Microsecond resolution
 // FIXME: move these declarations to the relevant modules
 
 // helper functions
-typedef LLTreeDFSPostIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_bottom_up_iterator_t;
+typedef LLTreeDFSPostIter<LLFastTimer::DeclareTimer, LLFastTimer::DeclareTimer::child_const_iter> timer_tree_bottom_up_iterator_t;
 
-static timer_tree_bottom_up_iterator_t begin_timer_tree_bottom_up(LLFastTimer::NamedTimer& id) 
+static timer_tree_bottom_up_iterator_t begin_timer_tree_bottom_up(LLFastTimer::DeclareTimer& id) 
 { 
 	return timer_tree_bottom_up_iterator_t(&id, 
-							boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1), 
-							boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1));
+							boost::bind(boost::mem_fn(&LLFastTimer::DeclareTimer::beginChildren), _1), 
+							boost::bind(boost::mem_fn(&LLFastTimer::DeclareTimer::endChildren), _1));
 }
 
 static timer_tree_bottom_up_iterator_t end_timer_tree_bottom_up() 
@@ -87,14 +88,14 @@ static timer_tree_bottom_up_iterator_t end_timer_tree_bottom_up()
 	return timer_tree_bottom_up_iterator_t(); 
 }
 
-typedef LLTreeDFSIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_dfs_iterator_t;
+typedef LLTreeDFSIter<LLFastTimer::DeclareTimer, LLFastTimer::DeclareTimer::child_const_iter> timer_tree_dfs_iterator_t;
 
 
-static timer_tree_dfs_iterator_t begin_timer_tree(LLFastTimer::NamedTimer& id) 
+static timer_tree_dfs_iterator_t begin_timer_tree(LLFastTimer::DeclareTimer& id) 
 { 
 	return timer_tree_dfs_iterator_t(&id, 
-		boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1), 
-							boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1));
+		boost::bind(boost::mem_fn(&LLFastTimer::DeclareTimer::beginChildren), _1), 
+							boost::bind(boost::mem_fn(&LLFastTimer::DeclareTimer::endChildren), _1));
 }
 
 static timer_tree_dfs_iterator_t end_timer_tree() 
@@ -102,75 +103,12 @@ static timer_tree_dfs_iterator_t end_timer_tree()
 	return timer_tree_dfs_iterator_t(); 
 }
 
-// factory class that creates NamedTimers via static DeclareTimer objects
-class NamedTimerFactory : public LLSingleton<NamedTimerFactory>
+LLFastTimer::DeclareTimer& LLFastTimer::DeclareTimer::getRootTimer()
 {
-public:
-	NamedTimerFactory()
-	:	mTimerRoot(NULL)
-	{}
-
-	/*virtual */ void initSingleton()
-	{
-		mTimerRoot = new LLFastTimer::NamedTimer("root");
-		mRootFrameState.setNamedTimer(mTimerRoot);
-		mTimerRoot->setFrameState(&mRootFrameState);
-		mTimerRoot->mParent = mTimerRoot;
-		mTimerRoot->setCollapsed(false);
-		mRootFrameState.mParent = &mRootFrameState;
-	}
-
-	~NamedTimerFactory()
-	{
-		std::for_each(mTimers.begin(), mTimers.end(), DeletePairedPointer());
-
-		delete mTimerRoot;
-	}
-
-	LLFastTimer::NamedTimer& createNamedTimer(const std::string& name, LLFastTimer::FrameState* state)
-	{
-		LLFastTimer::NamedTimer* timer = new LLFastTimer::NamedTimer(name);
-		timer->setFrameState(state);
-		timer->setParent(mTimerRoot);
-		mTimers.insert(std::make_pair(name, timer));
-
-		return *timer;
-	}
-
-	LLFastTimer::NamedTimer* getTimerByName(const std::string& name)
-	{
-		timer_map_t::iterator found_it = mTimers.find(name);
-		if (found_it != mTimers.end())
-		{
-			return found_it->second;
-		}
-		return NULL;
-	}
-
-	LLFastTimer::NamedTimer* getRootTimer() { return mTimerRoot; }
-
-	typedef std::multimap<std::string, LLFastTimer::NamedTimer*> timer_map_t;
-	timer_map_t::iterator beginTimers() { return mTimers.begin(); }
-	timer_map_t::iterator endTimers() { return mTimers.end(); }
-	S32 timerCount() { return mTimers.size(); }
-
-private:
-	timer_map_t mTimers;
-
-	LLFastTimer::NamedTimer*		mTimerRoot;
-	LLFastTimer::FrameState			mRootFrameState;
-};
-
-LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name, bool open )
-:	mTimer(NamedTimerFactory::instance().createNamedTimer(name, &mFrameState))
-{
-	mTimer.setCollapsed(!open);
+	static DeclareTimer root_timer("root", true, NULL);
+	return root_timer;
 }
 
-LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name)
-:	mTimer(NamedTimerFactory::instance().createNamedTimer(name, &mFrameState))
-{
-}
 
 //static
 #if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
@@ -183,7 +121,7 @@ U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
 {
 #if LL_FASTTIMER_USE_RDTSC || !LL_WINDOWS
 	//getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz
-	static U64 sCPUClockFrequency = U64(LLProcessorInfo().getCPUFrequency()*1000000.0);
+	static LLUnit<LLUnits::Hertz, U64> sCPUClockFrequency = LLProcessorInfo().getCPUFrequency();
 
 	// we drop the low-order byte in our timers, so report a lower frequency
 #else
@@ -206,49 +144,44 @@ LLFastTimer::FrameState::FrameState()
 :	mActiveCount(0),
 	mCalls(0),
 	mSelfTimeCounter(0),
-	mParent(NULL),
 	mLastCaller(NULL),
 	mMoveUpTree(false)
 {}
 
 
-LLFastTimer::NamedTimer::NamedTimer(const std::string& name)
+LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name, bool open, DeclareTimer* parent)
 :	mName(name),
 	mCollapsed(true),
 	mParent(NULL),
 	mTreeTimeCounter(0),
 	mCountAverage(0),
 	mCallAverage(0),
-	mNeedsSorting(false),
-	mFrameState(NULL)
+	mNeedsSorting(false)
 {
+	setCollapsed(!open);
+
+	if (parent)
+	{
+		setParent(parent);
+	}
+	else
+	{
+		mParent = this;
+	}
+
 	mCountHistory = new U32[HISTORY_NUM];
 	memset(mCountHistory, 0, sizeof(U32) * HISTORY_NUM);
 	mCallHistory = new U32[HISTORY_NUM];
 	memset(mCallHistory, 0, sizeof(U32) * HISTORY_NUM);
 }
 
-LLFastTimer::NamedTimer::~NamedTimer()
+LLFastTimer::DeclareTimer::~DeclareTimer()
 {
 	delete[] mCountHistory;
 	delete[] mCallHistory;
 }
 
-std::string LLFastTimer::NamedTimer::getToolTip(S32 history_idx)
-{
-	F64 ms_multiplier = 1000.0 / (F64)LLFastTimer::countsPerSecond();
-	if (history_idx < 0)
-	{
-		// by default, show average number of call
-		return llformat("%s (%d ms, %d calls)", getName().c_str(), (S32)(getCountAverage() * ms_multiplier), (S32)getCallAverage());
-	}
-	else
-	{
-		return llformat("%s (%d ms, %d calls)", getName().c_str(), (S32)(getHistoricalCount(history_idx) * ms_multiplier), (S32)getHistoricalCalls(history_idx));
-	}
-}
-
-void LLFastTimer::NamedTimer::setParent(NamedTimer* parent)
+void LLFastTimer::DeclareTimer::setParent(DeclareTimer* parent)
 {
 	llassert_always(parent != this);
 	llassert_always(parent != NULL);
@@ -264,8 +197,8 @@ void LLFastTimer::NamedTimer::setParent(NamedTimer* parent)
 		// subtract average timing from previous parent
 		mParent->mCountAverage -= mCountAverage;
 
-		std::vector<NamedTimer*>& children = mParent->getChildren();
-		std::vector<NamedTimer*>::iterator found_it = std::find(children.begin(), children.end(), this);
+		std::vector<DeclareTimer*>& children = mParent->getChildren();
+		std::vector<DeclareTimer*>::iterator found_it = std::find(children.begin(), children.end(), this);
 		if (found_it != children.end())
 		{
 			children.erase(found_it);
@@ -275,16 +208,15 @@ void LLFastTimer::NamedTimer::setParent(NamedTimer* parent)
 	mParent = parent;
 	if (parent)
 	{
-		getFrameState().mParent = &parent->getFrameState();
 		parent->getChildren().push_back(this);
 		parent->mNeedsSorting = true;
 	}
 }
 
-S32 LLFastTimer::NamedTimer::getDepth()
+S32 LLFastTimer::DeclareTimer::getDepth()
 {
 	S32 depth = 0;
-	NamedTimer* timerp = mParent;
+	DeclareTimer* timerp = mParent;
 	while(timerp)
 	{
 		depth++;
@@ -295,7 +227,7 @@ S32 LLFastTimer::NamedTimer::getDepth()
 }
 
 // static
-void LLFastTimer::NamedTimer::processTimes()
+void LLFastTimer::DeclareTimer::processTimes()
 {
 	if (sCurFrameIndex < 0) return;
 
@@ -306,14 +238,14 @@ void LLFastTimer::NamedTimer::processTimes()
 // sort child timers by name
 struct SortTimerByName
 {
-	bool operator()(const LLFastTimer::NamedTimer* i1, const LLFastTimer::NamedTimer* i2)
+	bool operator()(const LLFastTimer::DeclareTimer* i1, const LLFastTimer::DeclareTimer* i2)
 	{
 		return i1->getName() < i2->getName();
 	}
 };
 
 //static
-void LLFastTimer::NamedTimer::buildHierarchy()
+void LLFastTimer::DeclareTimer::buildHierarchy()
 {
 	if (sCurFrameIndex < 0 ) return;
 
@@ -321,16 +253,16 @@ void LLFastTimer::NamedTimer::buildHierarchy()
 	{
 		for (instance_iter it = beginInstances(), end_it = endInstances(); it != end_it; ++it)
 		{
-			NamedTimer& timer = *it;
-			if (&timer == NamedTimerFactory::instance().getRootTimer()) continue;
+			DeclareTimer& timer = *it;
+			if (&timer == &DeclareTimer::getRootTimer()) continue;
 			
 			// bootstrap tree construction by attaching to last timer to be on stack
 			// when this timer was called
-			if (timer.getFrameState().mLastCaller && timer.mParent == NamedTimerFactory::instance().getRootTimer())
+			if (timer.mLastCaller && timer.mParent == &DeclareTimer::getRootTimer())
 			{
-				timer.setParent(timer.getFrameState().mLastCaller->mTimer);
+				timer.setParent(timer.mLastCaller);
 				// no need to push up tree on first use, flag can be set spuriously
-				timer.getFrameState().mMoveUpTree = false;
+				timer.mMoveUpTree = false;
 			}
 		}
 	}
@@ -338,22 +270,22 @@ void LLFastTimer::NamedTimer::buildHierarchy()
 	// bump timers up tree if they've 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(*NamedTimerFactory::instance().getRootTimer());
+	for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(DeclareTimer::getRootTimer());
 		it != end_timer_tree_bottom_up();
 		++it)
 	{
-		NamedTimer* timerp = *it;
+		DeclareTimer* timerp = *it;
 		// skip root timer
-		if (timerp == NamedTimerFactory::instance().getRootTimer()) continue;
+		if (timerp == &DeclareTimer::getRootTimer()) continue;
 
-		if (timerp->getFrameState().mMoveUpTree)
+		if (timerp->mMoveUpTree)
 		{
 			// since ancestors have already been visited, reparenting 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());
-			timerp->getFrameState().mMoveUpTree = false;
+			timerp->mMoveUpTree = false;
 
 			// don't bubble up any ancestors until descendants are done bubbling up
 			it.skipAncestors();
@@ -361,11 +293,11 @@ void LLFastTimer::NamedTimer::buildHierarchy()
 	}
 
 	// sort timers by time last called, so call graph makes sense
-	for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer());
+	for(timer_tree_dfs_iterator_t it = begin_timer_tree(DeclareTimer::getRootTimer());
 		it != end_timer_tree();
 		++it)
 	{
-		NamedTimer* timerp = (*it);
+		DeclareTimer* timerp = (*it);
 		if (timerp->mNeedsSorting)
 		{
 			std::sort(timerp->getChildren().begin(), timerp->getChildren().end(), SortTimerByName());
@@ -375,7 +307,7 @@ void LLFastTimer::NamedTimer::buildHierarchy()
 }
 
 //static
-void LLFastTimer::NamedTimer::accumulateTimings()
+void LLFastTimer::DeclareTimer::accumulateTimings()
 {
 	U32 cur_time = getCPUClockCount32();
 
@@ -388,8 +320,8 @@ void LLFastTimer::NamedTimer::accumulateTimings()
 		U32 cumulative_time_delta = cur_time - cur_timer->mStartTime;
 		U32 self_time_delta = cumulative_time_delta - cur_data->mChildTime;
 		cur_data->mChildTime = 0;
-		cur_data->mFrameState->mSelfTimeCounter += self_time_delta;
-		cur_data->mFrameState->mTotalTimeCounter += cumulative_time_delta;
+		cur_data->mTimerData->mSelfTimeCounter += self_time_delta;
+		cur_data->mTimerData->mTotalTimeCounter += cumulative_time_delta;
 
 		cur_timer->mStartTime = cur_time;
 
@@ -400,12 +332,12 @@ void LLFastTimer::NamedTimer::accumulateTimings()
 	}
 
 	// traverse tree in DFS post order, or bottom up
-	for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(*NamedTimerFactory::instance().getRootTimer());
+	for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(DeclareTimer::getRootTimer());
 		it != end_timer_tree_bottom_up();
 		++it)
 	{
-		NamedTimer* timerp = (*it);
-		timerp->mTreeTimeCounter = timerp->getFrameState().mSelfTimeCounter;
+		DeclareTimer* timerp = (*it);
+		timerp->mTreeTimeCounter = timerp->mSelfTimeCounter;
 		for (child_const_iter child_it = timerp->beginChildren(); child_it != timerp->endChildren(); ++child_it)
 		{
 			timerp->mTreeTimeCounter += (*child_it)->mTreeTimeCounter;
@@ -418,15 +350,15 @@ void LLFastTimer::NamedTimer::accumulateTimings()
 			int hidx = cur_frame % HISTORY_NUM;
 
 			timerp->mCountHistory[hidx] = timerp->mTreeTimeCounter;
-			timerp->mCountAverage = ((U64)timerp->mCountAverage * cur_frame + timerp->mTreeTimeCounter) / (cur_frame+1);
-			timerp->mCallHistory[hidx] = timerp->getFrameState().mCalls;
-			timerp->mCallAverage = ((U64)timerp->mCallAverage * cur_frame + timerp->getFrameState().mCalls) / (cur_frame+1);
+			timerp->mCountAverage       = ((U64)timerp->mCountAverage * cur_frame + timerp->mTreeTimeCounter) / (cur_frame+1);
+			timerp->mCallHistory[hidx]  = timerp->mCalls;
+			timerp->mCallAverage        = ((U64)timerp->mCallAverage * cur_frame + timerp->mCalls) / (cur_frame+1);
 		}
 	}
 }
 
 // static
-void LLFastTimer::NamedTimer::resetFrame()
+void LLFastTimer::DeclareTimer::resetFrame()
 {
 	if (sLog)
 	{ //output current frame counts to performance log
@@ -435,11 +367,11 @@ void LLFastTimer::NamedTimer::resetFrame()
 		if (call_count % 100 == 0)
 		{
 			LL_DEBUGS("FastTimers") << "countsPerSecond (32 bit): " << countsPerSecond() << LL_ENDL;
-			LL_DEBUGS("FastTimers") << "get_clock_count (64 bit): " << get_clock_count() << llendl;
+			LL_DEBUGS("FastTimers") << "get_clock_count (64 bit): " << get_clock_count() << 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())/((F64)LLProcessorInfo().getCPUFrequency()*1000000.0) << LL_ENDL;
+			LL_DEBUGS("FastTimers") << "elapsed sec " << ((F64)getCPUClockCount64()) / (LLUnit<LLUnits::Hertz, F64>(LLProcessorInfo().getCPUFrequency())) << LL_ENDL;
 		}
 		call_count++;
 
@@ -451,14 +383,13 @@ void LLFastTimer::NamedTimer::resetFrame()
 		{
 			for (instance_iter it = beginInstances(), end_it = endInstances(); it != end_it; ++it)
 			{
-				NamedTimer& timer = *it;
-				FrameState& info = timer.getFrameState();
-				sd[timer.getName()]["Time"] = (LLSD::Real) (info.mSelfTimeCounter*iclock_freq);	
-				sd[timer.getName()]["Calls"] = (LLSD::Integer) info.mCalls;
+				DeclareTimer& timer = *it;
+				sd[timer.getName()]["Time"] = (LLSD::Real) (timer.mSelfTimeCounter*iclock_freq);	
+				sd[timer.getName()]["Calls"] = (LLSD::Integer) timer.mCalls;
 				
 				// computing total time here because getting the root timer's getCountHistory
 				// doesn't work correctly on the first frame
-				total_time = total_time + info.mSelfTimeCounter * iclock_freq;
+				total_time = total_time + timer.mSelfTimeCounter * iclock_freq;
 			}
 		}
 
@@ -474,23 +405,16 @@ void LLFastTimer::NamedTimer::resetFrame()
 	// reset for next frame
 	for (instance_iter it = beginInstances(), end_it = endInstances(); it != end_it; ++it)
 	{
-		NamedTimer& timer = *it;
-			
-		FrameState& info = timer.getFrameState();
-		info.mSelfTimeCounter = 0;
-		info.mCalls = 0;
-		info.mLastCaller = NULL;
-		info.mMoveUpTree = false;
-		// update parent pointer in timer state struct
-		if (timer.mParent)
-		{
-			info.mParent = &timer.mParent->getFrameState();
-		}
+		DeclareTimer& timer = *it;
+		timer.mSelfTimeCounter = 0;
+		timer.mCalls = 0;
+		timer.mLastCaller = NULL;
+		timer.mMoveUpTree = false;
 	}
 }
 
 //static
-void LLFastTimer::NamedTimer::reset()
+void LLFastTimer::DeclareTimer::reset()
 {
 	resetFrame(); // reset frame data
 
@@ -514,10 +438,10 @@ void LLFastTimer::NamedTimer::reset()
 	{
 		for (instance_iter it = beginInstances(), end_it = endInstances(); it != end_it; ++it)
 		{
-			NamedTimer& timer = *it;
-			if (&timer != NamedTimerFactory::instance().getRootTimer()) 
+			DeclareTimer& timer = *it;
+			if (&timer != &DeclareTimer::getRootTimer()) 
 			{
-				timer.setParent(NamedTimerFactory::instance().getRootTimer());
+				timer.setParent(&DeclareTimer::getRootTimer());
 			}
 			
 			timer.mCountAverage = 0;
@@ -531,34 +455,29 @@ void LLFastTimer::NamedTimer::reset()
 	sCurFrameIndex = 0;
 }
 
-U32 LLFastTimer::NamedTimer::getHistoricalCount(S32 history_index) const
+U32 LLFastTimer::DeclareTimer::getHistoricalCount(S32 history_index) const
 {
-	S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::NamedTimer::HISTORY_NUM;
+	S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::DeclareTimer::HISTORY_NUM;
 	return mCountHistory[history_idx];
 }
 
-U32 LLFastTimer::NamedTimer::getHistoricalCalls(S32 history_index ) const
+U32 LLFastTimer::DeclareTimer::getHistoricalCalls(S32 history_index ) const
 {
-	S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::NamedTimer::HISTORY_NUM;
+	S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::DeclareTimer::HISTORY_NUM;
 	return mCallHistory[history_idx];
 }
 
-LLFastTimer::FrameState& LLFastTimer::NamedTimer::getFrameState() const
-{
-	return *mFrameState;
-}
-
-std::vector<LLFastTimer::NamedTimer*>::const_iterator LLFastTimer::NamedTimer::beginChildren()
+std::vector<LLFastTimer::DeclareTimer*>::const_iterator LLFastTimer::DeclareTimer::beginChildren()
 { 
 	return mChildren.begin(); 
 }
 
-std::vector<LLFastTimer::NamedTimer*>::const_iterator LLFastTimer::NamedTimer::endChildren()
+std::vector<LLFastTimer::DeclareTimer*>::const_iterator LLFastTimer::DeclareTimer::endChildren()
 {
 	return mChildren.end();
 }
 
-std::vector<LLFastTimer::NamedTimer*>& LLFastTimer::NamedTimer::getChildren()
+std::vector<LLFastTimer::DeclareTimer*>& LLFastTimer::DeclareTimer::getChildren()
 {
 	return mChildren;
 }
@@ -575,12 +494,12 @@ void LLFastTimer::nextFrame()
 
 	if (!sPauseHistory)
 	{
-		NamedTimer::processTimes();
+		DeclareTimer::processTimes();
 		sLastFrameIndex = sCurFrameIndex++;
 	}
 	
 	// get ready for next frame
-	NamedTimer::resetFrame();
+	DeclareTimer::resetFrame();
 	sLastFrameTime = frame_time;
 }
 
@@ -588,17 +507,17 @@ void LLFastTimer::nextFrame()
 void LLFastTimer::dumpCurTimes()
 {
 	// accumulate timings, etc.
-	NamedTimer::processTimes();
+	DeclareTimer::processTimes();
 	
 	F64 clock_freq = (F64)countsPerSecond();
 	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(*NamedTimerFactory::instance().getRootTimer());
+	for(timer_tree_dfs_iterator_t it = begin_timer_tree(DeclareTimer::getRootTimer());
 		it != end_timer_tree();
 		++it)
 	{
-		NamedTimer* timerp = (*it);
+		DeclareTimer* timerp = (*it);
 		F64 total_time_ms = ((F64)timerp->getHistoricalCount(0) * iclock_freq);
 		// Don't bother with really brief times, keep output concise
 		if (total_time_ms < 0.1) continue;
@@ -621,7 +540,7 @@ void LLFastTimer::dumpCurTimes()
 //static 
 void LLFastTimer::reset()
 {
-	NamedTimer::reset();
+	DeclareTimer::reset();
 }
 
 
@@ -637,22 +556,3 @@ void LLFastTimer::writeLog(std::ostream& os)
 	}
 }
 
-//static
-const LLFastTimer::NamedTimer* LLFastTimer::getTimerByName(const std::string& name)
-{
-	return NamedTimerFactory::instance().getTimerByName(name);
-}
-
-//LLFastTimer::LLFastTimer(LLFastTimer::FrameState* state)
-//:	mFrameState(state)
-//{
-//	U32 start_time = getCPUClockCount32();
-//	mStartTime = start_time;
-//	mFrameState->mActiveCount++;
-//	LLFastTimer::sCurTimerData.mCurTimer = this;
-//	LLFastTimer::sCurTimerData.mFrameState = mFrameState;
-//	LLFastTimer::sCurTimerData.mChildTime = 0;
-//	mLastTimerData = LLFastTimer::sCurTimerData;
-//}
-
-
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 4660fad5e3a..31872e4e657 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -30,7 +30,6 @@
 #include "llinstancetracker.h"
 
 #define FAST_TIMER_ON 1
-#define DEBUG_FAST_TIMER_THREADS 1
 
 class LLMutex;
 
@@ -45,64 +44,53 @@ LL_COMMON_API void assert_main_thread();
 class LL_COMMON_API LLFastTimer
 {
 public:
-	class NamedTimer;
-
+	class DeclareTimer;
 	struct LL_COMMON_API FrameState
 	{
 		FrameState();
-		void setNamedTimer(class NamedTimer* timerp) { mTimer = timerp; }
 
 		U32 				mSelfTimeCounter;
 		U32 				mTotalTimeCounter;
 		U32 				mCalls;
-		FrameState*			mParent;		// info for caller timer
-		FrameState*			mLastCaller;	// used to bootstrap tree construction
-		class NamedTimer*	mTimer;
+		DeclareTimer*		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
 	};
 
 	// stores a "named" timer instance to be reused via multiple LLFastTimer stack instances
-	class LL_COMMON_API NamedTimer
-	:	public LLInstanceTracker<NamedTimer>
+	class LL_COMMON_API DeclareTimer
+	:	public LLInstanceTracker<DeclareTimer>
 	{
-		friend class DeclareTimer;
 	public:
-		~NamedTimer();
+		DeclareTimer(const std::string& name, bool open = false, DeclareTimer* parent = &getRootTimer());
+		~DeclareTimer();
 
 		enum { HISTORY_NUM = 300 };
 
 		const std::string& getName() const { return mName; }
-		NamedTimer* getParent() const { return mParent; }
-		void setParent(NamedTimer* parent);
+		DeclareTimer* getParent() const { return mParent; }
+		void setParent(DeclareTimer* parent);
 		S32 getDepth();
-		std::string getToolTip(S32 history_index = -1);
 
-		typedef std::vector<NamedTimer*>::const_iterator child_const_iter;
+		typedef std::vector<DeclareTimer*>::const_iterator child_const_iter;
 		child_const_iter beginChildren();
 		child_const_iter endChildren();
-		std::vector<NamedTimer*>& getChildren();
+		std::vector<DeclareTimer*>& getChildren();
 
-		void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
-		bool getCollapsed() const { return mCollapsed; }
+		void setCollapsed(bool collapsed)	{ mCollapsed = collapsed; }
+		bool getCollapsed() const			{ return mCollapsed; }
 
 		U32 getCountAverage() const { return mCountAverage; }
-		U32 getCallAverage() const { return mCallAverage; }
+		U32 getCallAverage() const	{ return mCallAverage; }
 
 		U32 getHistoricalCount(S32 history_index = 0) const;
 		U32 getHistoricalCalls(S32 history_index = 0) const;
 
-		void setFrameState(FrameState* state) { mFrameState = state; state->setNamedTimer(this); }
-		FrameState& getFrameState() const;
+		static DeclareTimer& getRootTimer();
 
 	private:
 		friend class LLFastTimer;
-		friend class NamedTimerFactory;
 
-		//
-		// methods
-		//
-		NamedTimer(const std::string& name);
 		// recursive call to gather total time from children
 		static void accumulateTimings();
 
@@ -117,82 +105,62 @@ class LL_COMMON_API LLFastTimer
 		//
 		// members
 		//
-		FrameState*		mFrameState;
+		U32 						mSelfTimeCounter;
+		U32 						mTotalTimeCounter;
+		U32 						mCalls;
+		DeclareTimer*				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
 
-		std::string	mName;
+		std::string					mName;
 
-		// 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; 
+		// sum of recored self time and tree time of all children timers (might not match actual recorded time of children if topology is incomplete
+		U32 						mTreeTimeCounter; 
 
-		U32 		mCountAverage;
-		U32			mCallAverage;
+		U32 						mCountAverage;
+		U32							mCallAverage;
 
-		U32*		mCountHistory;
-		U32*		mCallHistory;
+		U32*						mCountHistory;
+		U32*						mCallHistory;
 
 		// tree structure
-		NamedTimer*					mParent;				// NamedTimer of caller(parent)
-		std::vector<NamedTimer*>	mChildren;
+		DeclareTimer*				mParent;				// DeclareTimer of caller(parent)
+		std::vector<DeclareTimer*>	mChildren;
 		bool						mCollapsed;				// don't show children
 		bool						mNeedsSorting;			// sort children whenever child added
 	};
 
-	// used to statically declare a new named timer
-	class LL_COMMON_API DeclareTimer
-	:	public LLInstanceTracker<DeclareTimer>
-	{
-		friend class LLFastTimer;
-	public:
-		DeclareTimer(const std::string& name, bool open);
-		DeclareTimer(const std::string& name);
-
-		NamedTimer& getNamedTimer() { return mTimer; }
-
-	private:
-		FrameState		mFrameState;
-		NamedTimer&		mTimer;
-	};
-
 public:
-	//LLFastTimer(LLFastTimer::FrameState* state);
-
 	LL_FORCE_INLINE LLFastTimer(LLFastTimer::DeclareTimer& timer)
 	{
 #if FAST_TIMER_ON
-		LLFastTimer::FrameState* frame_state = &timer.mFrameState;
 		mStartTime = getCPUClockCount32();
 
-		frame_state->mActiveCount++;
-		frame_state->mCalls++;
+		timer.mActiveCount++;
+		timer.mCalls++;
 		// keep current parent as long as it is active when we are
-		frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0);
+		timer.mMoveUpTree |= (timer.mParent->mActiveCount == 0);
 
 		LLFastTimer::CurTimerData* cur_timer_data = &LLFastTimer::sCurTimerData;
 		mLastTimerData = *cur_timer_data;
 		cur_timer_data->mCurTimer = this;
-		cur_timer_data->mFrameState = frame_state;
+		cur_timer_data->mTimerData = &timer;
 		cur_timer_data->mChildTime = 0;
-#endif
-#if DEBUG_FAST_TIMER_THREADS
-#if !LL_RELEASE
-		assert_main_thread();
-#endif
 #endif
 	}
 
 	LL_FORCE_INLINE ~LLFastTimer()
 	{
 #if FAST_TIMER_ON
-		LLFastTimer::FrameState* frame_state = LLFastTimer::sCurTimerData.mFrameState;
 		U32 total_time = getCPUClockCount32() - mStartTime;
-
-		frame_state->mSelfTimeCounter += total_time - LLFastTimer::sCurTimerData.mChildTime;
-		frame_state->mTotalTimeCounter += total_time;
-		frame_state->mActiveCount--;
+		DeclareTimer* timer_data = LLFastTimer::sCurTimerData.mTimerData;
+		timer_data->mSelfTimeCounter += total_time - LLFastTimer::sCurTimerData.mChildTime;
+		timer_data->mTotalTimeCounter += total_time;
+		timer_data->mActiveCount--;
 
 		// store last caller to bootstrap tree creation
 		// do this in the destructor in case of recursion to get topmost caller
-		frame_state->mLastCaller = mLastTimerData.mFrameState;
+		timer_data->mLastCaller = mLastTimerData.mTimerData;
 
 		// we are only tracking self time, so subtract our total time delta from parents
 		mLastTimerData.mChildTime += total_time;
@@ -225,12 +193,11 @@ class LL_COMMON_API LLFastTimer
 	static S32 getCurFrameIndex() { return sCurFrameIndex; }
 
 	static void writeLog(std::ostream& os);
-	static const NamedTimer* getTimerByName(const std::string& name);
 
 	struct CurTimerData
 	{
 		LLFastTimer*	mCurTimer;
-		FrameState*		mFrameState;
+		DeclareTimer*	mTimerData;
 		U32				mChildTime;
 	};
 	static CurTimerData		sCurTimerData;
@@ -374,15 +341,13 @@ class LL_COMMON_API LLFastTimer
 
 #endif
 
-	static U64 sClockResolution;
-
-	static S32				sCurFrameIndex;
-	static S32				sLastFrameIndex;
-	static U64				sLastFrameTime;
+	static U64	sClockResolution;
+	static S32	sCurFrameIndex;
+	static S32	sLastFrameIndex;
+	static U64	sLastFrameTime;
 
 	U32							mStartTime;
 	LLFastTimer::CurTimerData	mLastTimerData;
-
 };
 
 typedef class LLFastTimer LLFastTimer;
diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp
index fd8f603d21c..87a5930c14b 100644
--- a/indra/llcommon/llprocessor.cpp
+++ b/indra/llcommon/llprocessor.cpp
@@ -877,7 +877,7 @@ LLProcessorInfo::LLProcessorInfo() : mImpl(NULL)
 
 
 LLProcessorInfo::~LLProcessorInfo() {}
-F64 LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); }
+LLUnit<LLUnits::Megahertz, F64> LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); }
 bool LLProcessorInfo::hasSSE() const { return mImpl->hasSSE(); }
 bool LLProcessorInfo::hasSSE2() const { return mImpl->hasSSE2(); }
 bool LLProcessorInfo::hasAltivec() const { return mImpl->hasAltivec(); }
diff --git a/indra/llcommon/llprocessor.h b/indra/llcommon/llprocessor.h
index 6364d3c8bb2..2a21a5c1157 100644
--- a/indra/llcommon/llprocessor.h
+++ b/indra/llcommon/llprocessor.h
@@ -27,6 +27,8 @@
 
 #ifndef LLPROCESSOR_H
 #define LLPROCESSOR_H
+#include "llunit.h"
+
 class LLProcessorInfoImpl;
 
 class LL_COMMON_API LLProcessorInfo
@@ -35,7 +37,7 @@ class LL_COMMON_API LLProcessorInfo
 	LLProcessorInfo(); 
  	~LLProcessorInfo();
 
-	F64 getCPUFrequency() const;
+	LLUnit<LLUnits::Megahertz, F64> getCPUFrequency() const;
 	bool hasSSE() const;
 	bool hasSSE2() const;
 	bool hasAltivec() const;
diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp
index d5911ece252..3f605f2c743 100644
--- a/indra/llcommon/lltrace.cpp
+++ b/indra/llcommon/lltrace.cpp
@@ -42,6 +42,7 @@ void init()
 void cleanup()
 {
 	delete gMasterThreadRecorder;
+	LLUnitStrict<LLUnits::Seconds, F32> seconds;
 	gMasterThreadRecorder = NULL;
 }
 
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index d289ea9a88c..549e4078220 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -57,8 +57,6 @@ namespace LLTrace
 	typedef LLUnit<LLUnits::Milliseconds, F64>	Milliseconds;
 	typedef LLUnit<LLUnits::Minutes, F64>		Minutes;
 	typedef LLUnit<LLUnits::Hours, F64>			Hours;
-	typedef LLUnit<LLUnits::Days, F64>			Days;
-	typedef LLUnit<LLUnits::Weeks, F64>			Weeks;
 	typedef LLUnit<LLUnits::Milliseconds, F64>	Milliseconds;
 	typedef LLUnit<LLUnits::Microseconds, F64>	Microseconds;
 	typedef LLUnit<LLUnits::Nanoseconds, F64>	Nanoseconds;
@@ -226,27 +224,6 @@ namespace LLTrace
 		size_t		mAccumulatorIndex;
 	};
 
-
-	template<typename T, typename IS_UNIT = void>
-	struct StorageType
-	{
-		typedef T type_t;
-	};
-
-	template<typename T>
-	struct StorageType<T, typename T::is_unit_tag_t>
-	{
-		typedef typename StorageType<typename T::storage_t>::type_t type_t;
-	};
-
-	template<> struct StorageType<F32> { typedef F64 type_t; };
-	template<> struct StorageType<S32> { typedef S64 type_t; };
-	template<> struct StorageType<U32> { typedef S64 type_t; };
-	template<> struct StorageType<S16> { typedef S64 type_t; };
-	template<> struct StorageType<U16> { typedef S64 type_t; };
-	template<> struct StorageType<S8> { typedef S64 type_t; };
-	template<> struct StorageType<U8> { typedef S64 type_t; };
-
 	template<typename T>
 	class LL_COMMON_API MeasurementAccumulator
 	{
@@ -406,10 +383,10 @@ namespace LLTrace
 
 	template <typename T = F64, typename IS_UNIT = void>
 	class LL_COMMON_API Measurement
-	:	public TraceType<MeasurementAccumulator<typename StorageType<T>::type_t> >
+	:	public TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >
 	{
 	public:
-		typedef typename StorageType<T>::type_t storage_t;
+		typedef typename LLUnits::HighestPrecisionType<T>::type_t storage_t;
 
 		Measurement(const char* name, const char* description = NULL) 
 		:	TraceType(name, description)
@@ -423,10 +400,10 @@ namespace LLTrace
 
 	template <typename T>
 	class LL_COMMON_API Measurement <T, typename T::is_unit_tag_t>
-	:	public TraceType<MeasurementAccumulator<typename StorageType<typename T::storage_t>::type_t> >
+	:	public TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<typename T::storage_t>::type_t> >
 	{
 	public:
-		typedef typename StorageType<typename T::storage_t>::type_t storage_t;
+		typedef typename LLUnits::HighestPrecisionType<typename T::storage_t>::type_t storage_t;
 
 		Measurement(const char* name, const char* description = NULL) 
 		:	TraceType(name, description)
@@ -446,10 +423,10 @@ namespace LLTrace
 
 	template <typename T = F64, typename IS_UNIT = void>
 	class LL_COMMON_API Count 
-	:	public TraceType<CountAccumulator<typename StorageType<T>::type_t> >
+	:	public TraceType<CountAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >
 	{
 	public:
-		typedef typename StorageType<T>::type_t storage_t;
+		typedef typename LLUnits::HighestPrecisionType<T>::type_t storage_t;
 
 		Count(const char* name, const char* description = NULL) 
 		:	TraceType(name)
@@ -463,10 +440,10 @@ namespace LLTrace
 
 	template <typename T>
 	class LL_COMMON_API Count <T, typename T::is_unit_tag_t>
-	:	public TraceType<CountAccumulator<typename StorageType<typename T::storage_t>::type_t> >
+	:	public TraceType<CountAccumulator<typename LLUnits::HighestPrecisionType<typename T::storage_t>::type_t> >
 	{
 	public:
-		typedef typename StorageType<typename T::storage_t>::type_t storage_t;
+		typedef typename LLUnits::HighestPrecisionType<typename T::storage_t>::type_t storage_t;
 
 		Count(const char* name, const char* description = NULL) 
 		:	TraceType(name)
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h
index ca9950b78d3..16b80fd1d82 100644
--- a/indra/llcommon/lltracerecording.h
+++ b/indra/llcommon/lltracerecording.h
@@ -122,7 +122,7 @@ namespace LLTrace
 		template <typename T>
 		T getSum(const Count<T, typename T::is_unit_tag_t>& stat) const
 		{
-			return (T)getSum(static_cast<const TraceType<CountAccumulator<StorageType<T>::type_t> >&> (stat));
+			return (T)getSum(static_cast<const TraceType<CountAccumulator<LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
 		}
 
 		F64 getPerSec(const TraceType<CountAccumulator<F64> >& stat) const;
@@ -130,7 +130,7 @@ namespace LLTrace
 		template <typename T>
 		T getPerSec(const Count<T, typename T::is_unit_tag_t>& stat) const
 		{
-			return (T)getPerSec(static_cast<const TraceType<CountAccumulator<StorageType<T>::type_t> >&> (stat));
+			return (T)getPerSec(static_cast<const TraceType<CountAccumulator<LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
 		}
 
 		U32 getSampleCount(const TraceType<CountAccumulator<F64> >& stat) const;
@@ -143,7 +143,7 @@ namespace LLTrace
 		template <typename T>
 		T getSum(const Measurement<T, typename T::is_unit_tag_t>& stat) const
 		{
-			return (T)getSum(static_cast<const TraceType<MeasurementAccumulator<StorageType<T>::type_t> >&> (stat));
+			return (T)getSum(static_cast<const TraceType<MeasurementAccumulator<LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
 		}
 
 		F64 getPerSec(const TraceType<MeasurementAccumulator<F64> >& stat) const;
@@ -151,7 +151,7 @@ namespace LLTrace
 		template <typename T>
 		T getPerSec(const Measurement<T, typename T::is_unit_tag_t>& stat) const
 		{
-			return (T)getPerSec(static_cast<const TraceType<MeasurementAccumulator<StorageType<T>::type_t> >&> (stat));
+			return (T)getPerSec(static_cast<const TraceType<MeasurementAccumulator<LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
 		}
 
 		F64 getMin(const TraceType<MeasurementAccumulator<F64> >& stat) const;
@@ -159,7 +159,7 @@ namespace LLTrace
 		template <typename T>
 		T getMin(const Measurement<T, typename T::is_unit_tag_t>& stat) const
 		{
-			return (T)getMin(static_cast<const TraceType<MeasurementAccumulator<StorageType<T>::type_t> >&> (stat));
+			return (T)getMin(static_cast<const TraceType<MeasurementAccumulator<LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
 		}
 
 		F64 getMax(const TraceType<MeasurementAccumulator<F64> >& stat) const;
@@ -167,7 +167,7 @@ namespace LLTrace
 		template <typename T>
 		T getMax(const Measurement<T, typename T::is_unit_tag_t>& stat) const
 		{
-			return (T)getMax(static_cast<const TraceType<MeasurementAccumulator<StorageType<T>::type_t> >&> (stat));
+			return (T)getMax(static_cast<const TraceType<MeasurementAccumulator<LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
 		}
 
 		F64 getMean(const TraceType<MeasurementAccumulator<F64> >& stat) const;
@@ -175,7 +175,7 @@ namespace LLTrace
 		template <typename T>
 		T getMean(Measurement<T, typename T::is_unit_tag_t>& stat) const
 		{
-			return (T)getMean(static_cast<const TraceType<MeasurementAccumulator<StorageType<T>::type_t> >&> (stat));
+			return (T)getMean(static_cast<const TraceType<MeasurementAccumulator<LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
 		}
 
 		F64 getStandardDeviation(const TraceType<MeasurementAccumulator<F64> >& stat) const;
@@ -183,7 +183,7 @@ namespace LLTrace
 		template <typename T>
 		T getStandardDeviation(const Measurement<T, typename T::is_unit_tag_t>& stat) const
 		{
-			return (T)getMean(static_cast<const TraceType<MeasurementAccumulator<StorageType<T>::type_t> >&> (stat));
+			return (T)getMean(static_cast<const TraceType<MeasurementAccumulator<LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
 		}
 
 		F64 getLastValue(const TraceType<MeasurementAccumulator<F64> >& stat) const;
@@ -191,7 +191,7 @@ namespace LLTrace
 		template <typename T>
 		T getLastValue(const Measurement<T, typename T::is_unit_tag_t>& stat) const
 		{
-			return (T)getLastValue(static_cast<const TraceType<MeasurementAccumulator<StorageType<T>::type_t> >&> (stat));
+			return (T)getLastValue(static_cast<const TraceType<MeasurementAccumulator<LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
 		}
 
 		U32 getSampleCount(const TraceType<MeasurementAccumulator<F64> >& stat) const;
diff --git a/indra/llcommon/llunit.h b/indra/llcommon/llunit.h
index 0dcafbe26e2..54ba1d67db1 100644
--- a/indra/llcommon/llunit.h
+++ b/indra/llcommon/llunit.h
@@ -32,19 +32,44 @@
 
 namespace LLUnits
 {
-template<typename DERIVED_UNITS_TAG, typename BASE_UNITS_TAG>
+
+template<typename T, typename IS_UNIT = void>
+struct HighestPrecisionType
+{
+	typedef T type_t;
+};
+
+template<typename T>
+struct HighestPrecisionType<T, typename T::is_unit_tag_t>
+{
+	typedef typename HighestPrecisionType<typename T::storage_t>::type_t type_t;
+};
+
+template<> struct HighestPrecisionType<F32> { typedef F64 type_t; };
+template<> struct HighestPrecisionType<S32> { typedef S64 type_t; };
+template<> struct HighestPrecisionType<U32> { typedef S64 type_t; };
+template<> struct HighestPrecisionType<S16> { typedef S64 type_t; };
+template<> struct HighestPrecisionType<U16> { typedef S64 type_t; };
+template<> struct HighestPrecisionType<S8> { typedef S64 type_t; };
+template<> struct HighestPrecisionType<U8> { typedef S64 type_t; };
+
+template<typename DERIVED_UNITS_TAG, typename BASE_UNITS_TAG, typename VALUE_TYPE>
 struct ConversionFactor
 {
-	static F64 get()
+	static typename HighestPrecisionType<VALUE_TYPE>::type_t get()
 	{
+		// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
 		llstatic_assert(sizeof(DERIVED_UNITS_TAG) == 0, "Cannot convert between types.");
 	}
 };
 
-template<typename BASE_UNITS_TAG>
-struct ConversionFactor<BASE_UNITS_TAG, BASE_UNITS_TAG>
+template<typename BASE_UNITS_TAG, typename VALUE_TYPE>
+struct ConversionFactor<BASE_UNITS_TAG, BASE_UNITS_TAG, VALUE_TYPE>
 {
-	static F64 get() { return 1.0; }
+	static typename HighestPrecisionType<VALUE_TYPE>::type_t get() 
+	{ 
+		return 1; 
+	}
 };
 }
 
@@ -91,6 +116,11 @@ struct LLUnit
 		return mValue;
 	}
 
+	template<typename NEW_UNIT_TYPE> LLUnit<NEW_UNIT_TYPE, STORAGE_TYPE> as()
+	{
+		return LLUnit<NEW_UNIT_TYPE, STORAGE_TYPE>(*this);
+	}
+
 	void operator += (storage_t value)
 	{
 		mValue += value;
@@ -121,7 +151,8 @@ struct LLUnit
 	template<typename OTHER_UNIT, typename OTHER_STORAGE>
 	void operator *= (LLUnit<OTHER_UNIT, OTHER_STORAGE> multiplicand)
 	{
-		llstatic_assert(sizeof(OTHER_UNIT) == false, "Multiplication of unit types not supported.");
+		// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
+		llstatic_assert(sizeof(OTHER_UNIT) == 0, "Multiplication of unit types not supported.");
 	}
 
 	void operator /= (storage_t divisor)
@@ -132,15 +163,16 @@ struct LLUnit
 	template<typename OTHER_UNIT, typename OTHER_STORAGE>
 	void operator /= (LLUnit<OTHER_UNIT, OTHER_STORAGE> divisor)
 	{
-		llstatic_assert(sizeof(OTHER_UNIT) == false, "Division of unit types not supported.");
+		// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
+		llstatic_assert(sizeof(OTHER_UNIT) == 0, "Division of unit types not supported.");
 	}
 
-	template<typename SOURCE_UNITS, typename SOURCE_VALUE>
-	static storage_t convert(LLUnit<SOURCE_UNITS, SOURCE_VALUE> v) 
+	template<typename SOURCE_UNITS, typename SOURCE_STORAGE>
+	static storage_t convert(LLUnit<SOURCE_UNITS, SOURCE_STORAGE> v) 
 	{ 
 		return (storage_t)(v.value() 
-			* LLUnits::ConversionFactor<SOURCE_UNITS, typename UNIT_TYPE::base_unit_t>::get() 
-			* LLUnits::ConversionFactor<typename UNIT_TYPE::base_unit_t, UNIT_TYPE>::get()); 
+			* LLUnits::ConversionFactor<SOURCE_UNITS, typename UNIT_TYPE::base_unit_t, SOURCE_STORAGE>::get() 
+			* LLUnits::ConversionFactor<typename UNIT_TYPE::base_unit_t, UNIT_TYPE, STORAGE_TYPE>::get()); 
 	}
 
 protected:
@@ -148,6 +180,32 @@ struct LLUnit
 	storage_t mValue;
 };
 
+template<typename UNIT_TYPE, typename STORAGE_TYPE>
+struct LLUnitStrict : public LLUnit<UNIT_TYPE, STORAGE_TYPE>
+{
+	typedef LLUnitStrict<UNIT_TYPE, STORAGE_TYPE> self_t;
+
+	explicit LLUnitStrict(storage_t value = storage_t())
+	:	LLUnit(value)
+	{}
+
+	template<typename OTHER_UNIT, typename OTHER_STORAGE>
+	LLUnitStrict(LLUnit<OTHER_UNIT, OTHER_STORAGE> other)
+	:	LLUnit(convert(other))
+	{}
+
+	LLUnitStrict(self_t& other)
+	:	LLUnit(other)
+	{}
+
+
+private:
+	operator storage_t() const
+	{
+		return value();
+	}
+};
+
 //
 // operator +
 //
@@ -221,7 +279,8 @@ LLUnit<STORAGE_TYPE, UNIT_TYPE> operator * (LLUnit<STORAGE_TYPE, UNIT_TYPE> firs
 template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2>
 void operator * (LLUnit<STORAGE_TYPE1, UNIT_TYPE1>, LLUnit<STORAGE_TYPE2, UNIT_TYPE2>)
 {
-	llstatic_assert(sizeof(STORAGE_TYPE1) == false, "Multiplication of unit types results in new unit type - not supported.");
+	// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
+	llstatic_assert(sizeof(STORAGE_TYPE1) == 0, "Multiplication of unit types results in new unit type - not supported.");
 }
 
 //
@@ -242,7 +301,8 @@ LLUnit<STORAGE_TYPE, UNIT_TYPE> operator / (LLUnit<STORAGE_TYPE, UNIT_TYPE> firs
 template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2>
 void operator / (LLUnit<STORAGE_TYPE1, UNIT_TYPE1>, LLUnit<STORAGE_TYPE2, UNIT_TYPE2>)
 {
-	llstatic_assert(sizeof(STORAGE_TYPE1) == false, "Multiplication of unit types results in new unit type - not supported.");
+	// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
+	llstatic_assert(sizeof(STORAGE_TYPE1) == 0, "Multiplication of unit types results in new unit type - not supported.");
 }
 
 #define COMPARISON_OPERATORS(op)                                                                     \
@@ -273,21 +333,21 @@ COMPARISON_OPERATORS(!=)
 
 namespace LLUnits
 {
-#define LL_DECLARE_DERIVED_UNIT(base_unit_name, unit_name, conversion_factor)\
-struct unit_name                                                             \
-{                                                                            \
-	typedef base_unit_name base_unit_t;                                      \
-};                                                                           \
-template<>                                                                   \
-struct ConversionFactor<unit_name, base_unit_name>                           \
-{                                                                            \
-	static F64 get() { return (conversion_factor); }                         \
-};                                                                           \
-	                                                                         \
-template<>                                                                   \
-struct ConversionFactor<base_unit_name, unit_name>						     \
-{                                                                            \
-	static F64 get() { return 1.0 / (conversion_factor); }                   \
+#define LL_DECLARE_DERIVED_UNIT(base_unit_name, unit_name, conversion_factor)                                                                                   \
+struct unit_name                                                                                                                                                \
+{                                                                                                                                                               \
+	typedef base_unit_name base_unit_t;                                                                                                                         \
+};                                                                                                                                                              \
+template<typename STORAGE_TYPE>                                                                                                                                 \
+struct ConversionFactor<unit_name, base_unit_name, STORAGE_TYPE>                                                                                                \
+{                                                                                                                                                               \
+	static typename HighestPrecisionType<STORAGE_TYPE>::type_t get() { return typename HighestPrecisionType<STORAGE_TYPE>::type_t(conversion_factor); }         \
+};                                                                                                                                                              \
+	                                                                                                                                                            \
+template<typename STORAGE_TYPE>                                                                                                                                 \
+struct ConversionFactor<base_unit_name, unit_name, STORAGE_TYPE>						                                                                        \
+{                                                                                                                                                               \
+	static typename HighestPrecisionType<STORAGE_TYPE>::type_t get() { return typename HighestPrecisionType<STORAGE_TYPE>::type_t(1.0 / (conversion_factor)); } \
 }
 
 struct Bytes { typedef Bytes base_unit_t; };
@@ -302,16 +362,19 @@ LL_DECLARE_DERIVED_UNIT(Bytes, Gigabits,  (1024 * 1024 * 1024 / 8));
 struct Seconds { typedef Seconds base_unit_t; };
 LL_DECLARE_DERIVED_UNIT(Seconds, Minutes,		60);
 LL_DECLARE_DERIVED_UNIT(Seconds, Hours,			60 * 60);
-LL_DECLARE_DERIVED_UNIT(Seconds, Days,			60 * 60 * 24);
-LL_DECLARE_DERIVED_UNIT(Seconds, Weeks,			60 * 60 * 24 * 7);
 LL_DECLARE_DERIVED_UNIT(Seconds, Milliseconds,	(1.0 / 1000.0));
 LL_DECLARE_DERIVED_UNIT(Seconds, Microseconds,	(1.0 / (1000000.0)));
 LL_DECLARE_DERIVED_UNIT(Seconds, Nanoseconds,	(1.0 / (1000000000.0)));
 
 struct Meters { typedef Meters base_unit_t; };
 LL_DECLARE_DERIVED_UNIT(Meters, Kilometers, 1000);
-LL_DECLARE_DERIVED_UNIT(Meters, Centimeters, (1.0 / 100));
-LL_DECLARE_DERIVED_UNIT(Meters, Millimeters, (1.0 / 1000));
+LL_DECLARE_DERIVED_UNIT(Meters, Centimeters, (1.0 / 100.0));
+LL_DECLARE_DERIVED_UNIT(Meters, Millimeters, (1.0 / 1000.0));
+
+struct Hertz { typedef Hertz base_unit_t; };
+LL_DECLARE_DERIVED_UNIT(Hertz, Kilohertz, 1000);
+LL_DECLARE_DERIVED_UNIT(Hertz, Megahertz, 1000 * 1000);
+LL_DECLARE_DERIVED_UNIT(Hertz, Gigahertz, 1000 * 1000 * 1000);
 }
 
 #endif // LL_LLUNIT_H
diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp
index 065b20ba2b8..0934028a8c9 100644
--- a/indra/newview/llfasttimerview.cpp
+++ b/indra/newview/llfasttimerview.cpp
@@ -61,17 +61,17 @@ static const S32 LINE_GRAPH_HEIGHT = 240;
 static S32 FTV_NUM_TIMERS;
 const S32 FTV_MAX_DEPTH = 8;
 
-std::vector<LLFastTimer::NamedTimer*> ft_display_idx; // line of table entry for display purposes (for collapse)
+std::vector<LLFastTimer::DeclareTimer*> ft_display_idx; // line of table entry for display purposes (for collapse)
 
-typedef LLTreeDFSIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_iterator_t;
+typedef LLTreeDFSIter<LLFastTimer::DeclareTimer, LLFastTimer::DeclareTimer::child_const_iter> timer_tree_iterator_t;
 
 BOOL LLFastTimerView::sAnalyzePerformance = FALSE;
 
-static timer_tree_iterator_t begin_timer_tree(LLFastTimer::NamedTimer& id) 
+static timer_tree_iterator_t begin_timer_tree(LLFastTimer::DeclareTimer& id) 
 { 
 	return timer_tree_iterator_t(&id, 
-							boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1), 
-							boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1));
+							boost::bind(boost::mem_fn(&LLFastTimer::DeclareTimer::beginChildren), _1), 
+							boost::bind(boost::mem_fn(&LLFastTimer::DeclareTimer::endChildren), _1));
 }
 
 static timer_tree_iterator_t end_timer_tree() 
@@ -92,7 +92,7 @@ LLFastTimerView::LLFastTimerView(const LLSD& key)
 	mScrollIndex = 0;
 	mHoverID = NULL;
 	mHoverBarIndex = -1;
-	FTV_NUM_TIMERS = LLFastTimer::NamedTimer::instanceCount();
+	FTV_NUM_TIMERS = LLFastTimer::DeclareTimer::instanceCount();
 	mPrintStats = -1;	
 }
 
@@ -139,13 +139,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 = LLFastTimer::NamedTimer::HISTORY_NUM - mScrollIndex - bar_idx;
+		mPrintStats = LLFastTimer::DeclareTimer::HISTORY_NUM - mScrollIndex - bar_idx;
 		return TRUE;
 	}
 	return LLFloater::handleRightMouseDown(x, y, mask);
 }
 
-LLFastTimer::NamedTimer* LLFastTimerView::getLegendID(S32 y)
+LLFastTimer::DeclareTimer* LLFastTimerView::getLegendID(S32 y)
 {
 	S32 idx = (getRect().getHeight() - y) / (LLFontGL::getFontMonospace()->getLineHeight()+2) - 5;
 
@@ -172,7 +172,7 @@ BOOL LLFastTimerView::handleMouseDown(S32 x, S32 y, MASK mask)
 {
 	if (x < mBarRect.mLeft) 
 	{
-		LLFastTimer::NamedTimer* idp = getLegendID(y);
+		LLFastTimer::DeclareTimer* idp = getLegendID(y);
 		if (idp)
 		{
 			idp->setCollapsed(!idp->getCollapsed());
@@ -235,7 +235,7 @@ BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask)
 	if (hasMouseCapture())
 	{
 		F32 lerp = llclamp(1.f - (F32) (x - mGraphRect.mLeft) / (F32) mGraphRect.getWidth(), 0.f, 1.f);
-		mScrollIndex = llround( lerp * (F32)(LLFastTimer::NamedTimer::HISTORY_NUM - MAX_VISIBLE_HISTORY));
+		mScrollIndex = llround( lerp * (F32)(LLFastTimer::DeclareTimer::HISTORY_NUM - MAX_VISIBLE_HISTORY));
 		mScrollIndex = llclamp(	mScrollIndex, 0, LLFastTimer::getLastFrameIndex());
 		return TRUE;
 	}
@@ -288,7 +288,7 @@ BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask)
 	}
 	else if (x < mBarRect.mLeft) 
 	{
-		LLFastTimer::NamedTimer* timer_id = getLegendID(y);
+		LLFastTimer::DeclareTimer* timer_id = getLegendID(y);
 		if (timer_id)
 		{
 			mHoverID = timer_id;
@@ -299,6 +299,23 @@ BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask)
 }
 
 
+static std::string get_tooltip(LLFastTimer::DeclareTimer& timer, S32 history_index = -1)
+{
+	F64 ms_multiplier = 1000.0 / (F64)LLFastTimer::countsPerSecond();
+
+	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)(timer.getCountAverage() * ms_multiplier), (S32)timer.getCallAverage());
+	}
+	else
+	{
+		tooltip = llformat("%s (%d ms, %d calls)", timer.getName().c_str(), (S32)(timer.getHistoricalCount(history_index) * ms_multiplier), (S32)timer.getHistoricalCalls(history_index));
+	}
+	return tooltip;
+}
+
 BOOL LLFastTimerView::handleToolTip(S32 x, S32 y, MASK mask)
 {
 	if(LLFastTimer::sPauseHistory && mBarRect.pointInRect(x, y))
@@ -309,8 +326,10 @@ BOOL LLFastTimerView::handleToolTip(S32 x, S32 y, MASK mask)
 			LLRect screen_rect;
 			localRectToScreen(mToolTipRect, &screen_rect);
 
+			std::string tooltip = get_tooltip(*mHoverTimer, LLFastTimer::DeclareTimer::HISTORY_NUM - mScrollIndex - mHoverBarIndex);
+
 			LLToolTipMgr::instance().show(LLToolTip::Params()
-				.message(mHoverTimer->getToolTip(LLFastTimer::NamedTimer::HISTORY_NUM - mScrollIndex - mHoverBarIndex))
+				.message(tooltip)
 				.sticky_rect(screen_rect)
 				.delay_time(0.f));
 
@@ -322,10 +341,10 @@ BOOL LLFastTimerView::handleToolTip(S32 x, S32 y, MASK mask)
 		// tooltips for timer legend
 		if (x < mBarRect.mLeft) 
 		{
-			LLFastTimer::NamedTimer* idp = getLegendID(y);
+			LLFastTimer::DeclareTimer* idp = getLegendID(y);
 			if (idp)
 			{
-				LLToolTipMgr::instance().show(idp->getToolTip());
+				LLToolTipMgr::instance().show(get_tooltip(*idp));
 
 				return TRUE;
 			}
@@ -340,13 +359,13 @@ BOOL LLFastTimerView::handleScrollWheel(S32 x, S32 y, S32 clicks)
 	LLFastTimer::sPauseHistory = TRUE;
 	mScrollIndex = llclamp(	mScrollIndex + clicks,
 							0,
-							llmin(LLFastTimer::getLastFrameIndex(), (S32)LLFastTimer::NamedTimer::HISTORY_NUM - MAX_VISIBLE_HISTORY));
+							llmin(LLFastTimer::getLastFrameIndex(), (S32)LLFastTimer::DeclareTimer::HISTORY_NUM - MAX_VISIBLE_HISTORY));
 	return TRUE;
 }
 
 static LLFastTimer::DeclareTimer FTM_RENDER_TIMER("Timers", true);
 
-static std::map<LLFastTimer::NamedTimer*, LLColor4> sTimerColors;
+static std::map<LLFastTimer::DeclareTimer*, LLColor4> sTimerColors;
 
 void LLFastTimerView::draw()
 {
@@ -426,7 +445,7 @@ void LLFastTimerView::draw()
 		it != timer_tree_iterator_t();
 		++it)
 	{
-		LLFastTimer::NamedTimer* idp = (*it);
+		LLFastTimer::DeclareTimer* idp = (*it);
 
 		const F32 HUE_INCREMENT = 0.23f;
 		hue = fmodf(hue + HUE_INCREMENT, 1.f);
@@ -446,12 +465,12 @@ void LLFastTimerView::draw()
 		LLLocalClipRect clip(LLRect(margin, y, LEGEND_WIDTH, margin));
 		S32 cur_line = 0;
 		ft_display_idx.clear();
-		std::map<LLFastTimer::NamedTimer*, S32> display_line;
+		std::map<LLFastTimer::DeclareTimer*, S32> display_line;
 		for (timer_tree_iterator_t it = begin_timer_tree(getFrameTimer());
 			it != timer_tree_iterator_t();
 			++it)
 		{
-			LLFastTimer::NamedTimer* idp = (*it);
+			LLFastTimer::DeclareTimer* idp = (*it);
 			display_line[idp] = cur_line;
 			ft_display_idx.push_back(idp);
 			cur_line++;
@@ -471,7 +490,7 @@ void LLFastTimerView::draw()
 			S32 calls = 0;
 			if (mHoverBarIndex > 0 && mHoverID)
 			{
-				S32 hidx = LLFastTimer::NamedTimer::HISTORY_NUM - mScrollIndex - mHoverBarIndex;
+				S32 hidx = LLFastTimer::DeclareTimer::HISTORY_NUM - mScrollIndex - mHoverBarIndex;
 				U64 ticks = idp->getHistoricalCount(hidx);
 				ms = (F32)((F64)ticks * iclock_freq);
 				calls = (S32)idp->getHistoricalCalls(hidx);
@@ -509,7 +528,7 @@ void LLFastTimerView::draw()
 
 			x += dx;
 			BOOL is_child_of_hover_item = (idp == mHoverID);
-			LLFastTimer::NamedTimer* next_parent = idp->getParent();
+			LLFastTimer::DeclareTimer* next_parent = idp->getParent();
 			while(!is_child_of_hover_item && next_parent)
 			{
 				is_child_of_hover_item = (mHoverID == next_parent);
@@ -687,7 +706,7 @@ void LLFastTimerView::draw()
 			S32 tidx;
 			if (j >= 0)
 			{
-				tidx = LLFastTimer::NamedTimer::HISTORY_NUM - j - 1 - mScrollIndex;
+				tidx = LLFastTimer::DeclareTimer::HISTORY_NUM - j - 1 - mScrollIndex;
 			}
 			else
 			{
@@ -701,14 +720,14 @@ void LLFastTimerView::draw()
 			std::vector<S32> deltax;
 			xpos.push_back(xleft);
 			
-			LLFastTimer::NamedTimer* prev_id = NULL;
+			LLFastTimer::DeclareTimer* prev_id = NULL;
 
 			S32 i = 0;
 			for(timer_tree_iterator_t it = begin_timer_tree(getFrameTimer());
 				it != end_timer_tree();
 				++it, ++i)
 			{
-				LLFastTimer::NamedTimer* idp = (*it);
+				LLFastTimer::DeclareTimer* idp = (*it);
 				F32 frac = tidx == -1
 					? (F32)idp->getCountAverage() / (F32)totalticks 
 					: (F32)idp->getHistoricalCount(tidx) / (F32)totalticks;
@@ -735,7 +754,7 @@ void LLFastTimerView::draw()
 				{
 					U64 sublevelticks = 0;
 
-					for (LLFastTimer::NamedTimer::child_const_iter it = prev_id->beginChildren();
+					for (LLFastTimer::DeclareTimer::child_const_iter it = prev_id->beginChildren();
 						it != prev_id->endChildren();
 						++it)
 					{
@@ -777,7 +796,7 @@ void LLFastTimerView::draw()
 					S32 scale_offset = 0;
 
 					BOOL is_child_of_hover_item = (idp == mHoverID);
-					LLFastTimer::NamedTimer* next_parent = idp->getParent();
+					LLFastTimer::DeclareTimer* next_parent = idp->getParent();
 					while(!is_child_of_hover_item && next_parent)
 					{
 						is_child_of_hover_item = (mHoverID == next_parent);
@@ -842,10 +861,10 @@ void LLFastTimerView::draw()
 
 			//highlight visible range
 			{
-				S32 first_frame = LLFastTimer::NamedTimer::HISTORY_NUM - mScrollIndex;
+				S32 first_frame = LLFastTimer::DeclareTimer::HISTORY_NUM - mScrollIndex;
 				S32 last_frame = first_frame - MAX_VISIBLE_HISTORY;
 				
-				F32 frame_delta = ((F32) (mGraphRect.getWidth()))/(LLFastTimer::NamedTimer::HISTORY_NUM-1);
+				F32 frame_delta = ((F32) (mGraphRect.getWidth()))/(LLFastTimer::DeclareTimer::HISTORY_NUM-1);
 				
 				F32 right = (F32) mGraphRect.mLeft + frame_delta*first_frame;
 				F32 left = (F32) mGraphRect.mLeft + frame_delta*last_frame;
@@ -872,7 +891,7 @@ void LLFastTimerView::draw()
 				it != end_timer_tree();
 				++it)
 			{
-				LLFastTimer::NamedTimer* idp = (*it);
+				LLFastTimer::DeclareTimer* idp = (*it);
 				
 				//fatten highlighted timer
 				if (mHoverID == idp)
@@ -896,8 +915,8 @@ void LLFastTimerView::draw()
 
 				gGL.color4f(col[0], col[1], col[2], alpha);				
 				gGL.begin(LLRender::TRIANGLE_STRIP);
-				for (U32 j = llmax(0, LLFastTimer::NamedTimer::HISTORY_NUM - LLFastTimer::getLastFrameIndex());
-					j < LLFastTimer::NamedTimer::HISTORY_NUM;
+				for (U32 j = llmax(0, LLFastTimer::DeclareTimer::HISTORY_NUM - LLFastTimer::getLastFrameIndex());
+					j < LLFastTimer::DeclareTimer::HISTORY_NUM;
 					j++)
 				{
 					U64 ticks = idp->getHistoricalCount(j);
@@ -918,7 +937,7 @@ void LLFastTimerView::draw()
 						//normalize to highlighted timer
 						cur_max = llmax(cur_max, ticks);
 					}
-					F32 x = mGraphRect.mLeft + ((F32) (mGraphRect.getWidth()))/(LLFastTimer::NamedTimer::HISTORY_NUM-1)*j;
+					F32 x = mGraphRect.mLeft + ((F32) (mGraphRect.getWidth()))/(LLFastTimer::DeclareTimer::HISTORY_NUM-1)*j;
 					F32 y = mGraphRect.mBottom + (F32) mGraphRect.getHeight()/max_ticks*ticks;
 					gGL.vertex2f(x,y);
 					gGL.vertex2f(x,mGraphRect.mBottom);
@@ -973,7 +992,7 @@ void LLFastTimerView::draw()
 			it != end_timer_tree();
 			++it)
 		{
-			LLFastTimer::NamedTimer* idp = (*it);
+			LLFastTimer::DeclareTimer* idp = (*it);
 
 			if (!first)
 			{
@@ -995,7 +1014,7 @@ void LLFastTimerView::draw()
 			it != end_timer_tree();
 			++it)
 		{
-			LLFastTimer::NamedTimer* idp = (*it);
+			LLFastTimer::DeclareTimer* idp = (*it);
 
 			if (!first)
 			{
@@ -1033,11 +1052,8 @@ void LLFastTimerView::draw()
 
 F64 LLFastTimerView::getTime(const std::string& name)
 {
-	const LLFastTimer::NamedTimer* timerp = LLFastTimer::getTimerByName(name);
-	if (timerp)
-	{
-		return (F64)timerp->getCountAverage() / (F64)LLFastTimer::countsPerSecond();
-	}
+	//TODO: replace calls to this with use of timer object directly
+	//llstatic_assert(false, "TODO: implement");
 	return 0.0;
 }
 
@@ -1552,9 +1568,9 @@ void	LLFastTimerView::onClickCloseBtn()
 	setVisible(false);
 }
 
-LLFastTimer::NamedTimer& LLFastTimerView::getFrameTimer()
+LLFastTimer::DeclareTimer& LLFastTimerView::getFrameTimer()
 {
-	return FTM_FRAME.getNamedTimer();
+	return FTM_FRAME;
 }
 
 
diff --git a/indra/newview/llfasttimerview.h b/indra/newview/llfasttimerview.h
index 5766cfa0b05..01a3501e4b7 100644
--- a/indra/newview/llfasttimerview.h
+++ b/indra/newview/llfasttimerview.h
@@ -46,7 +46,7 @@ class LLFastTimerView : public LLFloater
 	static LLSD analyzePerformanceLogDefault(std::istream& is) ;
 	static void exportCharts(const std::string& base, const std::string& target);
 	void onPause();
-	LLFastTimer::NamedTimer& getFrameTimer();
+	LLFastTimer::DeclareTimer& getFrameTimer();
 
 public:
 
@@ -59,7 +59,7 @@ class LLFastTimerView : public LLFloater
 	virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
 	virtual void draw();
 
-	LLFastTimer::NamedTimer* getLegendID(S32 y);
+	LLFastTimer::DeclareTimer* getLegendID(S32 y);
 	F64 getTime(const std::string& name);
 
 protected:
@@ -85,8 +85,8 @@ class LLFastTimerView : public LLFloater
 	U64 mMaxCountTotal;
 	LLRect mBarRect;
 	S32	mScrollIndex;
-	LLFastTimer::NamedTimer* mHoverID;
-	LLFastTimer::NamedTimer* mHoverTimer;
+	LLFastTimer::DeclareTimer* mHoverID;
+	LLFastTimer::DeclareTimer* mHoverTimer;
 	LLRect					mToolTipRect;
 	S32 mHoverBarIndex;
 	LLFrameTimer mHighlightTimer;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index bf353cd1e04..5ac5ae892a8 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -2715,7 +2715,7 @@ void LLPipeline::updateGeom(F32 max_dtime)
 		
 	S32 count = 0;
 	
-	max_dtime = llmax(update_timer.getElapsedTimeF32()+0.001f, max_dtime);
+	max_dtime = llmax(update_timer.getElapsedTimeF32()+0.001f, LLUnit<LLUnits::Seconds, F32>(max_dtime));
 	LLSpatialGroup* last_group = NULL;
 	LLSpatialBridge* last_bridge = NULL;
 
-- 
GitLab