diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index 809a0327cabebbb2deb60a219f1fa7bf1c89c6ac..d9670891f8adaaebe69d4835166c80d2a0553ff2 100755
--- a/indra/llcommon/llfasttimer.cpp
+++ b/indra/llcommon/llfasttimer.cpp
@@ -365,11 +365,11 @@ void TimeBlock::dumpCurTimes()
 		++it)
 	{
 		TimeBlock* timerp = (*it);
-		LLUnit<F64, LLUnits::Seconds> total_time_ms = last_frame_recording.getSum(*timerp);
+		LLUnit<F64, LLUnits::Seconds> total_time = last_frame_recording.getSum(*timerp);
 		U32 num_calls = last_frame_recording.getSum(timerp->callCount());
 
 		// Don't bother with really brief times, keep output concise
-		if (total_time_ms < 0.1) continue;
+		if (total_time < LLUnit<F32, LLUnits::Milliseconds>(0.1)) continue;
 
 		std::ostringstream out_str;
 		TimeBlock* parent_timerp = timerp;
@@ -380,7 +380,7 @@ void TimeBlock::dumpCurTimes()
 		}
 
 		out_str << timerp->getName() << " " 
-			<< std::setprecision(3) << total_time_ms.as<LLUnits::Milliseconds>().value() << " ms, "
+			<< std::setprecision(3) << total_time.getAs<LLUnits::Milliseconds>() << " ms, "
 			<< num_calls << " calls";
 
 		llinfos << out_str.str() << llendl;
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index 1bf853c5c067b4fe3bd0e28dce8f1336c13b9d21..cd377531e81ce76d7e3186f8250db65626137ad5 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -66,6 +66,16 @@ typedef LLUnit<F64, LLUnits::Kilometers>	Kilometers;
 typedef LLUnit<F64, LLUnits::Centimeters>	Centimeters;
 typedef LLUnit<F64, LLUnits::Millimeters>	Millimeters;
 
+
+template<typename T>
+T storage_value(T val) { return val; }
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE> 
+STORAGE_TYPE storage_value(LLUnit<STORAGE_TYPE, UNIT_TYPE> val) { return val.value(); }
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE> 
+STORAGE_TYPE storage_value(LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> val) { return val.value(); }
+
 void init();
 void cleanup();
 bool isInitialized();
@@ -678,7 +688,7 @@ template<typename T, typename VALUE_T>
 void record(EventStatHandle<T>& measurement, VALUE_T value)
 {
 	T converted_value(value);
-	measurement.getPrimaryAccumulator()->record(LLUnits::storageValue(converted_value));
+	measurement.getPrimaryAccumulator()->record(storage_value(converted_value));
 }
 
 template <typename T = F64>
@@ -700,7 +710,7 @@ template<typename T, typename VALUE_T>
 void sample(SampleStatHandle<T>& measurement, VALUE_T value)
 {
 	T converted_value(value);
-	measurement.getPrimaryAccumulator()->sample(LLUnits::storageValue(converted_value));
+	measurement.getPrimaryAccumulator()->sample(storage_value(converted_value));
 }
 
 template <typename T = F64>
@@ -722,7 +732,7 @@ template<typename T, typename VALUE_T>
 void add(CountStatHandle<T>& count, VALUE_T value)
 {
 	T converted_value(value);
-	count.getPrimaryAccumulator()->add(LLUnits::storageValue(converted_value));
+	count.getPrimaryAccumulator()->add(storage_value(converted_value));
 }
 
 
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
index ff90da3822431d42e32a961487b10585dbed83c5..f2c59410112634f8965ac1c9422b88156dc014e4 100644
--- a/indra/llcommon/lltracerecording.cpp
+++ b/indra/llcommon/lltracerecording.cpp
@@ -121,22 +121,27 @@ Recording::Recording()
 }
 
 Recording::Recording( const Recording& other )
+{
+	*this = other;
+}
+
+Recording& Recording::operator = (const Recording& other)
 {
 	// this will allow us to seamlessly start without affecting any data we've acquired from other
 	setPlayState(PAUSED);
 
 	Recording& mutable_other = const_cast<Recording&>(other);
+	mutable_other.update();
 	EPlayState other_play_state = other.getPlayState();
-	mutable_other.pause();
 
-	mBuffers = other.mBuffers;
+	mBuffers = mutable_other.mBuffers;
 
 	LLStopWatchControlsMixin<Recording>::setPlayState(other_play_state);
-	mutable_other.setPlayState(other_play_state);
 
 	// above call will clear mElapsedSeconds as a side effect, so copy it here
 	mElapsedSeconds = other.mElapsedSeconds;
 	mSamplingTimer = other.mSamplingTimer;
+	return *this;
 }
 
 
@@ -444,12 +449,8 @@ void PeriodicRecording::nextPeriod()
 
 void PeriodicRecording::appendRecording(Recording& recording)
 {
-	// if I have a recording of any length, then close it off and start a fresh one
-	if (getCurRecording().getDuration().value())
-	{
-		nextPeriod();
-	}
 	getCurRecording().appendRecording(recording);
+	nextPeriod();
 }
 
 
@@ -460,12 +461,6 @@ void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
 	getCurRecording().update();
 	other.getCurRecording().update();
 
-	// if I have a recording of any length, then close it off and start a fresh one
-	if (getCurRecording().getDuration().value())
-	{
-		nextPeriod();
-	}
-
 	if (mAutoResize)
 	{
 		S32 other_index = (other.mCurPeriod + 1) % other.mRecordingPeriods.size();
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h
index e3cef77b06251e92ce1044dbb7dfdd6c4b69436b..b839e85de09bd8cc6cec49b4261dde43792ea520 100644
--- a/indra/llcommon/lltracerecording.h
+++ b/indra/llcommon/lltracerecording.h
@@ -135,6 +135,8 @@ namespace LLTrace
 		Recording(const Recording& other);
 		~Recording();
 
+		Recording& operator = (const Recording& other);
+
 		// accumulate data from subsequent, non-overlapping recording
 		void appendRecording(const Recording& other);
 
diff --git a/indra/llcommon/llunit.h b/indra/llcommon/llunit.h
index 5b961c81f068c3fc3ed49da3bf94b28e2245fa4a..5229fe69d7830713e88aa262082da1218a77ee6f 100644
--- a/indra/llcommon/llunit.h
+++ b/indra/llcommon/llunit.h
@@ -30,31 +30,7 @@
 #include "stdtypes.h"
 #include "llpreprocessor.h"
 #include "llerrorlegacy.h"
-
-namespace LLUnits
-{
-
-template<typename DERIVED_UNITS_TAG, typename BASE_UNITS_TAG, typename VALUE_TYPE>
-struct Convert
-{
-	static VALUE_TYPE get(VALUE_TYPE val)
-	{
-		// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
-		llstatic_assert_template(DERIVED_UNITS_TAG, false,  "Cannot convert between types.");
-        return val;
-	}
-};
-
-template<typename BASE_UNITS_TAG, typename VALUE_TYPE>
-struct Convert<BASE_UNITS_TAG, BASE_UNITS_TAG, VALUE_TYPE>
-{
-	static VALUE_TYPE get(VALUE_TYPE val)
-	{ 
-		return val; 
-	}
-};
-
-}
+#include <boost/type_traits/is_same.hpp>
 
 template<typename STORAGE_TYPE, typename UNIT_TYPE>
 struct LLUnit
@@ -70,7 +46,7 @@ struct LLUnit
 	// unit initialization and conversion
 	template<typename OTHER_STORAGE, typename OTHER_UNIT>
 	LLUnit(LLUnit<OTHER_STORAGE, OTHER_UNIT> other)
-	:	mValue(convert(other))
+	:	mValue(convert(other).mValue)
 	{}
 	
 	bool operator == (const self_t& other)
@@ -89,7 +65,7 @@ struct LLUnit
 	template<typename OTHER_STORAGE, typename OTHER_UNIT>
 	self_t& operator = (LLUnit<OTHER_STORAGE, OTHER_UNIT> other)
 	{
-		mValue = convert(other);
+		mValue = convert(other).mValue;
 		return *this;
 	}
 
@@ -98,11 +74,17 @@ struct LLUnit
 		return mValue;
 	}
 
-	template<typename NEW_UNIT_TYPE> LLUnit<STORAGE_TYPE, NEW_UNIT_TYPE> as()
+	template<typename NEW_UNIT_TYPE> 
+	STORAGE_TYPE getAs()
 	{
-		return LLUnit<STORAGE_TYPE, NEW_UNIT_TYPE>(*this);
+		return LLUnit<STORAGE_TYPE, NEW_UNIT_TYPE>(*this).value();
 	}
 
+	template<typename NEW_UNIT_TYPE> 
+	STORAGE_TYPE setAs(STORAGE_TYPE val)
+	{
+		*this = LLUnit<STORAGE_TYPE, NEW_UNIT_TYPE>(val);
+	}
 
 	void operator += (storage_t value)
 	{
@@ -112,7 +94,7 @@ struct LLUnit
 	template<typename OTHER_STORAGE, typename OTHER_UNIT>
 	void operator += (LLUnit<OTHER_STORAGE, OTHER_UNIT> other)
 	{
-		mValue += convert(other);
+		mValue += convert(other).mValue;
 	}
 
 	void operator -= (storage_t value)
@@ -123,7 +105,7 @@ struct LLUnit
 	template<typename OTHER_STORAGE, typename OTHER_UNIT>
 	void operator -= (LLUnit<OTHER_STORAGE, OTHER_UNIT> other)
 	{
-		mValue -= convert(other);
+		mValue -= convert(other).mValue;
 	}
 
 	void operator *= (storage_t multiplicand)
@@ -151,19 +133,13 @@ struct LLUnit
 	}
 
 	template<typename SOURCE_STORAGE, typename SOURCE_UNITS>
-	static storage_t convert(LLUnit<SOURCE_STORAGE, SOURCE_UNITS> v) 
+	static self_t convert(LLUnit<SOURCE_STORAGE, SOURCE_UNITS> v) 
 	{ 
-		return (storage_t)LLUnits::Convert<typename UNIT_TYPE::base_unit_t, UNIT_TYPE, STORAGE_TYPE>::get((STORAGE_TYPE)
-							LLUnits::Convert<SOURCE_UNITS, typename UNIT_TYPE::base_unit_t, SOURCE_STORAGE>::get(v.value())); 
+		self_t result;
+		ll_convert_units(v, result);
+		return result;
 	}
 
-	template<typename SOURCE_STORAGE>
-	static storage_t convert(LLUnit<SOURCE_STORAGE, UNIT_TYPE> v) 
-	{ 
-		return (storage_t)(v.value());
-	}
-
-
 protected:
 	storage_t mValue;
 };
@@ -192,6 +168,39 @@ struct LLUnitImplicit : public LLUnit<STORAGE_TYPE, UNIT_TYPE>
 	}
 };
 
+
+template<typename S1, typename T1, typename S2, typename T2>
+LL_FORCE_INLINE void ll_convert_units(LLUnit<S1, T1> in, LLUnit<S2, T2>& out, ...)
+{
+	static_assert(boost::is_same<T1, T2>::value 
+					|| !boost::is_same<T1, typename T1::base_unit_t>::value 
+					|| !boost::is_same<T2, typename T2::base_unit_t>::value, 
+				"invalid conversion");
+
+	if (boost::is_same<T1, typename T1::base_unit_t>::value)
+	{
+		if (boost::is_same<T2, typename T2::base_unit_t>::value)
+		{
+			// T1 and T2 fully reduced and equal...just copy
+			out = (S2)in.value();
+		}
+		else
+		{
+			// reduce T2
+			LLUnit<S2, typename T2::base_unit_t> new_out;
+			ll_convert_units(in, new_out);
+			ll_convert_units(new_out, out);
+		}
+	}
+	else
+	{
+		// reduce T1
+		LLUnit<S1, typename T1::base_unit_t> new_in;
+		ll_convert_units(in, new_in);
+		ll_convert_units(new_in, out);
+	}
+}
+
 //
 // operator +
 //
@@ -415,17 +424,11 @@ struct LLGetUnitLabel<LLUnit<STORAGE_T, T> >
 	static const char* getUnitLabel() { return T::getUnitLabel(); }
 };
 
-//
-// Unit declarations
-//
-namespace LLUnits
-{
-
 template<typename VALUE_TYPE>
-struct LinearOps
+struct LLUnitLinearOps
 {
-	typedef LinearOps<VALUE_TYPE> self_t;
-	LinearOps(VALUE_TYPE val) : mValue (val) {}
+	typedef LLUnitLinearOps<VALUE_TYPE> self_t;
+	LLUnitLinearOps(VALUE_TYPE val) : mValue (val) {}
 
 	operator VALUE_TYPE() const { return mValue; }
 	VALUE_TYPE mValue;
@@ -456,11 +459,11 @@ struct LinearOps
 };
 
 template<typename VALUE_TYPE>
-struct InverseLinearOps
+struct LLUnitInverseLinearOps
 {
-	typedef InverseLinearOps<VALUE_TYPE> self_t;
+	typedef LLUnitInverseLinearOps<VALUE_TYPE> self_t;
 
-	InverseLinearOps(VALUE_TYPE val) : mValue (val) {}
+	LLUnitInverseLinearOps(VALUE_TYPE val) : mValue (val) {}
 	operator VALUE_TYPE() const { return mValue; }
 	VALUE_TYPE mValue;
 
@@ -489,16 +492,6 @@ struct InverseLinearOps
 	}
 };
 
-
-template<typename T>
-T storageValue(T val) { return val; }
-
-template<typename UNIT_TYPE, typename STORAGE_TYPE> 
-STORAGE_TYPE storageValue(LLUnit<STORAGE_TYPE, UNIT_TYPE> val) { return val.value(); }
-
-template<typename UNIT_TYPE, typename STORAGE_TYPE> 
-STORAGE_TYPE storageValue(LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> val) { return val.value(); }
-
 #define LL_DECLARE_BASE_UNIT(base_unit_name, unit_label) \
 struct base_unit_name { typedef base_unit_name base_unit_t; static const char* getUnitLabel() { return unit_label; }}
 
@@ -507,57 +500,58 @@ struct unit_name
 {                                                                                               \
 	typedef base_unit_name base_unit_t;                                                         \
 	static const char* getUnitLabel() { return unit_label; }									\
-};                                                                                              \
-template<typename STORAGE_TYPE>                                                                 \
-struct Convert<unit_name, base_unit_name, STORAGE_TYPE>                                         \
-{                                                                                               \
-	static STORAGE_TYPE get(STORAGE_TYPE val)                                                   \
-	{                                                                                           \
-		return (LinearOps<STORAGE_TYPE>(val) conversion_operation).mValue;                      \
-	}                                                                                           \
 };                                                                                              \
 	                                                                                            \
-template<typename STORAGE_TYPE>                                                                 \
-struct Convert<base_unit_name, unit_name, STORAGE_TYPE>						                    \
+template<typename S1, typename S2>                                                              \
+void ll_convert_units(LLUnit<S1, unit_name> in, LLUnit<S2, base_unit_name>& out)                \
 {                                                                                               \
-	static STORAGE_TYPE get(STORAGE_TYPE val)                                                   \
-	{                                                                                           \
-		return (InverseLinearOps<STORAGE_TYPE>(val) conversion_operation).mValue;               \
-	}                                                                                           \
-}
+	out = (S2)(LLUnitLinearOps<S1>(in.value()) conversion_operation).mValue;                    \
+}                                                                                               \
+                                                                                                \
+template<typename S1, typename S2>                                                              \
+void ll_convert_units(LLUnit<S1, base_unit_name> in, LLUnit<S2, unit_name>& out)                \
+{                                                                                               \
+	out = (S2)(LLUnitInverseLinearOps<S1>(in.value()) conversion_operation).mValue;             \
+}                                                                                               
 
+//
+// Unit declarations
+//
+
+namespace LLUnits
+{
 LL_DECLARE_BASE_UNIT(Bytes, "B");
 LL_DECLARE_DERIVED_UNIT(Kilobytes, "KB", Bytes, * 1000);
-LL_DECLARE_DERIVED_UNIT(Megabytes, "MB", Bytes, * 1000 * 1000);
-LL_DECLARE_DERIVED_UNIT(Gigabytes, "GB", Bytes, * 1000 * 1000 * 1000);
+LL_DECLARE_DERIVED_UNIT(Megabytes, "MB", Kilobytes, * 1000);
+LL_DECLARE_DERIVED_UNIT(Gigabytes, "GB", Megabytes, * 1000);
 LL_DECLARE_DERIVED_UNIT(Kibibytes, "KiB", Bytes, * 1024);
-LL_DECLARE_DERIVED_UNIT(Mibibytes, "MiB", Bytes, * 1024 * 1024);
-LL_DECLARE_DERIVED_UNIT(Gibibytes, "GiB", Bytes, * 1024 * 1024 * 1024);
+LL_DECLARE_DERIVED_UNIT(Mibibytes, "MiB", Kibibytes, * 1024);
+LL_DECLARE_DERIVED_UNIT(Gibibytes, "GiB", Mibibytes, * 1024);
 
 LL_DECLARE_DERIVED_UNIT(Bits, "b", Bytes, / 8);
-LL_DECLARE_DERIVED_UNIT(Kilobits, "Kb", Bytes, * (1000 / 8));
-LL_DECLARE_DERIVED_UNIT(Megabits, "Mb", Bytes, * (1000 / 8));
-LL_DECLARE_DERIVED_UNIT(Gigabits, "Gb", Bytes, * (1000 * 1000 * 1000 / 8));
-LL_DECLARE_DERIVED_UNIT(Kibibits, "Kib", Bytes, * (1024 / 8));
-LL_DECLARE_DERIVED_UNIT(Mibibits, "Mib", Bytes, * (1024 / 8));
-LL_DECLARE_DERIVED_UNIT(Gibibits, "Gib", Bytes, * (1024 * 1024 * 1024 / 8));
+LL_DECLARE_DERIVED_UNIT(Kilobits, "Kb", Bytes, * 1000 / 8);
+LL_DECLARE_DERIVED_UNIT(Megabits, "Mb", Kilobits, * 1000 / 8);
+LL_DECLARE_DERIVED_UNIT(Gigabits, "Gb", Megabits, * 1000 / 8);
+LL_DECLARE_DERIVED_UNIT(Kibibits, "Kib", Bytes, * 1024 / 8);
+LL_DECLARE_DERIVED_UNIT(Mibibits, "Mib", Kibibits, * 1024 / 8);
+LL_DECLARE_DERIVED_UNIT(Gibibits, "Gib", Mibibits, * 1024 / 8);
 
 LL_DECLARE_BASE_UNIT(Seconds, "s");
 LL_DECLARE_DERIVED_UNIT(Minutes, "min", Seconds, * 60);
 LL_DECLARE_DERIVED_UNIT(Hours, "h", Seconds, * 60 * 60);
 LL_DECLARE_DERIVED_UNIT(Milliseconds, "ms", Seconds, / 1000);
-LL_DECLARE_DERIVED_UNIT(Microseconds, "\x09\x3cs", Seconds, / 1000000);
-LL_DECLARE_DERIVED_UNIT(Nanoseconds, "ns", Seconds, / 1000000000);
+LL_DECLARE_DERIVED_UNIT(Microseconds, "\x09\x3cs", Milliseconds, / 1000);
+LL_DECLARE_DERIVED_UNIT(Nanoseconds, "ns", Microseconds, / 1000);
 
 LL_DECLARE_BASE_UNIT(Meters, "m");
 LL_DECLARE_DERIVED_UNIT(Kilometers, "km", Meters, * 1000);
-LL_DECLARE_DERIVED_UNIT(Centimeters, "cm", Meters, * 100);
-LL_DECLARE_DERIVED_UNIT(Millimeters, "mm", Meters, * 1000);
+LL_DECLARE_DERIVED_UNIT(Centimeters, "cm", Meters, / 100);
+LL_DECLARE_DERIVED_UNIT(Millimeters, "mm", Meters, / 1000);
 
 LL_DECLARE_BASE_UNIT(Hertz, "Hz");
 LL_DECLARE_DERIVED_UNIT(Kilohertz, "KHz", Hertz, * 1000);
-LL_DECLARE_DERIVED_UNIT(Megahertz, "MHz", Hertz, * 1000 * 1000);
-LL_DECLARE_DERIVED_UNIT(Gigahertz, "GHz", Hertz, * 1000 * 1000 * 1000);
+LL_DECLARE_DERIVED_UNIT(Megahertz, "MHz", Kilohertz, * 1000);
+LL_DECLARE_DERIVED_UNIT(Gigahertz, "GHz", Megahertz, * 1000);
 
 LL_DECLARE_BASE_UNIT(Radians, "rad");
 LL_DECLARE_DERIVED_UNIT(Degrees, "deg", Radians, * 0.01745329251994);
diff --git a/indra/llcommon/tests/llunits_test.cpp b/indra/llcommon/tests/llunits_test.cpp
index 747e8d1827f040f797adb4014f0b67df5045f682..04764f6c2f3c75776cfe57ee417be84590fb7805 100644
--- a/indra/llcommon/tests/llunits_test.cpp
+++ b/indra/llcommon/tests/llunits_test.cpp
@@ -35,7 +35,7 @@ namespace LLUnits
 	// using powers of 2 to allow strict floating point equality
 	LL_DECLARE_BASE_UNIT(Quatloos, "Quat");
 	LL_DECLARE_DERIVED_UNIT(Latinum, "Lat", Quatloos, * 4);
-	LL_DECLARE_DERIVED_UNIT(Solari, "Sol", Quatloos, / 4);
+	LL_DECLARE_DERIVED_UNIT(Solari, "Sol", Latinum, / 16);
 }
 
 namespace tut
@@ -206,5 +206,11 @@ namespace tut
 
 		S32 int_val = quatloos_implicit;
 		ensure(int_val == 16);
+
+		// conversion of implicits
+		LLUnitImplicit<F32, Latinum> latinum_implicit(2);
+		ensure(latinum_implicit == 2);
+
+		ensure(latinum_implicit * 2 == quatloos_implicit);
 	}
 }
diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp
index 8e061ec87c7ea0f8181f3b5858a72045567ed71a..231ece4bbdec3333efed628800d30670bdcef309 100755
--- a/indra/newview/llfasttimerview.cpp
+++ b/indra/newview/llfasttimerview.cpp
@@ -56,7 +56,7 @@
 
 using namespace LLTrace;
 
-static const S32 MAX_VISIBLE_HISTORY = 10;
+static const S32 MAX_VISIBLE_HISTORY = 12;
 static const S32 LINE_GRAPH_HEIGHT = 240;
 static const S32 MIN_BAR_HEIGHT = 3;
 
@@ -105,7 +105,7 @@ LLFastTimerView::LLFastTimerView(const LLSD& key)
 	mPauseHistory(false),
 	mRecording(512)
 {
-	mTimerBarRows.resize(MAX_VISIBLE_HISTORY);
+	mTimerBarRows.resize(512);
 }
 
 LLFastTimerView::~LLFastTimerView()
@@ -272,32 +272,36 @@ BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask)
 			mHoverBarIndex = 0;
 		}
 
-		S32 i = 0;
-		for(timer_tree_iterator_t it = begin_timer_tree(FTM_FRAME);
-			it != end_timer_tree();
-			++it, ++i)
+		TimerBarRow& row = mHoverBarIndex == 0 ? mAverageTimerRow : mTimerBarRows[mHoverBarIndex - 1];
+
+		TimerBar* hover_bar = NULL;
+		LLUnit<F32, LLUnits::Seconds> mouse_time_offset = ((F32)(x - mBarRect.mLeft) / (F32)mBarRect.getWidth()) * mTotalTimeDisplay;
+		for (std::vector<TimerBar>::iterator it = row.mBars.begin(), end_it = row.mBars.end();
+			it != end_it;
+			++it)
 		{
-			// is mouse over bar for this timer?
-			TimerBarRow& row = mHoverBarIndex == 0 ? mAverageTimerRow : mTimerBarRows[mHoverBarIndex - 1];
-			if (row.mBars[i].mVisibleRect.pointInRect(x, y - row.mBottom))
+			if (it->mSelfStart > mouse_time_offset)
 			{
-				mHoverID = (*it);
-				if (mHoverTimer != *it)
-				{
-					// could be that existing tooltip is for a parent and is thus
-					// covering region for this new timer, go ahead and unblock 
-					// so we can create a new tooltip
-					LLToolTipMgr::instance().unblockToolTips();
-					mHoverTimer = (*it);
-				}
-
-				mToolTipRect = row.mBars[i].mVisibleRect;
-				mToolTipRect.translate(0, row.mBottom);
+				break;
 			}
+			hover_bar = &(*it);
+		}
 
-			if ((*it)->getCollapsed())
+		if (hover_bar)
+		{
+			mHoverID = hover_bar->mTimeBlock;
+			mHoverTimer = mHoverID;
+			if (mHoverTimer != mHoverID)
 			{
-				it.skipDescendants();
+				// could be that existing tooltip is for a parent and is thus
+				// covering region for this new timer, go ahead and unblock 
+				// so we can create a new tooltip
+				LLToolTipMgr::instance().unblockToolTips();
+				mHoverTimer = mHoverID;
+				mToolTipRect.set(mBarRect.mLeft + (hover_bar->mSelfStart / mTotalTimeDisplay) * mBarRect.getWidth(),
+								row.mTop,
+								mBarRect.mLeft + (hover_bar->mSelfStart / mTotalTimeDisplay) * mBarRect.getWidth(),
+								row.mBottom);
 			}
 		}
 	}
@@ -422,9 +426,14 @@ void LLFastTimerView::draw()
 
 void LLFastTimerView::onOpen(const LLSD& key)
 {
-	if (mRecording.getNumRecordedPeriods() == 0)
+	setPauseState(false);
+	mRecording.reset();
+	mRecording.appendPeriodicRecording(LLTrace::get_frame_recording());
+	for(std::deque<TimerBarRow>::iterator it = mTimerBarRows.begin(), end_it = mTimerBarRows.end();
+		it != end_it; 
+		++it)
 	{
-		mRecording.appendPeriodicRecording(LLTrace::get_frame_recording());
+		it->mBars.clear();
 	}
 }
 
@@ -1077,6 +1086,7 @@ void LLFastTimerView::drawLineGraph()
 			glLineWidth(3);
 		}
 
+		llassert(idp->getIndex() < sTimerColors.size());
 		const F32 * col = sTimerColors[idp->getIndex()].mV;// ft_display_table[idx].color->mV;
 
 		F32 alpha = 1.f;
@@ -1191,6 +1201,7 @@ void LLFastTimerView::drawLegend( S32 y )
 				scale_offset = llfloor(sinf(mHighlightTimer.getElapsedTimeF32() * 6.f) * 2.f);
 			}
 			bar_rect.stretch(scale_offset);
+			llassert(idp->getIndex() < sTimerColors.size());
 			gl_rect_2d(bar_rect, sTimerColors[idp->getIndex()]);
 
 			LLUnit<F32, LLUnits::Milliseconds> ms = 0;
@@ -1262,7 +1273,7 @@ void LLFastTimerView::generateUniqueColors()
 {
 	// generate unique colors
 	{
-		sTimerColors.reserve(LLTrace::TimeBlock::getNumIndices());
+		sTimerColors.resize(LLTrace::TimeBlock::getNumIndices());
 		sTimerColors[FTM_FRAME.getIndex()] = LLColor4::grey;
 
 		F32 hue = 0.f;
@@ -1283,6 +1294,7 @@ void LLFastTimerView::generateUniqueColors()
 			LLColor4 child_color;
 			child_color.setHSL(hue, saturation, lightness);
 
+			llassert(idp->getIndex() < sTimerColors.size());
 			sTimerColors[idp->getIndex()] = child_color;
 		}
 	}
@@ -1377,7 +1389,7 @@ void LLFastTimerView::drawBorders( S32 y, const S32 x_start, S32 bar_height, S32
 		//history bars
 		gl_rect_2d(x_start-5, by, getRect().getWidth()-5, LINE_GRAPH_HEIGHT-bar_height-dy-2, LLColor4::grey, FALSE);			
 
-		by = LINE_GRAPH_HEIGHT-bar_height-dy-7;
+		by = LINE_GRAPH_HEIGHT-dy;
 
 		//line graph
 		mGraphRect = LLRect(x_start-5, by, getRect().getWidth()-5, 5);
@@ -1391,21 +1403,21 @@ void LLFastTimerView::updateTotalTime()
 	switch(mDisplayMode)
 	{
 	case 0:
-		mTotalTimeDisplay = mRecording.getPeriodMean(FTM_FRAME)*2;
+		mTotalTimeDisplay = mRecording.getPeriodMean(FTM_FRAME, 100)*2;
 		break;
 	case 1:
-		mTotalTimeDisplay = mAllTimeMax;
+		mTotalTimeDisplay = mRecording.getPeriodMax(FTM_FRAME);
 		break;
 	case 2:
 		// Calculate the max total ticks for the current history
-		mTotalTimeDisplay = mRecording.getPeriodMax(FTM_FRAME);
+		mTotalTimeDisplay = mRecording.getPeriodMax(FTM_FRAME, 20);
 		break;
 	default:
 		mTotalTimeDisplay = LLUnit<F32, LLUnits::Milliseconds>(100);
 		break;
 	}
 
-	mTotalTimeDisplay = LLUnit<F32, LLUnits::Milliseconds>(llceil(mTotalTimeDisplay.as<LLUnits::Milliseconds>().value() / 20.f) * 20.f);
+	mTotalTimeDisplay = LLUnit<F32, LLUnits::Milliseconds>(llceil(mTotalTimeDisplay.getAs<LLUnits::Milliseconds>() / 20.f) * 20.f);
 }
 
 void LLFastTimerView::drawBars()
@@ -1432,41 +1444,44 @@ void LLFastTimerView::drawBars()
 
 	gGL.getTexUnit(0)->bind(bar_image->getImage());
 	{	
-		const S32 histmax = llmin((S32)mRecording.getNumRecordedPeriods(), MAX_VISIBLE_HISTORY);
-
-		llassert(mTimerBarRows.size() >= histmax);
+		const S32 histmax = (S32)mRecording.getNumRecordedPeriods();
 
 		// update widths
 		updateTimerBarWidths(&FTM_FRAME, mAverageTimerRow, -1);
-		mAverageTimerRow.mBars[0].mVisibleRect = LLRect(mBarRect.mLeft, 0, mBarRect.mLeft + mAverageTimerRow.mBars[0].mWidth, -bar_height);
-		updateTimerBarFractions(&FTM_FRAME, mAverageTimerRow);
+		updateTimerBarOffsets(&FTM_FRAME, mAverageTimerRow);
 
-		for (S32 history_index = 0; history_index < histmax; history_index++)
+		for (S32 history_index = 1; history_index <= histmax; history_index++)
 		{
-			TimerBarRow& row = mTimerBarRows[history_index];
+			llassert(history_index <= mTimerBarRows.size());
+			TimerBarRow& row = mTimerBarRows[history_index - 1];
 			if (row.mBars.empty())
 			{
 				row.mBars.reserve(LLInstanceTracker<LLTrace::TimeBlock>::instanceCount());
 				updateTimerBarWidths(&FTM_FRAME, row, history_index);
-				row.mBars[0].mVisibleRect = LLRect(mBarRect.mLeft, 0, mBarRect.mLeft + row.mBars[0].mWidth, -1);
-				updateTimerBarFractions(&FTM_FRAME, row);
+				updateTimerBarOffsets(&FTM_FRAME, row);
 			}
 		}
 
 		// draw bars
-		LLRect frame_bar_rect(	mBarRect.mLeft, 
-								bars_top, 
-								mBarRect.mLeft + mAverageTimerRow.mBars[0].mWidth, 
-								bars_top - bar_height);
+		LLRect frame_bar_rect;
+		frame_bar_rect.setLeftTopAndSize(mBarRect.mLeft, 
+										bars_top, 
+										llround((mAverageTimerRow.mBars[0].mTotalTime / mTotalTimeDisplay) * mBarRect.getWidth()), 
+										bar_height);
+		mAverageTimerRow.mTop = frame_bar_rect.mTop;
 		mAverageTimerRow.mBottom = frame_bar_rect.mBottom;
-		drawBar(&FTM_FRAME, frame_bar_rect, mAverageTimerRow, image_width, image_height, false);
+		drawBar(frame_bar_rect, mAverageTimerRow, image_width, image_height);
 		frame_bar_rect.translate(0, -(bar_height + vpad + bar_height));
 
 		for(S32 bar_index = mScrollIndex; bar_index < llmin(histmax, mScrollIndex + MAX_VISIBLE_HISTORY); ++bar_index)
 		{
+			llassert(bar_index < mTimerBarRows.size());
 			TimerBarRow& row = mTimerBarRows[bar_index];
+			row.mTop = frame_bar_rect.mTop;
 			row.mBottom = frame_bar_rect.mBottom;
-			drawBar(&FTM_FRAME, frame_bar_rect, row, image_width, image_height, false);
+			frame_bar_rect.mRight = frame_bar_rect.mLeft 
+									+ llround((row.mBars[0].mTotalTime / mTotalTimeDisplay) * mBarRect.getWidth());
+ 			drawBar(frame_bar_rect, row, image_width, image_height);
 
 			frame_bar_rect.translate(0, -(bar_height + vpad));
 		}
@@ -1477,97 +1492,115 @@ void LLFastTimerView::drawBars()
 
 static LLFastTimer::DeclareTimer FTM_UPDATE_TIMER_BAR_WIDTHS("Update timer bar widths");
 
-S32 LLFastTimerView::updateTimerBarWidths(LLTrace::TimeBlock* time_block, TimerBarRow& row, S32 history_index, bool visible)
+LLUnit<F32, LLUnits::Seconds> LLFastTimerView::updateTimerBarWidths(LLTrace::TimeBlock* time_block, TimerBarRow& row, S32 history_index, bool visible)
 {
-	std::vector<TimerBar>& bars = row.mBars;
 	LLFastTimer _(FTM_UPDATE_TIMER_BAR_WIDTHS);
-	const F32 self_time_frame_fraction = history_index == -1
-										? (mRecording.getPeriodMean(time_block->selfTime()) / mTotalTimeDisplay) 
-										: (mRecording.getPrevRecording(history_index).getSum(time_block->selfTime()) / mTotalTimeDisplay);
+	const LLUnit<F32, LLUnits::Seconds> self_time = history_index == -1
+										? mRecording.getPeriodMean(time_block->selfTime()) 
+										: mRecording.getPrevRecording(history_index).getSum(time_block->selfTime());
 
-	const S32 self_time_width = llround(self_time_frame_fraction * (F32)mBarRect.getWidth());
-	S32 full_width = self_time_width;
+	LLUnit<F32, LLUnits::Seconds> full_time = self_time;
 
 	// reserve a spot for this bar to be rendered before its children
 	// even though we don't know its size yet
+	std::vector<TimerBar>& bars = row.mBars;
+	S32 bar_index = bars.size();
 	bars.push_back(TimerBar());
-	TimerBar& timer_bar = bars.back();
 
 	const bool children_visible = visible && !time_block->getCollapsed();
 	for (TimeBlock::child_iter it = time_block->beginChildren(), end_it = time_block->endChildren(); it != end_it; ++it)
 	{
-		full_width += updateTimerBarWidths(*it, row, history_index, children_visible);
+		full_time += updateTimerBarWidths(*it, row, history_index, children_visible);
 	}
 
-	timer_bar.mWidth     = full_width;
-	timer_bar.mSelfWidth = self_time_width;
-	timer_bar.mTimeBlock = time_block;
-	timer_bar.mVisible   = visible;
+	TimerBar& timer_bar = bars[bar_index];
+	timer_bar.mTotalTime  = full_time;
+	timer_bar.mSelfTime   = self_time;
+	timer_bar.mTimeBlock  = time_block;
+	timer_bar.mVisible    = visible;
 	
-	return full_width;
+	return full_time;
 }
 
 static LLFastTimer::DeclareTimer FTM_UPDATE_TIMER_BAR_FRACTIONS("Update timer bar fractions");
 
-S32 LLFastTimerView::updateTimerBarFractions(LLTrace::TimeBlock* time_block, TimerBarRow& row, S32 timer_bar_index)
+S32 LLFastTimerView::updateTimerBarOffsets(LLTrace::TimeBlock* time_block, TimerBarRow& row, S32 timer_bar_index)
 {
-	std::vector<TimerBar>& bars = row.mBars;
 	LLFastTimer _(FTM_UPDATE_TIMER_BAR_FRACTIONS);
+
+	std::vector<TimerBar>& bars = row.mBars;
+	llassert(timer_bar_index < bars.size());
 	TimerBar& timer_bar = bars[timer_bar_index];
-	S32 child_time_width = timer_bar.mWidth - timer_bar.mSelfWidth;
-	LLRect children_rect = timer_bar.mVisibleRect;
+	const LLUnit<F32, LLUnits::Seconds> child_time_width = timer_bar.mTotalTime - timer_bar.mSelfTime;
+	timer_bar.mChildrenStart = timer_bar.mSelfStart;
 
 	if (mDisplayCenter == ALIGN_CENTER)
 	{
-		children_rect.mLeft += timer_bar.mSelfWidth / 2;
+		timer_bar.mChildrenStart += timer_bar.mSelfTime / 2;
 	}
 	else if (mDisplayCenter == ALIGN_RIGHT)
 	{
-		children_rect.mLeft += timer_bar.mSelfWidth;
+		timer_bar.mChildrenStart += timer_bar.mSelfTime;
 	}
-	children_rect.mRight = children_rect.mLeft + timer_bar.mWidth - timer_bar.mSelfWidth;
-
-	timer_bar.mChildrenRect = children_rect;
+	timer_bar.mChildrenEnd = timer_bar.mChildrenStart + timer_bar.mTotalTime - timer_bar.mSelfTime;
 
 	//now loop through children and figure out portion of bar image covered by each bar, now that we know the
 	//sum of all children
-	if (!time_block->getCollapsed())
+	F32 bar_fraction_start = 0.f;
+	TimerBar* last_child_timer_bar = NULL;
+
+	bool first_child = true;
+	for (TimeBlock::child_iter it = time_block->beginChildren(), end_it = time_block->endChildren(); 
+		it != end_it; 
+		++it)
 	{
-		F32 bar_fraction_start = 0.f;
-		for (TimeBlock::child_iter it = time_block->beginChildren(), end_it = time_block->endChildren(); 
-			it != end_it; 
-			++it)
+		timer_bar_index++;
+		
+		llassert(timer_bar_index < bars.size());
+		TimerBar& child_timer_bar = bars[timer_bar_index];
+		TimeBlock* child_time_block = *it;
+
+		if (last_child_timer_bar)
 		{
-			timer_bar_index++;
+			last_child_timer_bar->mLastChild = false;
+		}
+		child_timer_bar.mLastChild = true;
+		last_child_timer_bar = &child_timer_bar;
 
-			TimerBar& child_timer_bar = bars[timer_bar_index];
-			TimeBlock* child_time_block = *it;
+		child_timer_bar.mFirstChild = first_child;
+		if (first_child)
+		{
+			first_child = false;
+		}
 
-			child_timer_bar.mStartFraction = bar_fraction_start;
-			child_timer_bar.mEndFraction = child_time_width > 0
-				? bar_fraction_start + (F32)child_timer_bar.mWidth / child_time_width
-				: 1.f;
-			child_timer_bar.mVisibleRect.set(children_rect.mLeft + llround(child_timer_bar.mStartFraction * children_rect.getWidth()), 
-				children_rect.mTop, 
-				children_rect.mLeft + llround(child_timer_bar.mEndFraction * children_rect.getWidth()), 
-				children_rect.mBottom);
+		child_timer_bar.mStartFraction = bar_fraction_start;
+		child_timer_bar.mEndFraction = child_time_width > 0
+										? bar_fraction_start + child_timer_bar.mTotalTime / child_time_width
+										: 1.f;
+		child_timer_bar.mSelfStart = timer_bar.mChildrenStart 
+									+ child_timer_bar.mStartFraction 
+										* (timer_bar.mChildrenEnd - timer_bar.mChildrenStart);
+		child_timer_bar.mSelfEnd =	timer_bar.mChildrenStart 
+									+ child_timer_bar.mEndFraction 
+										* (timer_bar.mChildrenEnd - timer_bar.mChildrenStart);
 
-			timer_bar_index = updateTimerBarFractions(child_time_block, row, timer_bar_index);
+		timer_bar_index = updateTimerBarOffsets(child_time_block, row, timer_bar_index);
 
-			bar_fraction_start = child_timer_bar.mEndFraction;
-		}
+		bar_fraction_start = child_timer_bar.mEndFraction;
 	}
 	return timer_bar_index;
 }
 
-S32 LLFastTimerView::drawBar(LLTrace::TimeBlock* time_block, LLRect bar_rect, TimerBarRow& row, S32 image_width, S32 image_height, bool hovered, S32 bar_index)
+S32 LLFastTimerView::drawBar(LLRect bar_rect, TimerBarRow& row, S32 image_width, S32 image_height, bool hovered, S32 bar_index)
 {
+	llassert(bar_index < row.mBars.size());	
 	TimerBar& timer_bar = row.mBars[bar_index];
+	LLTrace::TimeBlock* time_block = timer_bar.mTimeBlock;
 
 	hovered |= mHoverID == time_block;
 
 	// animate scale of bar when hovering over that particular timer
-	if (bar_rect.getWidth() > 0)
+	if ((F32)bar_rect.getWidth() * (timer_bar.mEndFraction - timer_bar.mStartFraction) > 2.f)
 	{
 		LLRect render_rect(bar_rect);
 		S32 scale_offset = 0;
@@ -1578,8 +1611,9 @@ S32 LLFastTimerView::drawBar(LLTrace::TimeBlock* time_block, LLRect bar_rect, Ti
 			render_rect.mBottom -= scale_offset;
 		}
 
+		llassert(time_block->getIndex() < sTimerColors.size());
 		LLColor4 color = sTimerColors[time_block->getIndex()];
-		if (!hovered) color = lerp(color, LLColor4::grey, 0.8f);
+		if (!hovered) color = lerp(color, LLColor4::grey, 0.2f);
 		gGL.color4fv(color.mV);
 		gl_segmented_rect_2d_fragment_tex(render_rect,
 			image_width, image_height, 
@@ -1587,26 +1621,33 @@ S32 LLFastTimerView::drawBar(LLTrace::TimeBlock* time_block, LLRect bar_rect, Ti
 			timer_bar.mStartFraction, timer_bar.mEndFraction);
 	}
 
-	if (!time_block->getCollapsed())
+	LLRect children_rect;
+	children_rect.mLeft  = llround(timer_bar.mChildrenStart / mTotalTimeDisplay * (F32)mBarRect.getWidth()) + mBarRect.mLeft;
+	children_rect.mRight = llround(timer_bar.mChildrenEnd   / mTotalTimeDisplay * (F32)mBarRect.getWidth()) + mBarRect.mLeft;
+
+	if (bar_rect.getHeight() > MIN_BAR_HEIGHT)
 	{
-		for (TimeBlock::child_iter it = time_block->beginChildren(), end_it = time_block->endChildren(); it != end_it; ++it)
+		// shrink as we go down a level
+		children_rect.mTop = bar_rect.mTop - 1;
+		children_rect.mBottom = bar_rect.mBottom + 1;
+	}
+	else
+	{
+		children_rect.mTop = bar_rect.mTop;
+		children_rect.mBottom = bar_rect.mBottom;
+	}
+
+	bar_index++;
+	const U32 num_bars = row.mBars.size();
+	if (bar_index < num_bars && row.mBars[bar_index].mFirstChild)
+	{
+		bool is_last = false;
+		do
 		{
-			++bar_index;
-			LLRect children_rect = timer_bar.mChildrenRect;
-			children_rect.translate(0, row.mBottom);
-			if (bar_rect.getHeight() > MIN_BAR_HEIGHT)
-			{
-				// shrink as we go down a level
-				children_rect.mTop = bar_rect.mTop - 1;
-				children_rect.mBottom = bar_rect.mBottom + 1;
-			}
-			else
-			{
-				children_rect.mTop = bar_rect.mTop;
-				children_rect.mBottom = bar_rect.mBottom;
-			}
-			bar_index = drawBar(*it, children_rect, row, image_width, image_height, hovered, bar_index);
+			is_last = row.mBars[bar_index].mLastChild;
+			bar_index = drawBar(children_rect, row, image_width, image_height, hovered, bar_index);
 		}
+		while(!is_last && bar_index < num_bars);
 	}
 
 	return bar_index;
diff --git a/indra/newview/llfasttimerview.h b/indra/newview/llfasttimerview.h
index c20cadd6d7dbc4fe016f57319c7ec382d5634285..d9ae6348dab00af0603dd3a0a24daee419c25dc2 100755
--- a/indra/newview/llfasttimerview.h
+++ b/indra/newview/llfasttimerview.h
@@ -80,31 +80,38 @@ class LLFastTimerView : public LLFloater
 	struct TimerBar
 	{
 		TimerBar()
-		:	mWidth(0),
-			mSelfWidth(0),
+		:	mTotalTime(0),
+			mSelfTime(0),
 			mVisible(true),
 			mStartFraction(0.f),
-			mEndFraction(1.f)
+			mEndFraction(1.f),
+			mFirstChild(false),
+			mLastChild(false)
 		{}
-		S32					mWidth;
-		S32					mSelfWidth;
-		LLRect				mVisibleRect,
-							mChildrenRect;
+		LLUnit<F32, LLUnits::Seconds>	mTotalTime,
+										mSelfTime,
+										mChildrenStart,
+										mChildrenEnd,
+										mSelfStart,
+										mSelfEnd;
 		LLTrace::TimeBlock* mTimeBlock;
-		bool				mVisible;
+		bool				mVisible,
+							mFirstChild,
+							mLastChild;
 		F32					mStartFraction,
 							mEndFraction;
 	};
 
 	struct TimerBarRow
 	{
-		S32						mBottom;
+		S32						mBottom,
+								mTop;
 		std::vector<TimerBar>	mBars;
 	};
 
-	S32 updateTimerBarWidths(LLTrace::TimeBlock* time_block, TimerBarRow& row, S32 history_index, bool visible = true);
-	S32 updateTimerBarFractions(LLTrace::TimeBlock* time_block, TimerBarRow& row, S32 timer_bar_index = 0);
-	S32 drawBar(LLTrace::TimeBlock* time_block, LLRect bar_rect, TimerBarRow& row, S32 image_width, S32 image_height, bool hovered, S32 bar_index = 0);
+	LLUnit<F32, LLUnits::Seconds> updateTimerBarWidths(LLTrace::TimeBlock* time_block, TimerBarRow& row, S32 history_index, bool visible = true);
+	S32 updateTimerBarOffsets(LLTrace::TimeBlock* time_block, TimerBarRow& row, S32 timer_bar_index = 0);
+	S32 drawBar(LLRect bar_rect, TimerBarRow& row, S32 image_width, S32 image_height, bool hovered = false, S32 bar_index = 0);
 	void setPauseState(bool pause_state);
 
 	std::deque<TimerBarRow> mTimerBarRows;
diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp
index 3d9e0ab4c3a482a75c4a9fd9df425217f78ca20e..80867454710daf110143bc64ace77228b682ef6f 100644
--- a/indra/newview/llscenemonitor.cpp
+++ b/indra/newview/llscenemonitor.cpp
@@ -616,7 +616,7 @@ void LLSceneMonitor::dumpToFile(std::string file_name)
 
 		for (S32 frame = 0; frame < frame_count; frame++)
 		{
-			os << ", " << scene_load_recording.getPrevRecording(frame_count - frame).getMax(*it).as<LLUnits::Kibibytes>().value();
+			os << ", " << scene_load_recording.getPrevRecording(frame_count - frame).getMax(*it).getAs<LLUnits::Kibibytes>();
 		}
 
 		os << std::endl;