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

[Merged by Bors] - Make System responsible for updating its own archetypes #4115

Closed
wants to merge 14 commits into from

Conversation

tornewuff
Copy link
Contributor

Objective

  • Make it possible to use Systems outside of the scheduler/executor without having to define logic to track new archetypes and call System::add_archetype() for each.

Solution

  • Replace System::add_archetype(&Archetype) with System::update_archetypes(&World), making systems responsible for tracking their own most recent archetype generation the way that SystemState already does.

This has minimal (or simplifying) effect on most of the code with the exception of FunctionSystem, which must now track the latest ArchetypeGeneration it saw instead of relying on the executor to do it.

@github-actions github-actions bot added the S-Needs-Triage This issue needs to be labelled label Mar 5, 2022
@tornewuff
Copy link
Contributor Author

This was suggested in the discussion on https://discord.com/channels/691052431525675048/947636849139150868 with @alice-i-cecile and others - it turned out to be pretty simple, so sending this to see what folks think.

@maniwani
Copy link
Contributor

maniwani commented Mar 5, 2022

Instead of replacing the new_archetype method, can we just add your update_archetypes method?

Some users (and mocking up tests) might still want to register only specific archetypes.

@alice-i-cecile alice-i-cecile added A-ECS Entities, components, systems, and events C-Usability A targeted quality-of-life change that makes Bevy easier to use and removed S-Needs-Triage This issue needs to be labelled labels Mar 5, 2022
Copy link
Contributor

@hymm hymm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall as long as this doesn't change perf too much, I think it makes sense as a low level api for people to run systems outside of the executor.

for archetype in world.archetypes.iter() {
system.new_archetype(archetype);
}
system.update_archetypes(&world);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test doesn't really check if the archetypes are updated correctly. Since this new function is part of the public api that we expect to be used, should we be adding more tests to check correctness?

Copy link
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall I like this change quite a bit:

Positive:

  • less duplication of complex, critical logic
  • essential for safe third-party implementations of custom executors or other scheduling strategies

Unsure:

  • how this affect performance, if at all?

Requested changes:

  • I would like to see some more robusts tests to verify that this works, with an emphasis on scenarios that were previously impossible
  • docs nits

@tornewuff
Copy link
Contributor Author

Instead of replacing the new_archetype method, can we just add your update_archetypes method?

Some users (and mocking up tests) might still want to register only specific archetypes.

I'm not sure how common a use case that would be - it seems like it makes the API rather less clear to have both? The interaction between the two isn't really obvious. If there's a general consensus that it's likely to be useful then I can restore it, and just try to describe the behaviour more thoroughly, though.

The other comments all make sense; I agree that better naming would help here, especially if keeping both functions. To propose yet another combination, register_archetype and update_registered_archetypes might work? Though even register_archetype or similar might not be ideal - it's really only notifying the system about the existence of the archetype, since the SystemParam still actually decides whether the archetype is relevant or not.

Since it seems like there's general agreement that this is desirable for the API, I'll see about benchmarking it and adding test coverage.

@tornewuff
Copy link
Contributor Author

Still need to work on tests/docs but wanted to see what folks think of this basic set of benchmarks, which don't show any difference outside of noise for me.

@alice-i-cecile
Copy link
Member

Some users (and mocking up tests) might still want to register only specific archetypes.

This seem extremely implausible to me. IMO if this is the best argument in favor of keeping it it should be cut for sure.

@tornewuff
Copy link
Contributor Author

(also this is the first time I've actually used github PR code review so am not entirely sure of expectations around resolving comments etc)

@alice-i-cecile
Copy link
Member

wanted to see what folks think of this basic set of benchmarks, which don't show any difference outside of noise for me.

Could you post the benchmark results in the PR description? It's helpful context for reviewers: no change is good news!

(also this is the first time I've actually used github PR code review so am not entirely sure of expectations around resolving comments etc)

Resolve comments once the changes are addressed :) If there are interesting but unactionable comments / call-outs, keep those around so folks can see those on later review / just before merge.

@tornewuff
Copy link
Contributor Author

Results of the benchmark without the change:

no_archetypes           time:   [39.805 us 39.956 us 40.119 us]                           
Found 3 outliers among 100 measurements (3.00%)
  3 (3.00%) high mild

added_archetypes        time:   [304.90 us 306.26 us 307.82 us]                             
Found 4 outliers among 100 measurements (4.00%)
  3 (3.00%) high mild
  1 (1.00%) high severe

and with the change:

no_archetypes           time:   [40.220 us 40.335 us 40.454 us]                           
                        change: [+0.2379% +0.6498% +1.0508%] (p = 0.00 < 0.05)
                        Change within noise threshold.
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild

added_archetypes        time:   [307.27 us 308.21 us 309.15 us]                             
                        change: [+0.1588% +0.7505% +1.3797%] (p = 0.02 < 0.05)
                        Change within noise threshold.
Found 4 outliers among 100 measurements (4.00%)
  1 (1.00%) high mild
  3 (3.00%) high severe

I re-ran this on my giant desktop instead of my ultrabook and there things are less noisy, so it does become statistically significant.

@tornewuff
Copy link
Contributor Author

Hm. Actually it's still pretty noisy on this machine too even with CPU frequency locked.

@maniwani
Copy link
Contributor

maniwani commented Mar 11, 2022

Thanks for benchmarking, I was hoping there wouldn't be much of a change since we'll still be registering archetypes the same number of times. Good to have some confirmation.

Copy link
Contributor

@maniwani maniwani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aside from two nits, this looks good to me.

crates/bevy_ecs/src/system/system.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/schedule/executor.rs Outdated Show resolved Hide resolved
@tornewuff
Copy link
Contributor Author

So with the updated benchmark here I'm actually seeing performance on added_archetypes with my change included being anything up to 10-15% faster, though the results are still pretty noisy and I'm not sure how to get criterion to generate a nice report with a comparison. So, hopefully it's at least no worse in reality?

I'm still thinking about tests to add here but am pretty happy with the form it's in now; thanks for the continued discussion all!

@james7132
Copy link
Member

though the results are still pretty noisy and I'm not sure how to get criterion to generate a nice report with a comparison

critcmp is a pretty common and standard solution here.

@tornewuff
Copy link
Contributor Author

Ah, I have a hypothesis for why the performance might have actually improved for large numbers of new archetypes - previously the update loop in the executor was iterating over all the new archetypes and passing each to every system in turn, but this is now iterating over the systems and having each deal with all the new archetypes, which seems likely to have better locality?

Copy link
Member

@james7132 james7132 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks great. Less code, and is potentially faster? Sounds great to me. Just one thing: could you use critcmp as suggested above and provide a solid comparison between the results from before and after?

Add a simple unit test for update_archetype_component_access to ensure
that the access is properly updated.
@tornewuff
Copy link
Contributor Author

Well, with the simple unit test I added above it does look like things are working; if folks have suggestions for more things to test I can give it a shot?

While I'm still a little sceptical of the benchmark results being particularly meaningful, it doesn't appear to have broken anything? :)

maniwani added a commit to maniwani/bevy that referenced this pull request Mar 30, 2022
@tornewuff
Copy link
Contributor Author

OK; I'm considering this done. If folks have other suggestions I can take a look.

@cart cart added this to the Bevy 0.7 milestone Apr 4, 2022
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
@cart
Copy link
Member

cart commented Apr 7, 2022

bors r+

bors bot pushed a commit that referenced this pull request Apr 7, 2022
# Objective

- Make it possible to use `System`s outside of the scheduler/executor without having to define logic to track new archetypes and call `System::add_archetype()` for each.

## Solution

- Replace `System::add_archetype(&Archetype)` with `System::update_archetypes(&World)`, making systems responsible for tracking their own most recent archetype generation the way that `SystemState` already does.

This has minimal (or simplifying) effect on most of the code with the exception of `FunctionSystem`, which must now track the latest `ArchetypeGeneration` it saw instead of relying on the executor to do it.

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
@bors
Copy link
Contributor

bors bot commented Apr 7, 2022

Canceled.

@cart
Copy link
Member

cart commented Apr 7, 2022

bors r+

bors bot pushed a commit that referenced this pull request Apr 7, 2022
# Objective

- Make it possible to use `System`s outside of the scheduler/executor without having to define logic to track new archetypes and call `System::add_archetype()` for each.

## Solution

- Replace `System::add_archetype(&Archetype)` with `System::update_archetypes(&World)`, making systems responsible for tracking their own most recent archetype generation the way that `SystemState` already does.

This has minimal (or simplifying) effect on most of the code with the exception of `FunctionSystem`, which must now track the latest `ArchetypeGeneration` it saw instead of relying on the executor to do it.

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
@bors
Copy link
Contributor

bors bot commented Apr 7, 2022

Build failed:

@cart
Copy link
Member

cart commented Apr 7, 2022

bors r+

bors bot pushed a commit that referenced this pull request Apr 7, 2022
# Objective

- Make it possible to use `System`s outside of the scheduler/executor without having to define logic to track new archetypes and call `System::add_archetype()` for each.

## Solution

- Replace `System::add_archetype(&Archetype)` with `System::update_archetypes(&World)`, making systems responsible for tracking their own most recent archetype generation the way that `SystemState` already does.

This has minimal (or simplifying) effect on most of the code with the exception of `FunctionSystem`, which must now track the latest `ArchetypeGeneration` it saw instead of relying on the executor to do it.

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
@bors bors bot changed the title Make System responsible for updating its own archetypes [Merged by Bors] - Make System responsible for updating its own archetypes Apr 7, 2022
@bors bors bot closed this Apr 7, 2022
@tornewuff tornewuff deleted the update-archetypes branch April 10, 2022 17:03
@tornewuff
Copy link
Contributor Author

Thanks; I didn't intend to leave the println calls in there but since they get swallowed during normal test runs I forgot :)

aevyrie pushed a commit to aevyrie/bevy that referenced this pull request Jun 7, 2022
…#4115)

# Objective

- Make it possible to use `System`s outside of the scheduler/executor without having to define logic to track new archetypes and call `System::add_archetype()` for each.

## Solution

- Replace `System::add_archetype(&Archetype)` with `System::update_archetypes(&World)`, making systems responsible for tracking their own most recent archetype generation the way that `SystemState` already does.

This has minimal (or simplifying) effect on most of the code with the exception of `FunctionSystem`, which must now track the latest `ArchetypeGeneration` it saw instead of relying on the executor to do it.

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
ItsDoot pushed a commit to ItsDoot/bevy that referenced this pull request Feb 1, 2023
…#4115)

# Objective

- Make it possible to use `System`s outside of the scheduler/executor without having to define logic to track new archetypes and call `System::add_archetype()` for each.

## Solution

- Replace `System::add_archetype(&Archetype)` with `System::update_archetypes(&World)`, making systems responsible for tracking their own most recent archetype generation the way that `SystemState` already does.

This has minimal (or simplifying) effect on most of the code with the exception of `FunctionSystem`, which must now track the latest `ArchetypeGeneration` it saw instead of relying on the executor to do it.

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
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 C-Performance A change motivated by improving speed, memory usage or compile times C-Usability A targeted quality-of-life change that makes Bevy easier to use S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
Archived in project
Archived in project
Development

Successfully merging this pull request may close these issues.

6 participants