[sldev] [VIEWER] Memory Usage / Animations

Nicholaz Beresford nicholaz at blueflash.cc
Tue Sep 4 05:32:00 PDT 2007


I applied little wizardry to my leak dump routines for visual studio 
yesterday, allowing me to get a heap snapshot while the program runs, 
spitting out a list of places in the source which have the memory 
allocated on the heap and sorting them by size.

I was going to a busy sim (Bad Girls) and found that (besides textures) 
the biggest memory spenders were llpointerskipmap, llpolymesh and 
keyframemotion (not entirely surprising in a place with 30-50 avatars 
dancing).

There's a construct called llkeyframemotioncache which I discovered 
previously, which caches keyframemotions, but never clears them.  I have 
a patch (see VWR-1769) which clears this cache on teleports, but 
unfortunately it's broken (or collides) by something that appeared in 
1.18.1, leading to crashes after teleport (I think it was planned to go 
into a recent release but was backed out because of the collision).

The Linden change also seems to produce new leaks (my own viewer runs 
normally practically with no mmory left over when it exits), even when 
not colliding with my VWR-1769, so somethig seems fishy there.

I also have a patch from Soft, refcounting LLMotion, which counter the 
effects, but I'm not sure if it fixes the collision and leaks entirely 
(doing test runs is a bit awkward, as they depend on what other avatars do).

*

Well, long story short: The llkeyframemotion cache needs some attention 
as it eats a lot of memory in busy sims.  30 minutes at Bad Girls or a 
similar sim can cost up to 50MB-100MB which never get freed until you 
log off with (literally) a million of small heap blocks.

If you have your own builds you may be interested in this:

Builds based on 1.16.0.8 can apply the 1769 from the JIRA (it's tried 
and trusted, runs on my viewer build for a long time now) to get the 
cache flushed on teleports.

If you have a build based on voice (1.18.1 or later) you need to apply 
(reverse) the attached llmotion patch if you want to run with VWR-1769.

And I'm attaching a newer version of VWR-1769 which expires entries from 
  the cache while staying on a sim.  That one is pretty new and more 
beta'ish, so it could use some eyeballs or comments.  On the other hand, 
  one of my users who is a manager at Bad Girls and stays there for 
hours, was running it with my voice viewer and very good results yesterday.


Nick

-------------- next part --------------

diff -urN -X srcdiff.ind --strip-trailing-cr linden/indra/llcharacter/llmotion.cpp sl1_18_2_0\linden-orig\indra/llcharacter/llmotion.cpp
--- linden/indra/llcharacter/llmotion.cpp	2007-07-11 15:19:44.000000000 +0200
+++ linden/indra/llcharacter/llmotion.cpp	2007-08-10 10:39:40.000000000 +0200
@@ -126,6 +126,11 @@
 	mDeactivateCallbackUserData = userdata;
 }
 
+BOOL LLMotion::isBlending()
+{
+	return mPose.getWeight() < 1.f;
+}
+
 //-----------------------------------------------------------------------------
 // activate()
 //-----------------------------------------------------------------------------
@@ -142,10 +147,16 @@
 void LLMotion::deactivate()
 {
 	mActive = FALSE;
+	mPose.setWeight(0.f);
 
 	if (mDeactivateCallback) (*mDeactivateCallback)(mDeactivateCallbackUserData);
 
 	onDeactivate();
 }
 
+BOOL LLMotion::canDeprecate()
+{
+	return TRUE;
+}
+
 // End
diff -urN -X srcdiff.ind --strip-trailing-cr linden/indra/llcharacter/llmotion.h sl1_18_2_0\linden-orig\indra/llcharacter/llmotion.h
--- linden/indra/llcharacter/llmotion.h	2007-07-11 15:19:44.000000000 +0200
+++ linden/indra/llcharacter/llmotion.h	2007-08-10 10:39:40.000000000 +0200
@@ -99,13 +99,14 @@
 
 	void setStopped(BOOL stopped) { mStopped = stopped; }
 
+	BOOL isBlending();
+
 	void activate();
 
 	void deactivate();
 
 	BOOL isActive() { return mActive; }
 
-
 public:
 	//-------------------------------------------------------------------------
 	// animation callbacks to be implemented by subclasses
@@ -145,6 +146,11 @@
 	// called when a motion is deactivated
 	virtual void onDeactivate() = 0;
 
+	// can we crossfade this motion with a new instance when restarted?
+	// should ultimately always be TRUE, but lack of emote blending, etc
+	// requires this
+	virtual BOOL canDeprecate();
+
 	// optional callback routine called when animation deactivated.
 	void	setDeactivateCallback( void (*cb)(void *), void* userdata );
 
diff -urN -X srcdiff.ind --strip-trailing-cr linden/indra/llcharacter/llmotioncontroller.cpp sl1_18_2_0\linden-orig\indra/llcharacter/llmotioncontroller.cpp
--- linden/indra/llcharacter/llmotioncontroller.cpp	2007-07-11 15:19:44.000000000 +0200
+++ linden/indra/llcharacter/llmotioncontroller.cpp	2007-08-10 10:39:40.000000000 +0200
@@ -194,34 +194,44 @@
 //-----------------------------------------------------------------------------
 void LLMotionController::addLoadedMotion(LLMotion* motionp)
 {
+	std::set<LLUUID> motions_to_kill;
+
+	// gather all inactive, loaded motions
 	if (mLoadedMotions.size() > MAX_MOTION_INSTANCES)
 	{
 		// too many motions active this frame, kill all blenders
 		mPoseBlender.clearBlenders();
 
-		for (U32 i = 0; i < mLoadedMotions.size(); i++)
+		for (motion_list_t::iterator loaded_motion_it = mLoadedMotions.begin(); 
+			loaded_motion_it != mLoadedMotions.end(); 
+			++loaded_motion_it)
 		{
-			LLMotion* cur_motionp = mLoadedMotions.front();
-			mLoadedMotions.pop_front();
+			LLMotion* cur_motionp = *loaded_motion_it;
 			
 			// motion isn't playing, delete it
 			if (!isMotionActive(cur_motionp))
 			{
-				mCharacter->requestStopMotion(cur_motionp);
-				mAllMotions.erase(cur_motionp->getID());
-				delete cur_motionp;
-				if (mLoadedMotions.size() <= MAX_MOTION_INSTANCES)
-				{
-					break;
-				}
-			}
-			else
-			{
-				// put active motion on back
-				mLoadedMotions.push_back(cur_motionp);
+				motions_to_kill.insert(cur_motionp->getID());
 			}
 		}
 	}
+
+	// clean up all inactive, loaded motions
+	for (std::set<LLUUID>::iterator motion_it = motions_to_kill.begin();
+		motion_it != motions_to_kill.end();
+		++motion_it)
+	{
+		// look up the motion again by ID to get canonical instance
+		// and kill it only if that one is inactive
+		LLUUID motion_id = *motion_it;
+		LLMotion* motionp = findMotion(motion_id);
+		if (motionp && !isMotionActive(motionp))
+		{
+			removeMotion(motion_id);
+		}
+	}
+
+	// add new motion to loaded list
 	mLoadedMotions.push_back(motionp);
 }
 
@@ -280,14 +290,24 @@
 void LLMotionController::removeMotion( const LLUUID& id)
 {
 	LLMotion* motionp = findMotion(id);
+	
+	removeMotionInstance(motionp);
+
+	mAllMotions.erase(id);
+}
+
+// removes instance of a motion from all runtime structures, but does
+// not erase entry by ID, as this could be a duplicate instance
+// use removeMotion(id) to remove all references to a given motion by id.
+void LLMotionController::removeMotionInstance(LLMotion* motionp)
+{
 	if (motionp)
 	{
-		stopMotionLocally(id, TRUE);
+		stopMotionInstance(motionp, TRUE);
 
 		mLoadingMotions.erase(motionp);
 		mLoadedMotions.remove(motionp);
 		mActiveMotions.remove(motionp);
-		mAllMotions.erase(id);
 		delete motionp;
 	}
 }
@@ -348,28 +368,39 @@
 //-----------------------------------------------------------------------------
 BOOL LLMotionController::startMotion(const LLUUID &id, F32 start_offset)
 {
-	// look for motion in our list of created motions
-	LLMotion *motion = createMotion(id);
+	// do we have an instance of this motion for this character?
+	LLMotion *motion = findMotion(id);
+
+	// motion that is stopping will be allowed to stop but
+	// replaced by a new instance of that motion
+	if (motion
+		&& motion->canDeprecate()
+		&& motion->getFadeWeight() > 0.01f // not LOD-ed out
+		&& (motion->isBlending() || motion->getStopTime() != 0.f))
+	{
+		deprecateMotionInstance(motion);
+		// force creation of new instance
+		motion = NULL;
+	}
+
+	// create new motion instance
+	if (!motion)
+	{
+		motion = createMotion(id);
+	}
 
 	if (!motion)
 	{
 		return FALSE;
 	}
-	//if the motion is already active, then we're done
-	else if (isMotionActive(motion)) // motion is playing and...
+	//if the motion is already active and allows deprecation, then let it keep playing
+	else if (motion->canDeprecate() && isMotionActive(motion))
 	{	
-		if (motion->isStopped()) // motion has been stopped
-		{
-			deactivateMotion(motion, false);
-		}
-		else if (mTime < motion->mSendStopTimestamp)	// motion is still active
-		{
-			return TRUE;
-		}
+		return TRUE;
 	}
 
 //	llinfos << "Starting motion " << name << llendl;
-	return activateMotion(motion, mTime - start_offset);
+	return activateMotionInstance(motion, mTime - start_offset);
 }
 
 
@@ -380,6 +411,12 @@
 {
 	// if already inactive, return false
 	LLMotion *motion = findMotion(id);
+
+	return stopMotionInstance(motion, stop_immediate);
+}
+
+BOOL LLMotionController::stopMotionInstance(LLMotion* motion, BOOL stop_immediate)
+{
 	if (!motion)
 	{
 		return FALSE;
@@ -396,7 +433,7 @@
 
 		if (stop_immediate)
 		{
-			deactivateMotion(motion, false);
+			deactivateMotionInstance(motion);
 		}
 		return TRUE;
 	}
@@ -492,7 +529,7 @@
 		{
 			if (motionp->isStopped() && mTime > motionp->getStopTime() + motionp->getEaseOutDuration())
 			{
-				deactivateMotion(motionp, false);
+				deactivateMotionInstance(motionp);
 			}
 			else if (motionp->isStopped() && mTime > motionp->getStopTime())
 			{
@@ -510,7 +547,7 @@
 				if (mLastTime <= motionp->mSendStopTimestamp)
 				{
 					mCharacter->requestStopMotion( motionp );
-					stopMotionLocally(motionp->getID(), FALSE);
+					stopMotionInstance(motionp, FALSE);
 				}
 			}
 			else if (mTime >= motionp->mActivationTimestamp)
@@ -538,7 +575,7 @@
 				if (mLastTime <= motionp->mSendStopTimestamp)
 				{
 					mCharacter->requestStopMotion( motionp );
-					stopMotionLocally(motionp->getID(), FALSE);
+					stopMotionInstance(motionp, FALSE);
 				}
 			}
 
@@ -546,7 +583,8 @@
 			{
 				if (motionp->isStopped() && mTime > motionp->getStopTime() + motionp->getEaseOutDuration())
 				{
-					deactivateMotion(motionp, true);
+					posep->setWeight(0.f);
+					deactivateMotionInstance(motionp);
 				}
 				continue;
 			}
@@ -572,7 +610,8 @@
 			}
 			else
 			{
-				deactivateMotion(motionp, true);
+				posep->setWeight(0.f);
+				deactivateMotionInstance(motionp);
 				continue;
 			}
 		}
@@ -617,7 +656,7 @@
 				if (mLastTime <= motionp->mSendStopTimestamp)
 				{
 					mCharacter->requestStopMotion( motionp );
-					stopMotionLocally(motionp->getID(), FALSE);
+					stopMotionInstance(motionp, FALSE);
 				}
 			}
 
@@ -661,7 +700,7 @@
 				// propagate this to the network
 				// as not all viewers are guaranteed to have access to the same logic
 				mCharacter->requestStopMotion( motionp );
-				stopMotionLocally(motionp->getID(), FALSE);
+				stopMotionInstance(motionp, FALSE);
 			}
 
 		}
@@ -733,7 +772,7 @@
 			// this motion should be playing
 			if (!motionp->isStopped())
 			{
-				activateMotion(motionp, mTime);
+				activateMotionInstance(motionp, mTime);
 			}
 		}
 		else if (status == LLMotion::STATUS_FAILURE)
@@ -741,6 +780,7 @@
 			llinfos << "Motion " << motionp->getID() << " init failed." << llendl;
 			sRegistry.markBad(motionp->getID());
 			mLoadingMotions.erase(curiter);
+
 			mAllMotions.erase(motionp->getID());
 			delete motionp;
 		}
@@ -773,9 +813,9 @@
 
 
 //-----------------------------------------------------------------------------
-// activateMotion()
+// activateMotionInstance()
 //-----------------------------------------------------------------------------
-BOOL LLMotionController::activateMotion(LLMotion *motion, F32 time)
+BOOL LLMotionController::activateMotionInstance(LLMotion *motion, F32 time)
 {
 	if (mLoadingMotions.find(motion) != mLoadingMotions.end())
 	{
@@ -818,23 +858,38 @@
 }
 
 //-----------------------------------------------------------------------------
-// deactivateMotion()
+// deactivateMotionInstance()
 //-----------------------------------------------------------------------------
-BOOL LLMotionController::deactivateMotion(LLMotion *motion, bool remove_weight)
+BOOL LLMotionController::deactivateMotionInstance(LLMotion *motion)
 {
-	if( remove_weight )
+	motion->deactivate();
+
+	motion_set_t::iterator found_it = mDeprecatedMotions.find(motion);
+	if (found_it != mDeprecatedMotions.end())
 	{
-		// immediately remove pose weighting instead of letting it time out
-		LLPose *posep = motion->getPose();
-		posep->setWeight(0.f);
+		// deprecated motions need to be completely excised
+		removeMotionInstance(motion);	
+		mDeprecatedMotions.erase(found_it);
+	}
+	else
+	{
+		// for motions that we are keeping, simply remove from active queue
+		mActiveMotions.remove(motion);
 	}
-	
-	motion->deactivate();
-	mActiveMotions.remove(motion);
 
 	return TRUE;
 }
 
+void LLMotionController::deprecateMotionInstance(LLMotion* motion)
+{
+	mDeprecatedMotions.insert(motion);
+
+	//fade out deprecated motion
+	stopMotionInstance(motion, FALSE);
+	//no longer canonical
+	mAllMotions.erase(motion->getID());
+}
+
 //-----------------------------------------------------------------------------
 // isMotionActive()
 //-----------------------------------------------------------------------------
@@ -857,7 +912,7 @@
 //-----------------------------------------------------------------------------
 LLMotion *LLMotionController::findMotion(const LLUUID& id)
 {
-	return mAllMotions[id];
+	return get_if_there<LLUUID, LLMotion*>(mAllMotions, id, NULL);
 }
 
 //-----------------------------------------------------------------------------
diff -urN -X srcdiff.ind --strip-trailing-cr linden/indra/llcharacter/llmotioncontroller.h sl1_18_2_0\linden-orig\indra/llcharacter/llmotioncontroller.h
--- linden/indra/llcharacter/llmotioncontroller.h	2007-07-11 15:19:44.000000000 +0200
+++ linden/indra/llcharacter/llmotioncontroller.h	2007-08-10 10:39:40.000000000 +0200
@@ -179,16 +179,21 @@
 	LLMotion *findMotion( const LLUUID& id );
 
 protected:
+	// internal operations act on motion instances directly
+	// as there can be duplicate motions per id during blending overlap
 	void deleteAllMotions();
 	void addLoadedMotion(LLMotion *motion);
-	BOOL activateMotion(LLMotion *motion, F32 time);
-	BOOL deactivateMotion(LLMotion *motion, bool remove_weight);
+	BOOL activateMotionInstance(LLMotion *motion, F32 time);
+	BOOL deactivateMotionInstance(LLMotion *motion);
+	void deprecateMotionInstance(LLMotion* motion);
+	BOOL stopMotionInstance(LLMotion *motion, BOOL stop_imemdiate);
+	void removeMotionInstance(LLMotion* motion);
 	void updateRegularMotions();
 	void updateAdditiveMotions();
 	void resetJointSignatures();
 	void updateMotionsByType(LLMotion::LLMotionBlendType motion_type);
-protected:
 
+protected:
 	F32					mTimeFactor;
 	static LLMotionRegistry	sRegistry;
 	LLPoseBlender		mPoseBlender;
@@ -203,11 +208,13 @@
 //	Once an animations is loaded, it will be initialized and put on the mLoadedMotions deque.
 //	Any animation that is currently playing also sits in the mActiveMotions list.
 
-	std::map<LLUUID, LLMotion*>	mAllMotions;
+	typedef std::map<LLUUID, LLMotion*> motion_map_t;
+	motion_map_t	mAllMotions;
 
 	motion_set_t		mLoadingMotions;
 	motion_list_t		mLoadedMotions;
 	motion_list_t		mActiveMotions;
+	motion_set_t		mDeprecatedMotions;
 	
 	LLFrameTimer		mTimer;
 	F32					mTime;
diff -urN -X srcdiff.ind --strip-trailing-cr linden/indra/llcharacter/llpose.cpp sl1_18_2_0\linden-orig\indra/llcharacter/llpose.cpp
--- linden/indra/llcharacter/llpose.cpp	2007-07-11 15:19:44.000000000 +0200
+++ linden/indra/llcharacter/llpose.cpp	2007-08-10 10:39:40.000000000 +0200
@@ -275,9 +275,9 @@
 		joint_state_index < JSB_NUM_JOINT_STATES && mJointStates[joint_state_index] != NULL;
 		joint_state_index++)
 	{
-		U32 current_usage = mJointStates[joint_state_index]->getUsage();
-		F32 current_weight = mJointStates[joint_state_index]->getWeight();
 		LLJointState* jsp = mJointStates[joint_state_index];
+		U32 current_usage = jsp->getUsage();
+		F32 current_weight = jsp->getWeight();
 
 		if (current_weight == 0.f)
 		{
@@ -292,17 +292,14 @@
 
 				// add in pos for this jointstate modulated by weight
 				added_pos += jsp->getPosition() * (new_weight_sum - sum_weights[POS_WEIGHT]);
-				//sum_weights[POS_WEIGHT] = new_weight_sum;
 			}
 
-			// now do scale
 			if(current_usage & LLJointState::SCALE)
 			{
 				F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[SCALE_WEIGHT]);
 
 				// add in scale for this jointstate modulated by weight
 				added_scale += jsp->getScale() * (new_weight_sum - sum_weights[SCALE_WEIGHT]);
-				//sum_weights[SCALE_WEIGHT] = new_weight_sum;
 			}
 
 			if (current_usage & LLJointState::ROT)
@@ -311,7 +308,6 @@
 
 				// add in rotation for this jointstate modulated by weight
 				added_rot = nlerp((new_weight_sum - sum_weights[ROT_WEIGHT]), added_rot, jsp->getRotation()) * added_rot;
-				//sum_weights[ROT_WEIGHT] = new_weight_sum;
 			}
 		}
 		else
@@ -326,13 +322,13 @@
 					F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[POS_WEIGHT]);
 
 					// blend positions from both
-					blended_pos = lerp(mJointStates[joint_state_index]->getPosition(), blended_pos, sum_weights[POS_WEIGHT] / new_weight_sum);
+					blended_pos = lerp(jsp->getPosition(), blended_pos, sum_weights[POS_WEIGHT] / new_weight_sum);
 					sum_weights[POS_WEIGHT] = new_weight_sum;
 				} 
 				else
 				{
 					// copy position from current
-					blended_pos = mJointStates[joint_state_index]->getPosition();
+					blended_pos = jsp->getPosition();
 					sum_weights[POS_WEIGHT] = current_weight;
 				}
 			}
@@ -345,13 +341,13 @@
 					F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[SCALE_WEIGHT]);
 
 					// blend scales from both
-					blended_scale = lerp(mJointStates[joint_state_index]->getScale(), blended_scale, sum_weights[SCALE_WEIGHT] / new_weight_sum);
+					blended_scale = lerp(jsp->getScale(), blended_scale, sum_weights[SCALE_WEIGHT] / new_weight_sum);
 					sum_weights[SCALE_WEIGHT] = new_weight_sum;
 				} 
 				else
 				{
 					// copy scale from current
-					blended_scale = mJointStates[joint_state_index]->getScale();
+					blended_scale = jsp->getScale();
 					sum_weights[SCALE_WEIGHT] = current_weight;
 				}
 			}
@@ -364,13 +360,13 @@
 					F32 new_weight_sum = llmin(1.f, current_weight + sum_weights[ROT_WEIGHT]);
 
 					// blend rotations from both
-					blended_rot = nlerp(sum_weights[ROT_WEIGHT] / new_weight_sum, mJointStates[joint_state_index]->getRotation(), blended_rot);
+					blended_rot = nlerp(sum_weights[ROT_WEIGHT] / new_weight_sum, jsp->getRotation(), blended_rot);
 					sum_weights[ROT_WEIGHT] = new_weight_sum;
 				} 
 				else
 				{
 					// copy rotation from current
-					blended_rot = mJointStates[joint_state_index]->getRotation();
+					blended_rot = jsp->getRotation();
 					sum_weights[ROT_WEIGHT] = current_weight;
 				}
 			}
diff -urN -X srcdiff.ind --strip-trailing-cr linden/indra/llcharacter/llpose.h sl1_18_2_0\linden-orig\indra/llcharacter/llpose.h
--- linden/indra/llcharacter/llpose.h	2007-07-11 15:19:44.000000000 +0200
+++ linden/indra/llcharacter/llpose.h	2007-08-10 10:39:40.000000000 +0200
@@ -81,7 +81,7 @@
 	S32 getNumJointStates() const;
 };
 
-const S32 JSB_NUM_JOINT_STATES = 4;
+const S32 JSB_NUM_JOINT_STATES = 6;
 
 class LLJointStateBlender
 {
-------------- next part --------------
--- linden-orig/indra/llcharacter/llkeyframemotion.h	2007-08-29 14:13:04.000000000 +0200
+++ linden/indra/llcharacter/llkeyframemotion.h	2007-09-04 00:58:44.656250000 +0200
@@ -40,6 +40,7 @@
 #include "llhandmotion.h"
 #include "lljointstate.h"
 #include "llmotion.h"
+#include "llmemory.h"
 #include "llptrskipmap.h"
 #include "llquaternion.h"
 #include "v3dmath.h"
@@ -151,7 +152,7 @@
 	BOOL	serialize(LLDataPacker& dp) const;
 	BOOL	deserialize(LLDataPacker& dp);
 	void	writeCAL3D(apr_file_t* fp);
-	BOOL	isLoaded() { return mJointMotionList != NULL; }
+	BOOL	isLoaded() { return mJointMotionList.notNull(); }
 
 
 	// setters for modifying a keyframe animation
@@ -391,10 +392,14 @@
 	//-------------------------------------------------------------------------
 	// JointMotionList
 	//-------------------------------------------------------------------------
-	class JointMotionList
+	class JointMotionList : public LLRefCount
 	{
+	protected:
+		~JointMotionList();
+
 	public:
 		U32						mNumJointMotions;
+		U64						mTimeLastCacheHit;
 		JointMotion*			mJointMotionArray;
 		F32						mDuration;
 		BOOL					mLoop;
@@ -410,7 +415,6 @@
 		LLBBoxLocal				mPelvisBBox;
 	public:
 		JointMotionList();
-		~JointMotionList();
 		U32 dumpDiagInfo();
 	};
 
@@ -421,7 +425,7 @@
 	//-------------------------------------------------------------------------
 	// Member Data
 	//-------------------------------------------------------------------------
-	JointMotionList*				mJointMotionList;
+	LLPointer<JointMotionList>		mJointMotionList;
 	LLJointState*					mJointStates;
 	LLJoint*						mPelvisp;
 	LLCharacter*					mCharacter;
@@ -441,13 +445,16 @@
 	LLKeyframeDataCache(){};
 	~LLKeyframeDataCache();
 
-	typedef std::map<LLUUID, class LLKeyframeMotion::JointMotionList*> keyframe_data_map_t; 
+	typedef std::map<LLUUID, LLPointer<class LLKeyframeMotion::JointMotionList> > keyframe_data_map_t; 
 	static keyframe_data_map_t sKeyframeDataMap;
 
+	static U64 sLastCacheCleanup;
+
 	static void addKeyframeData(const LLUUID& id, LLKeyframeMotion::JointMotionList*);
 	static LLKeyframeMotion::JointMotionList* getKeyframeData(const LLUUID& id);
 
 	static void removeKeyframeData(const LLUUID& id);
+	static void cleanupCache(int maxage = 0);
 
 	//print out diagnostic info
 	static void dumpDiagInfo();
--- linden-orig/indra/llcharacter/llkeyframemotion.cpp	2007-08-29 14:13:04.000000000 +0200
+++ linden/indra/llcharacter/llkeyframemotion.cpp	2007-09-04 01:43:02.343750000 +0200
@@ -42,6 +42,7 @@
 #include "llkeyframemotion.h"
 #include "llquantize.h"
 #include "llvfile.h"
+#include "lltimer.h"
 #include "m3math.h"
 #include "message.h"
 
@@ -50,6 +51,8 @@
 //-----------------------------------------------------------------------------
 LLVFS*				LLKeyframeMotion::sVFS = NULL;
 LLKeyframeDataCache::keyframe_data_map_t	LLKeyframeDataCache::sKeyframeDataMap;
+U64											LLKeyframeDataCache::sLastCacheCleanup;
+
 
 //-----------------------------------------------------------------------------
 // Globals
@@ -69,6 +72,7 @@
 //-----------------------------------------------------------------------------
 LLKeyframeMotion::JointMotionList::JointMotionList()
 	: mNumJointMotions(0),
+	  mTimeLastCacheHit(0),
 	  mJointMotionArray(NULL)
 {
 }
@@ -1858,8 +1862,7 @@
 //-----------------------------------------------------------------------------
 void LLKeyframeMotion::flushKeyframeCache()
 {
-	// TODO: Make this safe to do
-// 	LLKeyframeDataCache::clear();
+	LLKeyframeDataCache::clear();
 }
 
 //-----------------------------------------------------------------------------
@@ -2102,6 +2105,7 @@
 //--------------------------------------------------------------------
 void LLKeyframeDataCache::addKeyframeData(const LLUUID& id, LLKeyframeMotion::JointMotionList* joint_motion_listp)
 {
+	joint_motion_listp->mTimeLastCacheHit = (U64)LLTimer::getTotalSeconds();
 	sKeyframeDataMap[id] = joint_motion_listp;
 }
 
@@ -2113,7 +2117,6 @@
 	keyframe_data_map_t::iterator found_data = sKeyframeDataMap.find(id);
 	if (found_data != sKeyframeDataMap.end())
 	{
-		delete found_data->second;
 		sKeyframeDataMap.erase(found_data);
 	}
 }
@@ -2128,6 +2131,11 @@
 	{
 		return NULL;
 	}
+
+	found_data->second->mTimeLastCacheHit = (U64)LLTimer::getTotalSeconds();
+
+	cleanupCache(); 
+
 	return found_data->second;
 }
 
@@ -2139,12 +2147,72 @@
 	clear();
 }
 
+
+//-----------------------------------------------------------------------------
+// flush older entries
+//-----------------------------------------------------------------------------
+void LLKeyframeDataCache::cleanupCache(S32 maxage)
+{
+	U64 now = (U64)LLTimer::getTotalSeconds();
+
+	if (0 == sLastCacheCleanup) 
+	{
+		sLastCacheCleanup = now;
+		return;
+	}
+
+	if (now-sLastCacheCleanup > 60 || maxage != 0) 
+	{
+		S32 count = sKeyframeDataMap.size();
+		S32 deleted = 0;
+
+		if (0 == maxage) {
+			// lifetime of 30 min - 5 min depending on #of entries (0 - 250+)
+			maxage = 60 * (S32)(30.f - llclamp((F32)count/10, 0.f, 25.f));
+		}
+
+		llinfos << "before: " << count << " entries, flushing with maxage " << maxage << llendl;
+
+		for (keyframe_data_map_t::iterator map_it = sKeyframeDataMap.begin();
+			map_it != sKeyframeDataMap.end(); 
+			)
+		{
+			LLPointer<LLKeyframeMotion::JointMotionList> motion_list_p = map_it->second;
+
+			U64 age = now - motion_list_p->mTimeLastCacheHit;
+			if (age > maxage) 
+			{
+				llinfos << " erasing JointMotionList " 
+						<< map_it->first 
+						<< " from sKeyframeDataMap" 
+						<< llendl;
+				keyframe_data_map_t::iterator tmp_it = map_it;
+				++map_it;
+				sKeyframeDataMap.erase(tmp_it);
+				deleted++;
+			}
+			else
+			{
+				++map_it;
+			}
+		}
+
+		if (deleted>0) 
+		{
+			llinfos << "after: " << sKeyframeDataMap.size() << " (-" << deleted << ") entries " << llendl;
+		}
+
+		sLastCacheCleanup = now;
+	}
+
+}
+
 //-----------------------------------------------------------------------------
 // clear()
 //-----------------------------------------------------------------------------
 void LLKeyframeDataCache::clear()
 {
-	for_each(sKeyframeDataMap.begin(), sKeyframeDataMap.end(), DeletePairedPointer());
+	// dumpDiagInfo();
 	sKeyframeDataMap.clear();
 }
 
--- linden-orig/indra/newview/llviewermessage.cpp	2007-08-29 14:13:08.000000000 +0200
+++ linden/indra/newview/llviewermessage.cpp	2007-09-04 02:05:20.234375000 +0200
@@ -93,6 +93,7 @@
 #include "llimpanel.h"
 #include "llinventorymodel.h"
 #include "llinventoryview.h"
+#include "llkeyframemotion.h" 
 #include "llmenugl.h"
 #include "llmutelist.h"
 #include "llnetmap.h"
@@ -1189,9 +1190,17 @@
 		return;
 	}
 
+	// NICHOLAZ: KLUDGE to unclutter the server side message 
+	LLString::format_map_t repl;
+	LLString msg = info->mDesc;
+	repl[" ( http://slurl.com/secondlife/"] = "(";
+	repl[" )"] = ")";
+	LLString::format(msg, repl);
+
 	LLString::format_map_t args;
-	args["[OBJECTNAME]"] = info->mDesc;
+	args["[OBJECTNAME]"] = msg;
 	args["[OBJECTTYPE]"] = LLAssetType::lookupHumanReadable(info->mType);
+	// ~NICHOLAZ
 
 	// Name cache callbacks don't store userdata, so can't save
 	// off the LLOfferInfo.  Argh.  JC
@@ -2714,6 +2723,8 @@
 
 	llinfos << "Changing home region to " << x << ":" << y << llendl;
 
+	LLKeyframeDataCache::cleanupCache(60);
+
 	// set our upstream host the new simulator and shuffle things as
 	// appropriate.
 	LLVector3 shift_vector = regionp->getPosRegionFromGlobal(


More information about the SLDev mailing list