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:
Aleric Inglewood
2011-05-15 23:02:44 +02:00
parent 4e68f5878a
commit 93fdc2c89e
3 changed files with 71 additions and 32 deletions

View File

@@ -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;

View File

@@ -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)

View File

@@ -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