Skip to content
This repository has been archived by the owner on May 13, 2024. It is now read-only.

ISceneNode::removeChild() is slow #274

Closed
Desour opened this issue Jan 5, 2024 · 5 comments
Closed

ISceneNode::removeChild() is slow #274

Desour opened this issue Jan 5, 2024 · 5 comments

Comments

@Desour
Copy link
Member

Desour commented Jan 5, 2024

I've profiled Wuzzy's shadow forest game, which has many enemies that shoot with particles on you, and causes 4fps or so on my machine, even on low view range. I've used RelWithDebInfo. Here's a screenshot of the Game::run() part:
shadowforest_rlsdbg

Here's the implementation of ISceneNode::removeChild(), it iterates through all scene node childs:

virtual bool removeChild(ISceneNode* child)
{
ISceneNodeList::iterator it = Children.begin();
for (; it != Children.end(); ++it)
if ((*it) == child)
{
(*it)->Parent = 0;
(*it)->drop();
Children.erase(it);
return true;
}
return false;
}

This needs to be fixed for better particle performance.

@SmallJoker
Copy link
Member

SmallJoker commented Jan 5, 2024

The sorted std::set might perform better for lookups (binary search?). Or perhaps std::vector if the compiler is smart enough to parallelize the lookup code in std::find (e.g. by using SIMD).

Or move particles spawned by a particle spawner into a root ISceneNode's to shorten the child lookups.

@appgurueu
Copy link
Contributor

The sorted std::set might perform better for loopkups (binary search?). Or perhaps std::vector if the compiler is smart enough to parallelize the lookup code in std::find (e.g. by using SIMD).

I don't think we need any sorting here. An unordered set would work, but is unnecessary. We have a doubly linked list and that allows O(1) removal - we just need the ISceneNode to store an iterator to its position in the list.

@SmallJoker
Copy link
Member

SmallJoker commented Jan 5, 2024

@appgurueu How would you seamlessly update those iterators when one child is removed? Storing iterators is in general bad practice as they may get outdated. If not now, someone will surely forget to update them in a future change.

I think what slows down the code right now is that doubly-linked lists like std::list cannot be parallelized well due to the nature of pointer chains.

@appgurueu
Copy link
Contributor

appgurueu commented Jan 5, 2024

How would you seamlessly update those iterators when one child is removed?

That shouldn't be necessary, a doubly linked list doesn't invalidate iterators.

Storing iterators is in general bad practice as they may get outdated.

Doubly linked lists are special. Pretty much the only reason to use them is if you will be storing iterators to do element removal somewhere within the list in O(1) time.

If not now, someone will surely forget to update them in a future change.

I would have liked to believe that this would be well isolated to the addChild and removeChild methods, but ASan seems to be proving me wrong.

@Desour
Copy link
Member Author

Desour commented Jan 6, 2024

If in the future we want to replace the containers again or so, please note that iterating through also needs to be fast, because of functions like OnAnimate and OnRegisterSceneNode, which currently take about 1/8 client step cpu time that they mostly spend on iterating.

@sfan5 sfan5 closed this as completed Jan 8, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants