Speed up of LLViewerObjectList::cleanDeadObjects with a factor of 10000.
Also a little review of Dead objects in general. The old code was calling 'erase' on a large vector, once for every dead object (which are a lot, especially if you exit or teleport), causing the whole (large) vector to be copied every time. The new code only calls erase once per call (about once a second at most now), erasing 20 to 100 objects at the END of the vector. This is INCREDIBLY faster.
This commit is contained in:
@@ -376,6 +376,12 @@ std::vector<affected_object> LocalBitmap::getUsingObjects(bool seek_by_type, boo
|
||||
iter != gObjectList.mObjects.end(); iter++ )
|
||||
{
|
||||
LLViewerObject* obj = *iter;
|
||||
|
||||
if (obj->isDead())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
affected_object shell;
|
||||
shell.object = obj;
|
||||
shell.local_sculptmap = false;
|
||||
|
||||
@@ -103,6 +103,7 @@ LLViewerObjectList::LLViewerObjectList()
|
||||
mCurLazyUpdateIndex = 0;
|
||||
mCurBin = 0;
|
||||
mNumDeadObjects = 0;
|
||||
mMinNumDeadObjects = 20;
|
||||
mNumOrphans = 0;
|
||||
mNumNewObjects = 0;
|
||||
mWasPaused = FALSE;
|
||||
@@ -586,23 +587,27 @@ void LLViewerObjectList::dirtyAllObjectInventory()
|
||||
void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
|
||||
{
|
||||
S32 i;
|
||||
S32 num_objects = 0;
|
||||
S32 const objects_size = mObjects.size();
|
||||
LLViewerObject *objectp;
|
||||
|
||||
S32 num_updates, max_value;
|
||||
// The list can have shrinked since mCurLazyUpdateIndex was last updated.
|
||||
if (mCurLazyUpdateIndex >= objects_size)
|
||||
{
|
||||
mCurLazyUpdateIndex = 0;
|
||||
}
|
||||
if (NUM_BINS - 1 == mCurBin)
|
||||
{
|
||||
num_updates = (S32) mObjects.size() - mCurLazyUpdateIndex;
|
||||
max_value = (S32) mObjects.size();
|
||||
num_updates = objects_size - mCurLazyUpdateIndex;
|
||||
max_value = objects_size;
|
||||
gTextureList.setUpdateStats(TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
num_updates = ((S32) mObjects.size() / NUM_BINS) + 1;
|
||||
max_value = llmin((S32) mObjects.size(), mCurLazyUpdateIndex + num_updates);
|
||||
num_updates = (objects_size / NUM_BINS) + 1;
|
||||
max_value = llmin(objects_size, mCurLazyUpdateIndex + num_updates);
|
||||
}
|
||||
|
||||
|
||||
if (!gNoRender)
|
||||
{
|
||||
// Slam priorities for textures that we care about (hovered, selected, and focused)
|
||||
@@ -639,8 +644,6 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
|
||||
objectp = mObjects[i];
|
||||
if (!objectp->isDead())
|
||||
{
|
||||
num_objects++;
|
||||
|
||||
// Update distance & gpw
|
||||
objectp->setPixelAreaAndAngle(agent); // Also sets the approx. pixel area
|
||||
objectp->updateTextures(); // Update the image levels of textures for this object.
|
||||
@@ -648,7 +651,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
|
||||
}
|
||||
|
||||
mCurLazyUpdateIndex = max_value;
|
||||
if (mCurLazyUpdateIndex == mObjects.size())
|
||||
if (mCurLazyUpdateIndex == objects_size)
|
||||
{
|
||||
mCurLazyUpdateIndex = 0;
|
||||
}
|
||||
@@ -809,7 +812,7 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
|
||||
}
|
||||
*/
|
||||
|
||||
mNumObjectsStat.addValue((S32) mObjects.size());
|
||||
mNumObjectsStat.addValue((S32) mObjects.size() - mNumDeadObjects);
|
||||
mNumActiveObjectsStat.addValue(num_active_objects);
|
||||
mNumSizeCulledStat.addValue(mNumSizeCulled);
|
||||
mNumVisCulledStat.addValue(mNumVisCulled);
|
||||
@@ -819,7 +822,12 @@ void LLViewerObjectList::clearDebugText()
|
||||
{
|
||||
for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter)
|
||||
{
|
||||
(*iter)->setDebugText("");
|
||||
LLViewerObject *objectp = *iter;
|
||||
if (objectp->isDead())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
objectp->setDebugText("");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -975,41 +983,65 @@ void LLViewerObjectList::killAllObjects()
|
||||
|
||||
void LLViewerObjectList::cleanDeadObjects(BOOL use_timer)
|
||||
{
|
||||
if (!mNumDeadObjects)
|
||||
if (use_timer && mNumDeadObjects < mMinNumDeadObjects)
|
||||
{
|
||||
// No dead objects, don't need to scan object list.
|
||||
// Not enough dead objects, don't scan the whole object list until there are a few.
|
||||
// However, the longer it takes to reach this quota, the less demanding we are,
|
||||
// so decrease the lower limit but never demand less than 20.
|
||||
mMinNumDeadObjects = llmax(20, mMinNumDeadObjects - 1);
|
||||
return;
|
||||
}
|
||||
llwarns << "ENTERING LLViewerObjectList::cleanDeadObjects" << llendl;
|
||||
// If we got this many now, we might as well demand it for the next calls too (they
|
||||
// tend to come in batches). However, never demand more than 100.
|
||||
mMinNumDeadObjects = llmin(100, mNumDeadObjects);
|
||||
|
||||
// Scan for all of the dead objects and remove any "global" references to them.
|
||||
|
||||
// We first move all dead objects to the end of the std::vector (the swap
|
||||
// is VERY cheap) and only then call erase once: calling erase on a vector
|
||||
// is very expensive!
|
||||
|
||||
vobj_list_t::iterator iter = mObjects.begin(); // Runs over all objects.
|
||||
vobj_list_t::iterator const end = mObjects.end();
|
||||
vobj_list_t::iterator last = end; // Points to the last object that is not dead.
|
||||
S32 num_removed = 0;
|
||||
LLViewerObject *objectp;
|
||||
for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); )
|
||||
{
|
||||
// Scan for all of the dead objects and remove any "global" references to them.
|
||||
objectp = *iter;
|
||||
if (objectp->isDead())
|
||||
{
|
||||
iter = mObjects.erase(iter);
|
||||
num_removed++;
|
||||
|
||||
if (num_removed == mNumDeadObjects)
|
||||
{
|
||||
// We've cleaned up all of the dead objects.
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
// Find the first Dead object.
|
||||
while (iter != last && !(*iter)->isDead())
|
||||
++iter;
|
||||
|
||||
// While iter did not bumb into last, continue the search.
|
||||
while (iter != last)
|
||||
{
|
||||
// Find the next not Dead object from the end.
|
||||
do {
|
||||
--last;
|
||||
++num_removed;
|
||||
} while (last != iter && (*last)->isDead());
|
||||
if (iter == last)
|
||||
{
|
||||
++iter;
|
||||
// There no more Dead objects left before last.
|
||||
break;
|
||||
}
|
||||
// Swap both object Pointers.
|
||||
vobj_list_t::value_type::swap(*iter, *last);
|
||||
if (num_removed == mNumDeadObjects)
|
||||
{
|
||||
// There aren't any more dead objects.
|
||||
break;
|
||||
}
|
||||
// Find the next Dead object at the beginning.
|
||||
do {
|
||||
++iter;
|
||||
} while (iter != last && !(*iter)->isDead());
|
||||
}
|
||||
llassert(end - last == num_removed);
|
||||
mObjects.erase(last, end);
|
||||
|
||||
// We've cleaned the global object list, now let's do some paranoia testing on objects
|
||||
// before blowing away the dead list.
|
||||
mDeadObjects.clear();
|
||||
mNumDeadObjects = 0;
|
||||
llwarns << "LEAVING LLViewerObjectList::cleanDeadObjects" << llendl;
|
||||
}
|
||||
|
||||
void LLViewerObjectList::updateActive(LLViewerObject *objectp)
|
||||
|
||||
@@ -190,6 +190,7 @@ public:
|
||||
S32 mNumDeadObjectUpdates;
|
||||
S32 mNumUnknownKills;
|
||||
S32 mNumDeadObjects;
|
||||
S32 mMinNumDeadObjects;
|
||||
protected:
|
||||
std::vector<U64> mOrphanParents; // LocalID/ip,port of orphaned objects
|
||||
std::vector<OrphanInfo> mOrphanChildren; // UUID's of orphaned objects
|
||||
|
||||
Reference in New Issue
Block a user