From b1baf982b1bd41a150233d0a28d3601226924c65 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Sun, 30 Sep 2012 10:41:29 -0700
Subject: [PATCH] SH-3275 WIP Run viewer metrics for object update messages
 factored out lltrace::sampler into separate file added rudimentary lltrace
 support to llstatgraph made llstatgraph use param blocks more effectively
 moves initial set of stats over to lltrace removed windows.h #defines for min
 and max

---
 indra/llcommon/CMakeLists.txt         |   2 +
 indra/llcommon/llapr.h                |   2 +
 indra/llcommon/lltrace.cpp            | 112 ++++++++---------------
 indra/llcommon/lltrace.h              | 127 ++++++++------------------
 indra/llcommon/lltracesampler.cpp     | 103 +++++++++++++++++++++
 indra/llcommon/lltracesampler.h       |  91 ++++++++++++++++++
 indra/llrender/llglheaders.h          |   2 +
 indra/llui/llstatbar.cpp              |  79 ++++++++++++----
 indra/llui/llstatbar.h                |   3 +
 indra/llui/llstatgraph.cpp            | 123 +++++++++++++------------
 indra/llui/llstatgraph.h              |  99 +++++++++++++++++---
 indra/newview/llstatusbar.cpp         |  33 ++++---
 indra/newview/llviewerstats.cpp       |  38 +++++---
 indra/newview/llviewerstats.h         |  20 ++--
 indra/newview/llviewertexturelist.cpp |   4 +-
 indra/newview/llworld.cpp             |   3 +-
 16 files changed, 553 insertions(+), 288 deletions(-)
 create mode 100644 indra/llcommon/lltracesampler.cpp
 create mode 100644 indra/llcommon/lltracesampler.h

diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index f78751601c2..e10dbb3e4d7 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -101,6 +101,7 @@ set(llcommon_SOURCE_FILES
     llthreadsafequeue.cpp
     lltimer.cpp
     lltrace.cpp
+    lltracesampler.cpp
     lluri.cpp
     lluuid.cpp
     llworkerthread.cpp
@@ -243,6 +244,7 @@ set(llcommon_HEADER_FILES
     llthreadsafequeue.h
     lltimer.h
     lltrace.h
+    lltracesampler.h
     lltreeiterators.h
     lltypeinfolookup.h
     lluri.h
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index 830e0a33fab..4e704998c21 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -39,6 +39,8 @@
 	#define WIN32_LEAN_AND_MEAN
 	#include <winsock2.h>
 	#include <windows.h>
+	#undef min
+	#undef max
 #endif
 
 #include <boost/noncopyable.hpp>
diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp
index 2da4363b1d0..e487e450a96 100644
--- a/indra/llcommon/lltrace.cpp
+++ b/indra/llcommon/lltrace.cpp
@@ -26,6 +26,7 @@
 #include "linden_common.h"
 
 #include "lltrace.h"
+#include "lltracesampler.h"
 #include "llthread.h"
 
 namespace LLTrace
@@ -55,77 +56,6 @@ MasterThreadTrace& getMasterThreadTrace()
 	return *gMasterThreadTrace;
 }
 
-///////////////////////////////////////////////////////////////////////
-// Sampler
-///////////////////////////////////////////////////////////////////////
-
-Sampler::Sampler(ThreadTrace* thread_trace) 
-:	mElapsedSeconds(0),
-	mIsStarted(false),
-	mThreadTrace(thread_trace)
-{
-}
-
-Sampler::~Sampler()
-{
-}
-
-void Sampler::start()
-{
-	reset();
-	resume();
-}
-
-void Sampler::reset()
-{
-	mF32Stats.reset();
-	mS32Stats.reset();
-	mStackTimers.reset();
-
-	mElapsedSeconds = 0.0;
-	mSamplingTimer.reset();
-}
-
-void Sampler::resume()
-{
-	if (!mIsStarted)
-	{
-		mSamplingTimer.reset();
-		getThreadTrace()->activate(this);
-		mIsStarted = true;
-	}
-}
-
-void Sampler::stop()
-{
-	if (mIsStarted)
-	{
-		mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
-		getThreadTrace()->deactivate(this);
-		mIsStarted = false;
-	}
-}
-
-ThreadTrace* Sampler::getThreadTrace()
-{
-	return mThreadTrace;
-}
-
-void Sampler::makePrimary()
-{
-	mF32Stats.makePrimary();
-	mS32Stats.makePrimary();
-	mStackTimers.makePrimary();
-}
-
-void Sampler::mergeFrom( const Sampler* other )
-{
-	mF32Stats.mergeFrom(other->mF32Stats);
-	mS32Stats.mergeFrom(other->mS32Stats);
-	mStackTimers.mergeFrom(other->mStackTimers);
-}
-
-
 ///////////////////////////////////////////////////////////////////////
 // MasterThreadTrace
 ///////////////////////////////////////////////////////////////////////
@@ -148,6 +78,11 @@ ThreadTrace::~ThreadTrace()
 	delete mPrimarySampler;
 }
 
+Sampler* ThreadTrace::getPrimarySampler()
+{
+	return mPrimarySampler;
+}
+
 void ThreadTrace::activate( Sampler* sampler )
 {
 	flushPrimary();
@@ -205,6 +140,34 @@ void SlaveThreadTrace::pushToMaster()
 	mSharedData.copyFrom(mPrimarySampler);
 }
 
+void SlaveThreadTrace::SharedData::copyFrom( Sampler* source )
+{
+	LLMutexLock lock(&mSamplerMutex);
+	{	
+		mSampler->mergeFrom(source);
+	}
+}
+
+void SlaveThreadTrace::SharedData::copyTo( Sampler* sink )
+{
+	LLMutexLock lock(&mSamplerMutex);
+	{
+		sink->mergeFrom(mSampler);
+	}
+}
+
+SlaveThreadTrace::SharedData::~SharedData()
+{
+	delete mSampler;
+}
+
+SlaveThreadTrace::SharedData::SharedData( Sampler* sampler ) :	mSampler(sampler)
+{}
+
+
+
+
+
 ///////////////////////////////////////////////////////////////////////
 // MasterThreadTrace
 ///////////////////////////////////////////////////////////////////////
@@ -217,7 +180,7 @@ void MasterThreadTrace::pullFromSlaveThreads()
 		it != end_it;
 		++it)
 	{
-		it->mSlaveTrace->mSharedData.copyTo(it->mSamplerStorage);
+		(*it)->mSlaveTrace->mSharedData.copyTo((*it)->mSamplerStorage);
 	}
 }
 
@@ -225,7 +188,7 @@ void MasterThreadTrace::addSlaveThread( class SlaveThreadTrace* child )
 {
 	LLMutexLock lock(&mSlaveListMutex);
 
-	mSlaveThreadTraces.push_back(SlaveThreadTraceProxy(child, createSampler()));
+	mSlaveThreadTraces.push_back(new SlaveThreadTraceProxy(child, createSampler()));
 }
 
 void MasterThreadTrace::removeSlaveThread( class SlaveThreadTrace* child )
@@ -236,7 +199,7 @@ void MasterThreadTrace::removeSlaveThread( class SlaveThreadTrace* child )
 		it != end_it;
 		++it)
 	{
-		if (it->mSlaveTrace == child)
+		if ((*it)->mSlaveTrace == child)
 		{
 			mSlaveThreadTraces.erase(it);
 			break;
@@ -266,5 +229,4 @@ MasterThreadTrace::SlaveThreadTraceProxy::~SlaveThreadTraceProxy()
 	delete mSamplerStorage;
 }
 
-
 }
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index a443735e698..c6f920b5e40 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -43,14 +43,16 @@
 
 namespace LLTrace
 {
+	class Sampler;
+
 	void init();
 	void cleanup();
 
-	class MasterThreadTrace& getMasterThreadTrace();
+	class LL_COMMON_API MasterThreadTrace& getMasterThreadTrace();
 
 	// one per thread per type
 	template<typename ACCUMULATOR>
-	class AccumulatorBuffer
+	class LL_COMMON_API AccumulatorBuffer
 	{
 		static const U32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 64;
 	private:
@@ -64,6 +66,8 @@ namespace LLTrace
 
 	public:
 
+		// copying an accumulator buffer does not copy the actual contents, but simply initializes the buffer size
+		// to be identical to the other buffer
 		AccumulatorBuffer(const AccumulatorBuffer& other = getDefaultBuffer())
 		:	mStorageSize(other.mStorageSize),
 			mStorage(new ACCUMULATOR[other.mStorageSize]),
@@ -150,28 +154,30 @@ namespace LLTrace
 	template<typename ACCUMULATOR> LLThreadLocalPtr<ACCUMULATOR> AccumulatorBuffer<ACCUMULATOR>::sPrimaryStorage;
 
 	template<typename ACCUMULATOR>
-	class Trace
+	class LL_COMMON_API TraceType
 	{
 	public:
-		Trace(const std::string& name)
+		TraceType(const std::string& name)
 		:	mName(name)
 		{
 			mAccumulatorIndex = AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer().reserveSlot();
 		}
 
-		LL_FORCE_INLINE ACCUMULATOR& getAccumulator()
+		LL_FORCE_INLINE ACCUMULATOR& getPrimaryAccumulator()
 		{
 			return AccumulatorBuffer<ACCUMULATOR>::getPrimaryStorage()[mAccumulatorIndex];
 		}
 
-	private:
+		ACCUMULATOR& getAccumulator(AccumulatorBuffer<ACCUMULATOR>& buffer) { return buffer[mAccumulatorIndex]; }
+
+	protected:
 		std::string	mName;
 		size_t		mAccumulatorIndex;
 	};
 
 
 	template<typename T>
-	class StatAccumulator
+	class LL_COMMON_API StatAccumulator
 	{
 	public:
 		StatAccumulator()
@@ -217,6 +223,11 @@ namespace LLTrace
 			mMax = 0;
 		}
 
+		T	getSum() { return mSum; }
+		T	getMin() { return mMin; }
+		T	getMax() { return mMax; }
+		T	getMean() { return mSum / (T)mNumSamples; }
+
 	private:
 		T	mSum,
 			mMin,
@@ -226,20 +237,23 @@ namespace LLTrace
 	};
 
 	template <typename T>
-	class Stat : public Trace<StatAccumulator<T> >
+	class LL_COMMON_API Stat 
+	:	public TraceType<StatAccumulator<T> >, 
+		public LLInstanceTracker<Stat<T>, std::string>
 	{
 	public:
 		Stat(const std::string& name) 
-		:	Trace(name)
+		:	TraceType(name),
+			LLInstanceTracker(name)
 		{}
 
 		void sample(T value)
 		{
-			getAccumulator().sample(value);
+			getPrimaryAccumulator().sample(value);
 		}
 	};
 
-	struct TimerAccumulator
+	struct LL_COMMON_API TimerAccumulator
 	{
 		U32 							mTotalTimeCounter,
 										mChildTimeCounter,
@@ -267,11 +281,11 @@ namespace LLTrace
 
 	};
 
-	class BlockTimer : public Trace<TimerAccumulator>
+	class LL_COMMON_API BlockTimer : public TraceType<TimerAccumulator>
 	{
 	public:
 		BlockTimer(const char* name)
-		:	Trace(name)
+		:	TraceType(name)
 		{}
 
 		struct Recorder
@@ -287,7 +301,7 @@ namespace LLTrace
 			:	mLastRecorder(sCurRecorder)
 			{
 				mStartTime = getCPUClockCount32();
-				TimerAccumulator* accumulator = &block_timer.getAccumulator(); // get per-thread accumulator
+				TimerAccumulator* accumulator = &block_timer.getPrimaryAccumulator(); // get per-thread accumulator
 				accumulator->mActiveCount++;
 				accumulator->mCalls++;
 				accumulator->mMoveUpTree |= (accumulator->mParent->mActiveCount == 0);
@@ -353,44 +367,7 @@ namespace LLTrace
 		static Recorder::StackEntry sCurRecorder;
 	};
 
-	class Sampler
-	{
-	public:
-		~Sampler();
-
-		void makePrimary();
-
-		void start();
-		void stop();
-		void resume();
-
-		void mergeFrom(const Sampler* other);
-
-		void reset();
-
-		bool isStarted() { return mIsStarted; }
-
-	private:
-		friend class ThreadTrace;
-		Sampler(class ThreadTrace* thread_trace);
-
-		// no copy
-		Sampler(const Sampler& other) {}
-		// returns data for current thread
-		class ThreadTrace* getThreadTrace(); 
-
-		AccumulatorBuffer<StatAccumulator<F32> >	mF32Stats;
-		AccumulatorBuffer<StatAccumulator<S32> >	mS32Stats;
-
-		AccumulatorBuffer<TimerAccumulator>			mStackTimers;
-
-		bool										mIsStarted;
-		LLTimer										mSamplingTimer;
-		F64											mElapsedSeconds;
-		ThreadTrace*								mThreadTrace;
-	};
-
-	class ThreadTrace
+	class LL_COMMON_API ThreadTrace
 	{
 	public:
 		ThreadTrace();
@@ -406,13 +383,13 @@ namespace LLTrace
 
 		virtual void pushToMaster() = 0;
 
-		Sampler* getPrimarySampler() { return mPrimarySampler; }
+		Sampler* getPrimarySampler();
 	protected:
 		Sampler*				mPrimarySampler;
 		std::list<Sampler*>		mActiveSamplers;
 	};
 
-	class MasterThreadTrace : public ThreadTrace
+	class LL_COMMON_API MasterThreadTrace : public ThreadTrace
 	{
 	public:
 		MasterThreadTrace();
@@ -433,14 +410,17 @@ namespace LLTrace
 			~SlaveThreadTraceProxy();
 			class SlaveThreadTrace*	mSlaveTrace;
 			Sampler*				mSamplerStorage;
+		private:
+			//no need to copy these and then have to duplicate the storage
+			SlaveThreadTraceProxy(const SlaveThreadTraceProxy& other) {}
 		};
-		typedef std::list<SlaveThreadTraceProxy> slave_thread_trace_list_t;
+		typedef std::list<SlaveThreadTraceProxy*> slave_thread_trace_list_t;
 
 		slave_thread_trace_list_t		mSlaveThreadTraces;
 		LLMutex							mSlaveListMutex;
 	};
 
-	class SlaveThreadTrace : public ThreadTrace
+	class LL_COMMON_API SlaveThreadTrace : public ThreadTrace
 	{
 	public:
 		SlaveThreadTrace();
@@ -457,31 +437,12 @@ namespace LLTrace
 		{
 		public:
 			explicit 
-			SharedData(Sampler* sampler) 
-			:	mSampler(sampler)
-			{
-			}
+			SharedData(Sampler* sampler);
 
-			~SharedData()
-			{
-				delete mSampler;
-			}
+			~SharedData();
 
-			void copyFrom(Sampler* source)
-			{
-				LLMutexLock lock(&mSamplerMutex);
-				{	
-					mSampler->mergeFrom(source);
-				}
-			}
-
-			void copyTo(Sampler* sink)
-			{
-				LLMutexLock lock(&mSamplerMutex);
-				{
-					sink->mergeFrom(mSampler);
-				}
-			}
+			void copyFrom(Sampler* source);
+			void copyTo(Sampler* sink);
 		private:
 			// add a cache line's worth of unused space to avoid any potential of false sharing
 			LLMutex					mSamplerMutex;
@@ -489,14 +450,6 @@ namespace LLTrace
 		};
 		SharedData					mSharedData;
 	};
-
-	class TimeInterval 
-	{
-	public:
-		void start() {}
-		void stop() {}
-		void resume() {}
-	};
 }
 
 #endif // LL_LLTRACE_H
diff --git a/indra/llcommon/lltracesampler.cpp b/indra/llcommon/lltracesampler.cpp
new file mode 100644
index 00000000000..0cf01d7a3ad
--- /dev/null
+++ b/indra/llcommon/lltracesampler.cpp
@@ -0,0 +1,103 @@
+/** 
+ * @file lltracesampler.cpp
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "lltracesampler.h"
+
+namespace LLTrace
+{
+
+///////////////////////////////////////////////////////////////////////
+// Sampler
+///////////////////////////////////////////////////////////////////////
+
+Sampler::Sampler(ThreadTrace* thread_trace) 
+:	mElapsedSeconds(0),
+	mIsStarted(false),
+	mThreadTrace(thread_trace)
+{
+}
+
+Sampler::~Sampler()
+{
+}
+
+void Sampler::start()
+{
+	reset();
+	resume();
+}
+
+void Sampler::reset()
+{
+	mF32Stats.reset();
+	mS32Stats.reset();
+	mStackTimers.reset();
+
+	mElapsedSeconds = 0.0;
+	mSamplingTimer.reset();
+}
+
+void Sampler::resume()
+{
+	if (!mIsStarted)
+	{
+		mSamplingTimer.reset();
+		getThreadTrace()->activate(this);
+		mIsStarted = true;
+	}
+}
+
+void Sampler::stop()
+{
+	if (mIsStarted)
+	{
+		mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
+		getThreadTrace()->deactivate(this);
+		mIsStarted = false;
+	}
+}
+
+ThreadTrace* Sampler::getThreadTrace()
+{
+	return mThreadTrace;
+}
+
+void Sampler::makePrimary()
+{
+	mF32Stats.makePrimary();
+	mS32Stats.makePrimary();
+	mStackTimers.makePrimary();
+}
+
+void Sampler::mergeFrom( const Sampler* other )
+{
+	mF32Stats.mergeFrom(other->mF32Stats);
+	mS32Stats.mergeFrom(other->mS32Stats);
+	mStackTimers.mergeFrom(other->mStackTimers);
+}
+
+}
diff --git a/indra/llcommon/lltracesampler.h b/indra/llcommon/lltracesampler.h
new file mode 100644
index 00000000000..d1ca7fc9bb8
--- /dev/null
+++ b/indra/llcommon/lltracesampler.h
@@ -0,0 +1,91 @@
+/** 
+ * @file lltracesampler.h
+ * @brief Sampling object for collecting runtime statistics originating from lltrace.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLTRACESAMPLER_H
+#define LL_LLTRACESAMPLER_H
+
+#include "stdtypes.h"
+#include "llpreprocessor.h"
+
+#include "lltrace.h"
+
+namespace LLTrace
+{
+	class LL_COMMON_API Sampler
+	{
+	public:
+		~Sampler();
+
+		void makePrimary();
+
+		void start();
+		void stop();
+		void resume();
+
+		void mergeFrom(const Sampler* other);
+
+		void reset();
+
+		bool isStarted() { return mIsStarted; }
+
+		F32 getSum(Stat<F32>& stat) { return stat.getAccumulator(mF32Stats).getSum(); }
+		F32 getMin(Stat<F32>& stat) { return stat.getAccumulator(mF32Stats).getMin(); }
+		F32 getMax(Stat<F32>& stat) { return stat.getAccumulator(mF32Stats).getMax(); }
+		F32 getMean(Stat<F32>& stat) { return stat.getAccumulator(mF32Stats).getMean(); }
+
+		S32 getSum(Stat<S32>& stat) { return stat.getAccumulator(mS32Stats).getSum(); }
+		S32 getMin(Stat<S32>& stat) { return stat.getAccumulator(mS32Stats).getMin(); }
+		S32 getMax(Stat<S32>& stat) { return stat.getAccumulator(mS32Stats).getMax(); }
+		S32 getMean(Stat<S32>& stat) { return stat.getAccumulator(mS32Stats).getMean(); }
+
+		F64 getSampleTime() { return mElapsedSeconds; }
+
+	private:
+		friend class ThreadTrace;
+		Sampler(class ThreadTrace* thread_trace);
+
+		// no copy
+		Sampler(const Sampler& other) {}
+		// returns data for current thread
+		class ThreadTrace* getThreadTrace(); 
+
+		//TODO: take snapshot at sampler start so we can simplify updates
+		//AccumulatorBuffer<StatAccumulator<F32> >	mF32StatsStart;
+		//AccumulatorBuffer<StatAccumulator<S32> >	mS32StatsStart;
+		//AccumulatorBuffer<TimerAccumulator>			mStackTimersStart;
+
+		AccumulatorBuffer<StatAccumulator<F32> >	mF32Stats;
+		AccumulatorBuffer<StatAccumulator<S32> >	mS32Stats;
+		AccumulatorBuffer<TimerAccumulator>			mStackTimers;
+
+		bool										mIsStarted;
+		LLTimer										mSamplingTimer;
+		F64											mElapsedSeconds;
+		ThreadTrace*								mThreadTrace;
+	};
+}
+
+#endif // LL_LLTRACESAMPLER_H
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index 509de51f4df..605b424b354 100644
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -543,6 +543,8 @@ extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange;
 #define WIN32_LEAN_AND_MEAN
 #include <winsock2.h>
 #include <windows.h>
+#undef min
+#undef max
 
 //----------------------------------------------------------------------------
 #include <GL/gl.h>
diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp
index a21d7aa6a17..2d1b5825986 100644
--- a/indra/llui/llstatbar.cpp
+++ b/indra/llui/llstatbar.cpp
@@ -36,6 +36,7 @@
 
 #include "llstat.h"
 #include "lluictrlfactory.h"
+#include "lltracesampler.h"
 
 ///////////////////////////////////////////////////////////////////////////////////
 
@@ -46,6 +47,8 @@ LLStatBar::LLStatBar(const Params& p)
 	  mMinBar(p.bar_min),
 	  mMaxBar(p.bar_max),
 	  mStatp(LLStat::getInstance(p.stat)),
+	  mFloatStatp(LLTrace::Stat<F32>::getInstance(p.stat)),
+	  mIntStatp(LLTrace::Stat<S32>::getInstance(p.stat)),
 	  mTickSpacing(p.tick_spacing),
 	  mLabelSpacing(p.label_spacing),
 	  mPrecision(p.precision),
@@ -84,30 +87,66 @@ BOOL LLStatBar::handleMouseDown(S32 x, S32 y, MASK mask)
 
 void LLStatBar::draw()
 {
-	if (!mStatp)
+	F32 current = 0.f, 
+		min = 0.f, 
+		max = 0.f,
+		mean = 0.f;
+
+	if (mStatp)
 	{
-//		llinfos << "No stats for statistics bar!" << llendl;
-		return;
+		// Get the values.
+		if (mPerSec)
+		{
+			current = mStatp->getCurrentPerSec();
+			min = mStatp->getMinPerSec();
+			max = mStatp->getMaxPerSec();
+			mean = mStatp->getMeanPerSec();
+		}
+		else
+		{
+			current = mStatp->getCurrent();
+			min = mStatp->getMin();
+			max = mStatp->getMax();
+			mean = mStatp->getMean();
+		}
 	}
-
-	// Get the values.
-	F32 current, min, max, mean;
-	if (mPerSec)
+	else if (mFloatStatp)
 	{
-		current = mStatp->getCurrentPerSec();
-		min = mStatp->getMinPerSec();
-		max = mStatp->getMaxPerSec();
-		mean = mStatp->getMeanPerSec();
+		LLTrace::Sampler* sampler = LLThread::getTraceData()->getPrimarySampler();
+		if (mPerSec)
+		{
+			current = sampler->getSum(*mFloatStatp) / sampler->getSampleTime();
+			min = sampler->getMin(*mFloatStatp) / sampler->getSampleTime();
+			max = sampler->getMax(*mFloatStatp) / sampler->getSampleTime();
+			mean = sampler->getMean(*mFloatStatp) / sampler->getSampleTime();
+		}
+		else
+		{
+			current = sampler->getSum(*mFloatStatp);
+			min = sampler->getMin(*mFloatStatp);
+			max = sampler->getMax(*mFloatStatp);
+			mean = sampler->getMean(*mFloatStatp);
+		}
 	}
-	else
+	else if (mIntStatp)
 	{
-		current = mStatp->getCurrent();
-		min = mStatp->getMin();
-		max = mStatp->getMax();
-		mean = mStatp->getMean();
+		LLTrace::Sampler* sampler = LLThread::getTraceData()->getPrimarySampler();
+		if (mPerSec)
+		{
+			current = (F32)sampler->getSum(*mIntStatp) / sampler->getSampleTime();
+			min = (F32)sampler->getMin(*mIntStatp) / sampler->getSampleTime();
+			max = (F32)sampler->getMax(*mIntStatp) / sampler->getSampleTime();
+			mean = (F32)sampler->getMean(*mIntStatp) / sampler->getSampleTime();
+		}
+		else
+		{
+			current = (F32)sampler->getSum(*mIntStatp);
+			min = (F32)sampler->getMin(*mIntStatp);
+			max = (F32)sampler->getMax(*mIntStatp);
+			mean = (F32)sampler->getMean(*mIntStatp);
+		}
 	}
 
-
 	if ((mUpdatesPerSec == 0.f) || (mUpdateTimer.getElapsedTimeF32() > 1.f/mUpdatesPerSec) || (mValue == 0.f))
 	{
 		if (mDisplayMean)
@@ -153,7 +192,7 @@ void LLStatBar::draw()
 											 LLFontGL::RIGHT, LLFontGL::TOP);
 
 	value_format = llformat( "%%.%df", mPrecision);
-	if (mDisplayBar)
+	if (mDisplayBar && mStatp)
 	{
 		std::string tick_label;
 
@@ -213,9 +252,9 @@ void LLStatBar::draw()
 		right = (S32) ((max - mMinBar) * value_scale);
 		gl_rect_2d(left, top, right, bottom, LLColor4(1.f, 0.f, 0.f, 0.25f));
 
-		S32 num_values = mStatp->getNumValues() - 1;
 		if (mDisplayHistory)
 		{
+			S32 num_values = mStatp->getNumValues() - 1;
 			S32 i;
 			for (i = 0; i < num_values; i++)
 			{
@@ -270,7 +309,7 @@ LLRect LLStatBar::getRequiredRect()
 
 	if (mDisplayBar)
 	{
-		if (mDisplayHistory)
+		if (mDisplayHistory && mStatp)
 		{
 			rect.mTop = 35 + mStatp->getNumBins();
 		}
diff --git a/indra/llui/llstatbar.h b/indra/llui/llstatbar.h
index 7e636d0aa7e..8348290abff 100644
--- a/indra/llui/llstatbar.h
+++ b/indra/llui/llstatbar.h
@@ -29,6 +29,7 @@
 
 #include "llview.h"
 #include "llframetimer.h"
+#include "lltrace.h"
 
 class LLStat;
 
@@ -92,6 +93,8 @@ class LLStatBar : public LLView
 	BOOL mDisplayMean;			// If true, display mean, if false, display current value
 
 	LLStat* mStatp;
+	LLTrace::Stat<F32>* mFloatStatp;
+	LLTrace::Stat<S32>* mIntStatp;
 
 	LLFrameTimer mUpdateTimer;
 	LLUIString mLabel;
diff --git a/indra/llui/llstatgraph.cpp b/indra/llui/llstatgraph.cpp
index e44887ebf0e..19896c45974 100644
--- a/indra/llui/llstatgraph.cpp
+++ b/indra/llui/llstatgraph.cpp
@@ -35,28 +35,38 @@
 #include "llstat.h"
 #include "llgl.h"
 #include "llglheaders.h"
+#include "lltracesampler.h"
 //#include "llviewercontrol.h"
 
 ///////////////////////////////////////////////////////////////////////////////////
 
-LLStatGraph::LLStatGraph(const LLView::Params& p)
-:	LLView(p)
+LLStatGraph::LLStatGraph(const Params& p)
+:	LLView(p),
+	mMin(p.min),
+	mMax(p.max),
+	mPerSec(true),
+	mPrecision(p.precision),
+	mValue(p.value),
+	mStatp(p.stat.legacy_stat),
+	mF32Statp(p.stat.f32_stat),
+	mS32Statp(p.stat.s32_stat)
 {
-	mStatp = NULL;
 	setToolTip(p.name());
-	mNumThresholds = 3;
-	mThresholdColors[0] = LLColor4(0.f, 1.f, 0.f, 1.f);
-	mThresholdColors[1] = LLColor4(1.f, 1.f, 0.f, 1.f);
-	mThresholdColors[2] = LLColor4(1.f, 0.f, 0.f, 1.f);
-	mThresholdColors[3] = LLColor4(1.f, 0.f, 0.f, 1.f);
-	mThresholds[0] = 50.f;
-	mThresholds[1] = 75.f;
-	mThresholds[2] = 100.f;
-	mMin = 0.f;
-	mMax = 125.f;
-	mPerSec = TRUE;
-	mValue = 0.f;
-	mPrecision = 0;
+
+	for(LLInitParam::ParamIterator<ThresholdParams>::const_iterator it = p.thresholds.threshold.begin(), end_it = p.thresholds.threshold.end();
+		it != end_it;
+		++it)
+	{
+		mThresholds.push_back(Threshold(it->value(), it->color));
+	}
+
+	//mThresholdColors[0] = LLColor4(0.f, 1.f, 0.f, 1.f);
+	//mThresholdColors[1] = LLColor4(1.f, 1.f, 0.f, 1.f);
+	//mThresholdColors[2] = LLColor4(1.f, 0.f, 0.f, 1.f);
+	//mThresholdColors[3] = LLColor4(1.f, 0.f, 0.f, 1.f);
+	//mThresholds[0] = 50.f;
+	//mThresholds[1] = 75.f;
+	//mThresholds[2] = 100.f;
 }
 
 void LLStatGraph::draw()
@@ -74,6 +84,33 @@ void LLStatGraph::draw()
 			mValue = mStatp->getMean();
 		}
 	}
+	else if (mF32Statp)
+	{
+		LLTrace::Sampler* sampler = LLThread::getTraceData()->getPrimarySampler();
+
+		if (mPerSec)
+		{
+			mValue = sampler->getSum(*mF32Statp) / sampler->getSampleTime();
+		}
+		else
+		{
+			mValue = sampler->getSum(*mF32Statp);
+		}
+
+	}
+	else if (mS32Statp)
+	{
+		LLTrace::Sampler* sampler = LLThread::getTraceData()->getPrimarySampler();
+
+		if (mPerSec)
+		{
+			mValue = sampler->getSum(*mS32Statp) / sampler->getSampleTime();
+		}
+		else
+		{
+			mValue = sampler->getSum(*mS32Statp);
+		}
+	}
 	frac = (mValue - mMin) / range;
 	frac = llmax(0.f, frac);
 	frac = llmin(1.f, frac);
@@ -91,19 +128,22 @@ void LLStatGraph::draw()
 
 	LLColor4 color;
 
-	S32 i;
-	for (i = 0; i < mNumThresholds - 1; i++)
+	//S32 i;
+	//for (i = 0; i < mNumThresholds - 1; i++)
+	//{
+	//	if (mThresholds[i] > mValue)
+	//	{
+	//		break;
+	//	}
+	//}
+
+	threshold_vec_t::iterator it = std::lower_bound(mThresholds.begin(), mThresholds.end(), Threshold(mValue / mMax, LLUIColor()));
+
+	if (it != mThresholds.begin())
 	{
-		if (mThresholds[i] > mValue)
-		{
-			break;
-		}
+		it--;
 	}
 
-	//gl_drop_shadow(0,  getRect().getHeight(), getRect().getWidth(), 0,
-	//				LLUIColorTable::instance().getColor("ColorDropShadow"), 
-	//				(S32) gSavedSettings.getF32("DropShadowFloater") );
-
 	color = LLUIColorTable::instance().getColor( "MenuDefaultBgColor" );
 	gGL.color4fv(color.mV);
 	gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, TRUE);
@@ -111,16 +151,11 @@ void LLStatGraph::draw()
 	gGL.color4fv(LLColor4::black.mV);
 	gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, FALSE);
 	
-	color = mThresholdColors[i];
+	color = it->mColor;
 	gGL.color4fv(color.mV);
 	gl_rect_2d(1, llround(frac*getRect().getHeight()), getRect().getWidth() - 1, 0, TRUE);
 }
 
-void LLStatGraph::setValue(const LLSD& value)
-{
-	mValue = (F32)value.asReal();
-}
-
 void LLStatGraph::setMin(const F32 min)
 {
 	mMin = min;
@@ -131,27 +166,3 @@ void LLStatGraph::setMax(const F32 max)
 	mMax = max;
 }
 
-void LLStatGraph::setStat(LLStat *statp)
-{
-	mStatp = statp;
-}
-
-void LLStatGraph::setLabel(const std::string& label)
-{
-	mLabel = label;
-}
-
-void LLStatGraph::setUnits(const std::string& units)
-{
-	mUnits = units;
-}
-
-void LLStatGraph::setPrecision(const S32 precision)
-{
-	mPrecision = precision;
-}
-
-void LLStatGraph::setThreshold(const S32 i, F32 value)
-{
-	mThresholds[i] = value;
-}
diff --git a/indra/llui/llstatgraph.h b/indra/llui/llstatgraph.h
index 757525e232f..e7de9456946 100644
--- a/indra/llui/llstatgraph.h
+++ b/indra/llui/llstatgraph.h
@@ -30,29 +30,88 @@
 #include "llview.h"
 #include "llframetimer.h"
 #include "v4color.h"
+#include "lltrace.h"
 
 class LLStat;
 
 class LLStatGraph : public LLView
 {
 public:
-	LLStatGraph(const LLView::Params&);
+	struct ThresholdParams : public LLInitParam::Block<ThresholdParams>
+	{
+		Mandatory<F32>	value;
+		Optional<LLUIColor>	color;
 
-	virtual void draw();
+		ThresholdParams()
+		:	value("value"),
+			color("color", LLColor4::white)
+		{}
+	};
+
+	struct Thresholds : public LLInitParam::Block<Thresholds>
+	{
+		Multiple<ThresholdParams> threshold;
+
+		Thresholds()
+		:	threshold("threshold")
+		{}
+	};
+
+	struct StatParams : public LLInitParam::ChoiceBlock<StatParams>
+	{
+		Alternative<LLStat*>				legacy_stat;
+		Alternative<LLTrace::Stat<F32>* >	f32_stat;
+		Alternative<LLTrace::Stat<S32>* >	s32_stat;
+	};
+
+	struct Params : public LLInitParam::Block<Params, LLView::Params>
+	{
+		Mandatory<StatParams>	stat;
+		Optional<std::string>	label,
+								units;
+		Optional<S32>			precision;
+		Optional<F32>			min,
+								max;
+		Optional<bool>			per_sec;
+		Optional<F32>			value;
+
+		Optional<Thresholds>	thresholds;
+
+		Params()
+		:	stat("stat"),
+			label("label"),
+			units("units"),
+			precision("precision", 0),
+			min("min", 0.f),
+			max("max", 125.f),
+			per_sec("per_sec", true),
+			value("value", 0.f),
+			thresholds("thresholds")
+		{
+			Thresholds _thresholds;
+			_thresholds.threshold.add(ThresholdParams().value(0.f).color(LLColor4::green))
+								.add(ThresholdParams().value(0.33f).color(LLColor4::yellow))
+								.add(ThresholdParams().value(0.5f).color(LLColor4::red))
+								.add(ThresholdParams().value(0.75f).color(LLColor4::red));
+			thresholds = _thresholds;
+		}
+	};
+	LLStatGraph(const Params&);
 
-	void setLabel(const std::string& label);
-	void setUnits(const std::string& units);
-	void setPrecision(const S32 precision);
-	void setStat(LLStat *statp);
-	void setThreshold(const S32 i, F32 value);
 	void setMin(const F32 min);
 	void setMax(const F32 max);
 
+	virtual void draw();
+
 	/*virtual*/ void setValue(const LLSD& value);
 	
-	LLStat *mStatp;
-	BOOL mPerSec;
 private:
+	LLStat*				mStatp;
+	LLTrace::Stat<F32>*	mF32Statp;
+	LLTrace::Stat<S32>*	mS32Statp;
+
+	BOOL mPerSec;
+
 	F32 mValue;
 
 	F32 mMin;
@@ -62,9 +121,25 @@ class LLStatGraph : public LLView
 	std::string mUnits;
 	S32 mPrecision; // Num of digits of precision after dot
 
-	S32 mNumThresholds;
-	F32 mThresholds[4];
-	LLColor4 mThresholdColors[4];
+	struct Threshold
+	{
+		Threshold(F32 value, const LLUIColor& color)
+		:	mValue(value),
+			mColor(color)
+		{}
+
+		F32 mValue;
+		LLUIColor mColor;
+		bool operator <(const Threshold& other)
+		{
+			return mValue < other.mValue;
+		}
+	};
+	typedef std::vector<Threshold> threshold_vec_t;
+	threshold_vec_t mThresholds;
+	//S32 mNumThresholds;
+	//F32 mThresholds[4];
+	//LLColor4 mThresholdColors[4];
 };
 
 #endif  // LL_LLSTATGRAPH_H
diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp
index 4892de9da0a..9f499ef4ef4 100644
--- a/indra/newview/llstatusbar.cpp
+++ b/indra/newview/llstatusbar.cpp
@@ -198,10 +198,10 @@ BOOL LLStatusBar::postBuild()
 	sgp.rect(r);
 	sgp.follows.flags(FOLLOWS_BOTTOM | FOLLOWS_RIGHT);
 	sgp.mouse_opaque(false);
+	sgp.stat.f32_stat(&STAT_KBIT);
+	sgp.units("Kbps");
+	sgp.precision(0);
 	mSGBandwidth = LLUICtrlFactory::create<LLStatGraph>(sgp);
-	mSGBandwidth->setStat(&LLViewerStats::getInstance()->mKBitStat);
-	mSGBandwidth->setUnits("Kbps");
-	mSGBandwidth->setPrecision(0);
 	addChild(mSGBandwidth);
 	x -= SIM_STAT_WIDTH + 2;
 
@@ -212,17 +212,20 @@ BOOL LLStatusBar::postBuild()
 	pgp.rect(r);
 	pgp.follows.flags(FOLLOWS_BOTTOM | FOLLOWS_RIGHT);
 	pgp.mouse_opaque(false);
+	pgp.stat.legacy_stat(&LLViewerStats::getInstance()->mPacketsLostPercentStat);
+	pgp.units("%");
+	pgp.min(0.f);
+	pgp.max(5.f);
+	pgp.precision(1);
+	pgp.per_sec(false);
+	LLStatGraph::Thresholds thresholds;
+	thresholds.threshold.add(LLStatGraph::ThresholdParams().value(0.1).color(LLColor4::green))
+						.add(LLStatGraph::ThresholdParams().value(0.25f).color(LLColor4::yellow))
+						.add(LLStatGraph::ThresholdParams().value(0.6f).color(LLColor4::red));
+
+	pgp.thresholds(thresholds);
 
 	mSGPacketLoss = LLUICtrlFactory::create<LLStatGraph>(pgp);
-	mSGPacketLoss->setStat(&LLViewerStats::getInstance()->mPacketsLostPercentStat);
-	mSGPacketLoss->setUnits("%");
-	mSGPacketLoss->setMin(0.f);
-	mSGPacketLoss->setMax(5.f);
-	mSGPacketLoss->setThreshold(0, 0.5f);
-	mSGPacketLoss->setThreshold(1, 1.f);
-	mSGPacketLoss->setThreshold(2, 3.f);
-	mSGPacketLoss->setPrecision(1);
-	mSGPacketLoss->mPerSec = FALSE;
 	addChild(mSGPacketLoss);
 
 	mPanelVolumePulldown = new LLPanelVolumePulldown();
@@ -252,9 +255,9 @@ void LLStatusBar::refresh()
 		F32 bwtotal = gViewerThrottle.getMaxBandwidth() / 1000.f;
 		mSGBandwidth->setMin(0.f);
 		mSGBandwidth->setMax(bwtotal*1.25f);
-		mSGBandwidth->setThreshold(0, bwtotal*0.75f);
-		mSGBandwidth->setThreshold(1, bwtotal);
-		mSGBandwidth->setThreshold(2, bwtotal);
+		//mSGBandwidth->setThreshold(0, bwtotal*0.75f);
+		//mSGBandwidth->setThreshold(1, bwtotal);
+		//mSGBandwidth->setThreshold(2, bwtotal);
 	}
 	
 	// update clock every 10 seconds
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index da87cc2673f..b1aeaef91d6 100755
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -62,6 +62,13 @@
 #include "llmeshrepository.h" //for LLMeshRepository::sBytesReceived
 
 
+LLTrace::Stat<F32>	STAT_KBIT("kbitstat"),
+					STAT_LAYERS_KBIT("layerskbitstat"),
+					STAT_OBJECT_KBIT("objectkbitstat"),
+					STAT_ASSET_KBIT("assetkbitstat"),
+					STAT_TEXTURE_KBIT("texturekbitstat");
+
+
 class StatAttributes
 {
 public:
@@ -198,11 +205,6 @@ const StatAttributes STAT_INFO[LLViewerStats::ST_COUNT] =
 };
 
 LLViewerStats::LLViewerStats() :
-	mKBitStat("kbitstat"),
-	mLayersKBitStat("layerskbitstat"),
-	mObjectKBitStat("objectkbitstat"),
-	mAssetKBitStat("assetkbitstat"),
-	mTextureKBitStat("texturekbitstat"),
 	mVFSPendingOperations("vfspendingoperations"),
 	mFPSStat("fpsstat"),
 	mPacketsInStat("packetsinstat"),
@@ -261,7 +263,8 @@ LLViewerStats::LLViewerStats() :
 	mNumNewObjectsStat("numnewobjectsstat"),
 	mNumSizeCulledStat("numsizeculledstat"),
 	mNumVisCulledStat("numvisculledstat"),
-	mLastTimeDiff(0.0)
+	mLastTimeDiff(0.0),
+	mSampler(LLThread::getTraceData()->createSampler())
 {
 	for (S32 i = 0; i < ST_COUNT; i++)
 	{
@@ -274,17 +277,18 @@ LLViewerStats::LLViewerStats() :
 	}	
 	
 	mAgentPositionSnaps.reset();
+	mSampler->start();
+}
+
+LLViewerStats::~LLViewerStats()
+{
+	delete mSampler;
 }
 
 void LLViewerStats::resetStats()
 {
 	LLViewerStats& stats = LLViewerStats::instance();
-	stats.mKBitStat.reset();
-	stats.mLayersKBitStat.reset();
-	stats.mObjectKBitStat.reset();
-	stats.mTextureKBitStat.reset();
 	stats.mVFSPendingOperations.reset();
-	stats.mAssetKBitStat.reset();
 	stats.mPacketsInStat.reset();
 	stats.mPacketsLostStat.reset();
 	stats.mPacketsOutStat.reset();
@@ -463,10 +467,13 @@ void update_statistics()
 
 	stats.mFPSStat.addValue(1);
 	F32 layer_bits = (F32)(gVLManager.getLandBits() + gVLManager.getWindBits() + gVLManager.getCloudBits());
-	stats.mLayersKBitStat.addValue(layer_bits/1024.f);
-	stats.mObjectKBitStat.addValue(gObjectBits/1024.f);
+	STAT_LAYERS_KBIT.sample(layer_bits/1024.f);
+	//stats.mLayersKBitStat.addValue(layer_bits/1024.f);
+	STAT_OBJECT_KBIT.sample(gObjectBits/1024.f);
+	//stats.mObjectKBitStat.addValue(gObjectBits/1024.f);
 	stats.mVFSPendingOperations.addValue(LLVFile::getVFSThread()->getPending());
-	stats.mAssetKBitStat.addValue(gTransferManager.getTransferBitsIn(LLTCT_ASSET)/1024.f);
+	STAT_ASSET_KBIT.sample(gTransferManager.getTransferBitsIn(LLTCT_ASSET)/1024.f);
+	//stats.mAssetKBitStat.addValue(gTransferManager.getTransferBitsIn(LLTCT_ASSET)/1024.f);
 	gTransferManager.resetTransferBitsIn(LLTCT_ASSET);
 
 	if (LLAppViewer::getTextureFetch()->getNumRequests() == 0)
@@ -503,7 +510,8 @@ void update_statistics()
 		static LLFrameTimer texture_stats_timer;
 		if (texture_stats_timer.getElapsedTimeF32() >= texture_stats_freq)
 		{
-			stats.mTextureKBitStat.addValue(LLViewerTextureList::sTextureBits/1024.f);
+			STAT_TEXTURE_KBIT.sample(LLViewerTextureList::sTextureBits/1024.f);
+			//stats.mTextureKBitStat.addValue(LLViewerTextureList::sTextureBits/1024.f);
 			stats.mTexturePacketsStat.addValue(LLViewerTextureList::sTexturePackets);
 			gTotalTextureBytes += LLViewerTextureList::sTextureBits / 8;
 			LLViewerTextureList::sTextureBits = 0;
diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h
index 0d8f2a45c0a..ca70660ce95 100755
--- a/indra/newview/llviewerstats.h
+++ b/indra/newview/llviewerstats.h
@@ -29,16 +29,18 @@
 
 #include "llstat.h"
 #include "lltextureinfo.h"
+#include "lltracesampler.h"
+
+extern LLTrace::Stat<F32>	STAT_KBIT,
+							STAT_LAYERS_KBIT,
+							STAT_OBJECT_KBIT,
+							STAT_ASSET_KBIT,
+							STAT_TEXTURE_KBIT;
 
 class LLViewerStats : public LLSingleton<LLViewerStats>
 {
 public:
-	LLStat	mKBitStat,
-			mLayersKBitStat,
-			mObjectKBitStat,
-			mAssetKBitStat,
-			mTextureKBitStat,
-			mVFSPendingOperations,
+	LLStat	mVFSPendingOperations,
 			mFPSStat,
 			mPacketsInStat,
 			mPacketsLostStat,
@@ -110,7 +112,9 @@ class LLViewerStats : public LLSingleton<LLViewerStats>
 			mNumVisCulledStat;
 
 	void resetStats();
+
 public:
+
 	// If you change this, please also add a corresponding text label in llviewerstats.cpp
 	enum EStatType
 	{
@@ -177,6 +181,7 @@ class LLViewerStats : public LLSingleton<LLViewerStats>
 	};
 
 	LLViewerStats();
+	~LLViewerStats();
 
 	// all return latest value of given stat
 	F64 getStat(EStatType type) const;
@@ -292,8 +297,11 @@ class LLViewerStats : public LLSingleton<LLViewerStats>
 		static void recordPhaseStat(const std::string& phase_name, F32 value);
 	};
 
+	LLTrace::Sampler* getSampler() { return mSampler; }
+
 private:
 	F64	mStats[ST_COUNT];
+	LLTrace::Sampler*	mSampler;
 
 	F64 mLastTimeDiff;  // used for time stat updates
 };
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 17d8e5e4fa8..034f8edf248 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -622,7 +622,9 @@ void LLViewerTextureList::updateImages(F32 max_time)
 	}
 	cleared = FALSE;
 
-	LLAppViewer::getTextureFetch()->setTextureBandwidth(LLViewerStats::getInstance()->mTextureKBitStat.getMeanPerSec());
+	LLTrace::Sampler* sampler = LLThread::getTraceData()->getPrimarySampler();
+
+	LLAppViewer::getTextureFetch()->setTextureBandwidth(sampler->getMean(STAT_TEXTURE_KBIT) / sampler->getSampleTime());
 
 	LLViewerStats::getInstance()->mNumImagesStat.addValue(sNumImages);
 	LLViewerStats::getInstance()->mNumRawImagesStat.addValue(LLImageRaw::sRawImageCount);
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 43152c9025c..97079e05889 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -704,7 +704,8 @@ void LLWorld::updateNetStats()
 	S32 actual_out_bits = gMessageSystem->mPacketRing.getAndResetActualOutBits();
 	LLViewerStats::getInstance()->mActualInKBitStat.addValue(actual_in_bits/1024.f);
 	LLViewerStats::getInstance()->mActualOutKBitStat.addValue(actual_out_bits/1024.f);
-	LLViewerStats::getInstance()->mKBitStat.addValue(bits/1024.f);
+	STAT_KBIT.sample(bits/1024.f);
+	//LLViewerStats::getInstance()->mKBitStat.addValue(bits/1024.f);
 	LLViewerStats::getInstance()->mPacketsInStat.addValue(packets_in);
 	LLViewerStats::getInstance()->mPacketsOutStat.addValue(packets_out);
 	LLViewerStats::getInstance()->mPacketsLostStat.addValue(gMessageSystem->mDroppedPackets);
-- 
GitLab