Skip to content
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

Faster entity cloning #16717

Open
wants to merge 19 commits into
base: main
Choose a base branch
from

Conversation

eugineerd
Copy link
Contributor

Objective

#16132 introduced entity cloning functionality, and while it works and is useful, it can be made faster. This is the promised follow-up to improve performance.

Solution

PREFACE: This is my first time writing unsafe in rust and I have only vague idea about what I'm doing. I would encourage reviewers to scrutinize unsafe parts in particular.

The solution is to use EntityWorldMut::insert_by_ids to clone components without archetype moves.

To facilitate this, EntityCloner::clone_entity now reads all components of the source entity and provides clone handlers with the ability to read component data straight from component storage using read_source_component and write to intermediate buffer using write_target_component. ComponentId is used to check that requested type corresponds to the type available on source entity.

Reflect-based handler is a little trickier to pull of: we only have &dyn Reflect and no access to the underlying data. For this reason, only components that have ReflectDefault would use the fast path; all other components will use previous implementation. The good news is that this is actually only a temporary limitation: once #13432 lands we will be able to use the fast path for all Reflect components without using Default to initialize component data.

This PR also introduces entity_cloning benchmark to better compare changes between the PR and main, you can see the results in the showcase section.

Testing

  • All previous tests passing
  • Added test for fast reflect clone path (temporary, will be removed after reflection-based cloning lands)
  • Ran miri

Showcase

Here's a table demonstrating the improvement:

NOTE: reflect benchmarks are run on components with ReflectDefault, for components that do not it is unchanged or slightly worse (due to more allocations) than main.

benchmark main, avg PR, avg change, avg
many components reflect 20.229 µs 3.1248 µs -84.581%
hierarchy wide reflect 24.611 ms 5.1320 ms -79.147%
hierarchy tall reflect 115.73 µs 30.587 µs -74.874%
hierarchy many reflect 85.200 ms 14.063 ms -83.494%
many components clone 1.3738 µs 777.98 ns -43.897%
hierarchy wide clone 2.8930 ms 2.7272 ms -5.7298%
hierarchy tall clone 17.590 µs 20.873 µs +20.100%
hierarchy many clone 6.0900 ms 4.6903 ms -22.984%

Considerations

Once #10154 is resolved a large part of the functionality in this PR will probably become obsolete. It might still be a little bit faster than using command batching, but the complexity might not be worth it.

Migration Guide

  • EntityCloner in component clone handlers is changed to ComponentCloneCtx to better separate data.
  • Changed EntityCloneHandler from enum to struct and added convenience functions to add default clone and reflect handler more easily.

@alice-i-cecile alice-i-cecile added this to the 0.16 milestone Dec 8, 2024
@alice-i-cecile alice-i-cecile added A-ECS Entities, components, systems, and events C-Performance A change motivated by improving speed, memory usage or compile times A-Reflection Runtime information about types D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes D-Unsafe Touches with unsafe code in some way S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Dec 8, 2024
@eugineerd
Copy link
Contributor Author

Fixed tests for reflect-based cloning paths not actually checking reflect paths (oops) and clone_fast path in reflect handler not actually writing pointers to component data (which the tests should've caught). This fix didn't affect benchmark results in any noticeable way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events A-Reflection Runtime information about types C-Performance A change motivated by improving speed, memory usage or compile times D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes D-Unsafe Touches with unsafe code in some way S-Needs-Review Needs reviewer attention (from anyone!) to move forward
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants