-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deleting / detaching / moving large numbers of child nodes can be excessively slow #61929
Comments
Related: |
I just noticed this problem too in Godot 4, as I was removing about 500 3D nodes from a list of a few thousand siblings. It resulted in hiccups where framerate slowed down to 180ms. The main culprit in my case was the Possible workarounds:
Possible solution:
Other solutions for 2D nodes could depend on how that notification is actually used. Maybe it could be changed to some lazy evaluation or polling (node index is updated faster than sending the notification). A virtual function could be used, though I dont know how fast it would be. |
This issue (deletion) is mostly solved by a combination of #62444 (particularly where large percentage of siblings are deleted) and #65581 (prevents more than 1 notification). I discussed the use of bitflags, observer pattern etc in #65581 (comment) in the "additional methods". As I say there, registering an interest and observer pattern is potentially the most efficient mechanism, but the problem of backward compatibility is important (especially in 3.x), and also weighing up the complexity / efficiency of maintaining observer lists versus simpler, less perfect solutions. For I'm happy to do an observer lists PR, but really am waiting for these existing PRs to either be merged or get further review from @reduz . Otherwise it could be a waste of time. Observer lists is also very compat breaking so is more likely to be refused, so would be better to discuss first. An additional technique I considered but didn't write about before is maintaining the ID within the child list of a node that all others are considered dirty, and flushing this list for |
There is no observer list to maintain in my solution. The change is only a few lines. Also, I did it in Godot 4. |
Sorry, I was not clear - in that quoted paragraph I'm discussing only observer lists. 🙂 |
It's fixed in 3.6 as I wrote above. But it's not fixed in 4.0, which is why this issue is still open - and since it's now a 4.x specific bug, the 3.6 milestone isn't accurate. |
Is there going to be a way to allow nodes to opt into NOTIFICATION_MOVED_IN_PARENT in 4.x in the future? I'm making a container node that uses NOTIFICATION_MOVED_IN_PARENT to refresh its background. It draws the background with VisualServer and needs to make it a non-child of the container node to prevent it from being clipped by the container's bounds, with the draw index based on the index of the container node in its parent. I need to use this notification because otherwise moving other nodes around the container causes the background to draw at the wrong sort level, resulting in situations like this: 2023-08-12_06-48-49.mp4 |
Godot version
3.5 current (3.5 RC 3), earlier versions presumably
System information
N/A
Issue description
While benchmarking something else, I noticed that the time taken to
queue_delete()
a large number ofMeshInstance
children seemed to grow exponentially with the number of siblings of the parent. This is unlikely to come up that often outside of benchmarks / extreme cases, but is still a concern.On discussion with @akien-mga there were two suspect areas, the ordered remove and possibly notifications sent as a result of the moving of the children. Testing revealed that the slowdown didn't occur when removing children in back to front order, which confirmed the suspicions.
A very similar problem can also occur when detaching / attaching / moving nodes.
I've also profiled the slow situation:
Steps to reproduce
queue_delete()
in the order ofget_child()
Minimal reproduction project
QueueDeleteSlow.zip
queue_free()
line 14, takes 250ms.If you queue free in reverse order:
It takes 730ms - still curiously slower than adding, but a lot faster than before.
Update
Make the box invisible to eliminate the BVH from the bottlenecks, this shows the real difference from the PR linked.
Discussion
It is possible we can modify the deletion code to prevent this situation occurring, perhaps by guaranteeing reverse ordering:
queued_for_deletion
flags when deleting nodesAdditionally, if there is a notification on re-ordering, perhaps it can be sent once (after all deletes) instead of after each deletion.
The text was updated successfully, but these errors were encountered: