diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 6c07974f69bc6cc52345056b50740673b16ebffc..5972e7aef829e52d27ad1081c4ea06784a5d2193 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -44,6 +44,7 @@
 #include "llagentwearables.h"
 #include "llwindow.h"
 #include "llviewerstats.h"
+#include "llviewerstatsrecorder.h"
 #include "llmd5.h"
 #include "llpumpio.h"
 #include "llmimetypes.h"
@@ -648,6 +649,10 @@ bool LLAppViewer::init()
 
     mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling"));
 
+#if LL_RECORD_VIEWER_STATS
+	LLViewerStatsRecorder::initClass();
+#endif
+
     // *NOTE:Mani - LLCurl::initClass is not thread safe. 
     // Called before threads are created.
     LLCurl::initClass();
@@ -950,6 +955,8 @@ bool LLAppViewer::init()
 
 	LLAgentLanguage::init();
 
+
+
 	return true;
 }
 
@@ -1665,6 +1672,10 @@ bool LLAppViewer::cleanup()
 	}
 	LLMetricPerformanceTesterBasic::cleanClass() ;
 
+#if LL_RECORD_VIEWER_STATS
+	LLViewerStatsRecorder::cleanupClass();
+#endif
+
 	llinfos << "Cleaning up Media and Textures" << llendflush;
 
 	//Note:
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 5a42f10c8f7e0ed6107d7f15e4fd79485754d019..249799bf553d946dc38bea51d4c9a705541a92bc 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -350,8 +350,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 	LLDataPacker *cached_dpp = NULL;
 
 #if LL_RECORD_VIEWER_STATS
-	static LLViewerStatsRecorder	stats_recorder;
-	stats_recorder.initObjectUpdateEvents(regionp);
+	LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(regionp);
 #endif
 
 	for (i = 0; i < num_objects; i++)
@@ -368,7 +367,8 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i);
 		
 			// Lookup data packer and add this id to cache miss lists if necessary.
-			cached_dpp = regionp->getDP(id, crc);
+			U8 cache_miss_type = LLViewerRegion::CACHE_MISS_TYPE_NONE;
+			cached_dpp = regionp->getDP(id, crc, cache_miss_type);
 			if (cached_dpp)
 			{
 				// Cache Hit.
@@ -381,8 +381,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			{
 				// Cache Miss.
 				#if LL_RECORD_VIEWER_STATS
-				const BOOL success = TRUE;
-				stats_recorder.recordObjectUpdateEvent(regionp, id, update_type, success, NULL);
+				LLViewerStatsRecorder::instance()->recordCacheMissEvent(id, update_type, cache_miss_type);
 				#endif
 
 				continue; // no data packer, skip this object
@@ -503,8 +502,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 				{
 					// llinfos << "terse update for an unknown object:" << fullid << llendl;
 					#if LL_RECORD_VIEWER_STATS
-					const BOOL success = FALSE;
-					stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, NULL);
+					LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
 					#endif
 					continue;
 				}
@@ -518,8 +516,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 				{
 					// llinfos << "terse update for an unknown object:" << fullid << llendl;
 					#if LL_RECORD_VIEWER_STATS
-					const BOOL success = FALSE;
-					stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, NULL);
+					LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
 					#endif
 					continue;
 				}
@@ -532,8 +529,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 				mNumDeadObjectUpdates++;
 				// llinfos << "update for a dead object:" << fullid << llendl;
 				#if LL_RECORD_VIEWER_STATS
-				const BOOL success = FALSE;
-				stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, NULL);
+				LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
 				#endif
 				continue;
 			}
@@ -543,8 +539,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			if (!objectp)
 			{
 				#if LL_RECORD_VIEWER_STATS
-				const BOOL success = FALSE;
-				stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, NULL);
+				LLViewerStatsRecorder::instance()->recordObjectUpdateFailure(local_id, update_type);
 				#endif
 				continue;
 			}
@@ -584,13 +579,12 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			processUpdateCore(objectp, user_data, i, update_type, NULL, justCreated);
 		}
 		#if LL_RECORD_VIEWER_STATS
-		const BOOL success = TRUE;
-		stats_recorder.recordObjectUpdateEvent(regionp, local_id, update_type, success, objectp);
+		LLViewerStatsRecorder::instance()->recordObjectUpdateEvent(local_id, update_type, objectp);
 		#endif
 	}
 
 #if LL_RECORD_VIEWER_STATS
-	stats_recorder.closeObjectUpdateEvents(regionp);
+	LLViewerStatsRecorder::instance()->endObjectUpdateEvents();
 #endif
 
 	LLVOAvatar::cullAvatarsByPixelArea();
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index ca07e7c4cf1886ecb7979e04af7e84c954b7949a..da2373c39d83dc92128dd881e2ac0a03daea90c8 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -59,6 +59,7 @@
 #include "llurldispatcher.h"
 #include "llviewerobjectlist.h"
 #include "llviewerparceloverlay.h"
+#include "llviewerstatsrecorder.h"
 #include "llvlmanager.h"
 #include "llvlcomposition.h"
 #include "llvocache.h"
@@ -1074,7 +1075,7 @@ void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinary
 
 // Get data packer for this object, if we have cached data
 // AND the CRC matches. JC
-LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc)
+LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type)
 {
 	llassert(mCacheLoaded);
 
@@ -1087,17 +1088,20 @@ LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc)
 		{
 			// Record a hit
 			entry->recordHit();
+			cache_miss_type = CACHE_MISS_TYPE_NONE;
 			return entry->getDP(crc);
 		}
 		else
 		{
 			// llinfos << "CRC miss for " << local_id << llendl;
+			cache_miss_type = CACHE_MISS_TYPE_CRC;
 			mCacheMissCRC.put(local_id);
 		}
 	}
 	else
 	{
 		// llinfos << "Cache miss for " << local_id << llendl;
+		cache_miss_type = CACHE_MISS_TYPE_FULL;
 		mCacheMissFull.put(local_id);
 	}
 	return NULL;
@@ -1119,9 +1123,6 @@ void LLViewerRegion::requestCacheMisses()
 	S32 blocks = 0;
 	S32 i;
 
-	const U8 CACHE_MISS_TYPE_FULL = 0;
-	const U8 CACHE_MISS_TYPE_CRC  = 1;
-
 	// Send full cache miss updates.  For these, we KNOW we don't
 	// have a viewer object.
 	for (i = 0; i < full_count; i++)
@@ -1184,6 +1185,11 @@ void LLViewerRegion::requestCacheMisses()
 
 	mCacheDirty = TRUE ;
 	// llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl;
+	#if LL_RECORD_VIEWER_STATS
+	LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(this);
+	LLViewerStatsRecorder::instance()->recordRequestCacheMissesEvent(full_count + crc_count);
+	LLViewerStatsRecorder::instance()->endObjectUpdateEvents();
+	#endif
 }
 
 void LLViewerRegion::dumpCache()
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 8b71998f6054ddbaa7fccb8a1ee94ee317a5e093..7fac2020ee38a73bcefdfe440b9c8ce923725f70 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -274,9 +274,16 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 
 	void getInfo(LLSD& info);
 
+	typedef enum
+	{
+		CACHE_MISS_TYPE_FULL = 0,
+		CACHE_MISS_TYPE_CRC,
+		CACHE_MISS_TYPE_NONE
+	} eCacheMissType;
+
 	// handle a full update message
 	void cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp);
-	LLDataPacker *getDP(U32 local_id, U32 crc);
+	LLDataPacker *getDP(U32 local_id, U32 crc, U8 &cache_miss_type);
 	void requestCacheMisses();
 	void addCacheMissFull(const U32 local_id);
 
diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp
index 1b80a2bc1c53f96f82933e75bc5cd80d1a766304..27bbc17b3615858f81f5cd6c0798df5cc228594d 100644
--- a/indra/newview/llviewerstatsrecorder.cpp
+++ b/indra/newview/llviewerstatsrecorder.cpp
@@ -30,43 +30,73 @@
 #include "llviewerregion.h"
 #include "llviewerobject.h"
 
+
+// To do - something using region name or global position
+#if LL_WINDOWS
+	static const std::string STATS_FILE_NAME("C:\\ViewerObjectCacheStats.csv");
+#else
+	static const std::string STATS_FILE_NAME("/tmp/viewerstats.csv");
+#endif
+
+
+LLViewerStatsRecorder* LLViewerStatsRecorder::sInstance = NULL;
 LLViewerStatsRecorder::LLViewerStatsRecorder() :
 	mObjectCacheFile(NULL),
-	mTimer()
+	mTimer(),
+	mRegionp(NULL),
+	mStartTime(0.f),
+	mProcessingTime(0.f)
 {
-	mStartTime = LLTimer::getTotalTime();
+	if (NULL != sInstance)
+	{
+		llerrs << "Attempted to create multiple instances of LLViewerStatsRecorder!" << llendl;
+	}
+	sInstance = this;
+	clearStats();
 }
 
 LLViewerStatsRecorder::~LLViewerStatsRecorder()
 {
-	LLFile::close(mObjectCacheFile);
-	mObjectCacheFile = NULL;
+	if (mObjectCacheFile != NULL)
+	{
+		LLFile::close(mObjectCacheFile);
+		mObjectCacheFile = NULL;
+	}
 }
 
+// static
+void LLViewerStatsRecorder::initClass()
+{
+	sInstance = new LLViewerStatsRecorder();
+}
 
-void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp)
+// static
+void LLViewerStatsRecorder::cleanupClass()
 {
-	// To do - something using region name or global position
-#if LL_WINDOWS
-	std::string stats_file_name("C:\\ViewerObjectCacheStats.csv");
-#else
-	std::string stats_file_name("/tmp/viewerstats.csv");
-#endif
+	delete sInstance;
+	sInstance = NULL;
+}
 
+
+void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp)
+{
 	if (mObjectCacheFile == NULL)
 	{
-		mObjectCacheFile = LLFile::fopen(stats_file_name, "wb");
+		mStartTime = LLTimer::getTotalTime();
+		mObjectCacheFile = LLFile::fopen(STATS_FILE_NAME, "wb");
 		if (mObjectCacheFile)
 		{	// Write column headers
 			std::ostringstream data_msg;
 			data_msg << "EventTime, "
 				<< "ProcessingTime, "
 				<< "CacheHits, "
-				<< "CacheMisses, "
+				<< "CacheFullMisses, "
+				<< "CacheCrcMisses, "
 				<< "FullUpdates, "
 				<< "TerseUpdates, "
+				<< "CacheMissRequests, "
 				<< "CacheMissResponses, "
-				<< "TotalUpdates "
+				<< "UpdateFailures"
 				<< "\n";
 
 			fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile );
@@ -74,58 +104,83 @@ void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp)
 	}
 }
 
-
-void LLViewerStatsRecorder::initObjectUpdateEvents(LLViewerRegion *regionp)
+void LLViewerStatsRecorder::beginObjectUpdateEvents(LLViewerRegion *regionp)
 {
 	initStatsRecorder(regionp);
+	mRegionp = regionp;
+	mProcessingTime = LLTimer::getTotalTime();
+	clearStats();
+}
+
+void LLViewerStatsRecorder::clearStats()
+{
 	mObjectCacheHitCount = 0;
-	mObjectCacheMissCount = 0;
+	mObjectCacheMissFullCount = 0;
+	mObjectCacheMissCrcCount = 0;
 	mObjectFullUpdates = 0;
 	mObjectTerseUpdates = 0;
+	mObjectCacheMissRequests = 0;
 	mObjectCacheMissResponses = 0;
-	mProcessingTime = LLTimer::getTotalTime();
+	mObjectUpdateFailures = 0;
 }
 
 
-void LLViewerStatsRecorder::recordObjectUpdateEvent(LLViewerRegion *regionp, U32 local_id, const EObjectUpdateType update_type, BOOL success, LLViewerObject * objectp)
+void LLViewerStatsRecorder::recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type)
+{
+	mObjectUpdateFailures++;
+}
+
+void LLViewerStatsRecorder::recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type)
 {
-	if (!objectp)
+	if (LLViewerRegion::CACHE_MISS_TYPE_FULL == cache_miss_type)
 	{
-		// no object, must be a miss
-		mObjectCacheMissCount++;
+		mObjectCacheMissFullCount++;
 	}
 	else
-	{	
-		switch (update_type)
-		{
-		case OUT_FULL:
-			mObjectFullUpdates++;
-			break;
-		case OUT_TERSE_IMPROVED:
-			mObjectTerseUpdates++;
-			break;
-		case OUT_FULL_COMPRESSED:
-			mObjectCacheMissResponses++;
-			break;
-		case OUT_FULL_CACHED:
-		default:
-			mObjectCacheHitCount++;
-			break;
-		};
+	{
+		mObjectCacheMissCrcCount++;
 	}
 }
 
-void LLViewerStatsRecorder::closeObjectUpdateEvents(LLViewerRegion *regionp)
+void LLViewerStatsRecorder::recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp)
+{
+	switch (update_type)
+	{
+	case OUT_FULL:
+		mObjectFullUpdates++;
+		break;
+	case OUT_TERSE_IMPROVED:
+		mObjectTerseUpdates++;
+		break;
+	case OUT_FULL_COMPRESSED:
+		mObjectCacheMissResponses++;
+		break;
+	case OUT_FULL_CACHED:
+	default:
+		mObjectCacheHitCount++;
+		break;
+	};
+}
+
+void LLViewerStatsRecorder::recordRequestCacheMissesEvent(S32 count)
+{
+	mObjectCacheMissRequests += count;
+}
+
+void LLViewerStatsRecorder::endObjectUpdateEvents()
 {
 	llinfos << "ILX: " 
 		<< mObjectCacheHitCount << " hits, " 
-		<< mObjectCacheMissCount << " misses, "
+		<< mObjectCacheMissFullCount << " full misses, "
+		<< mObjectCacheMissCrcCount << " crc misses, "
 		<< mObjectFullUpdates << " full updates, "
 		<< mObjectTerseUpdates << " terse updates, "
-		<< mObjectCacheMissResponses << " cache miss responses"
+		<< mObjectCacheMissRequests << " cache miss requests, "
+		<< mObjectCacheMissResponses << " cache miss responses, "
+		<< mObjectUpdateFailures << " update failures"
 		<< llendl;
 
-	S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissResponses;;
+	S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCrcCount + mObjectCacheMissFullCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissRequests + mObjectCacheMissResponses + mObjectUpdateFailures;
 	if (mObjectCacheFile != NULL &&
 		total_objects > 0)
 	{
@@ -136,18 +191,19 @@ void LLViewerStatsRecorder::closeObjectUpdateEvents(LLViewerRegion *regionp)
 		data_msg << now32
 			<< ", " << processing32
 			<< ", " << mObjectCacheHitCount
-			<< ", " << mObjectCacheMissCount
+			<< ", " << mObjectCacheMissFullCount
+			<< ", " << mObjectCacheMissCrcCount
 			<< ", " << mObjectFullUpdates
 			<< ", " << mObjectTerseUpdates
+			<< ", " << mObjectCacheMissRequests
 			<< ", " << mObjectCacheMissResponses
-			<< ", " << total_objects
+			<< ", " << mObjectUpdateFailures
 			<< "\n";
 
 		fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile );
 	}
 
-	mObjectCacheHitCount = 0;
-	mObjectCacheMissCount = 0;
+	clearStats();
 }
 
 
diff --git a/indra/newview/llviewerstatsrecorder.h b/indra/newview/llviewerstatsrecorder.h
index 213d15f963184c6da379d7a87a20bfac779566d1..001b8d9bd647445bde39013822f1d6bbfc565bb8 100644
--- a/indra/newview/llviewerstatsrecorder.h
+++ b/indra/newview/llviewerstatsrecorder.h
@@ -39,6 +39,7 @@
 #include "llframetimer.h"
 #include "llviewerobject.h"
 
+class LLMutex;
 class LLViewerRegion;
 class LLViewerObject;
 
@@ -48,24 +49,41 @@ class LLViewerStatsRecorder
 	LLViewerStatsRecorder();
 	~LLViewerStatsRecorder();
 
+	static void initClass();
+	static void cleanupClass();
+	static LLViewerStatsRecorder* instance() {return sInstance; }
+
 	void initStatsRecorder(LLViewerRegion *regionp);
 
-	void initObjectUpdateEvents(LLViewerRegion *regionp);
-	void recordObjectUpdateEvent(LLViewerRegion *regionp, U32 local_id, const EObjectUpdateType update_type, BOOL success, LLViewerObject * objectp);
-	void closeObjectUpdateEvents(LLViewerRegion *regionp);
+	void beginObjectUpdateEvents(LLViewerRegion *regionp);
+	void recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type);
+	void recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type);
+	void recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp);
+	void recordRequestCacheMissesEvent(S32 count);
+	void endObjectUpdateEvents();
 
 private:
-	 LLFrameTimer	mTimer;
-	 F64			mStartTime;
-	 F64			mProcessingTime;
-
-	 LLFILE *		mObjectCacheFile;		// File to write data into
-	 S32			mObjectCacheHitCount;
-	 S32			mObjectCacheMissCount;
-	 S32			mObjectFullUpdates;
-	 S32			mObjectTerseUpdates;
-	 S32			mObjectCacheMissResponses;
+	static LLViewerStatsRecorder* sInstance;
+
+	LLFILE *	mObjectCacheFile;		// File to write data into
+	LLFrameTimer	mTimer;
+	LLViewerRegion*	mRegionp;
+	F64			mStartTime;
+	F64			mProcessingTime;
+
+	S32			mObjectCacheHitCount;
+	S32			mObjectCacheMissFullCount;
+	S32			mObjectCacheMissCrcCount;
+	S32			mObjectFullUpdates;
+	S32			mObjectTerseUpdates;
+	S32			mObjectCacheMissRequests;
+	S32			mObjectCacheMissResponses;
+	S32			mObjectUpdateFailures;
+
+
+	void	clearStats();
 };
 #endif	// LL_RECORD_VIEWER_STATS
 
 #endif // LLVIEWERSTATSRECORDER_H
+