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] - Speed up Query::get_many and add benchmarks #6400

Closed
wants to merge 6 commits into from

Conversation

JoJoJet
Copy link
Member

@JoJoJet JoJoJet commented Oct 28, 2022

Objective

  • Add benchmarks for Query::get_many.
  • Speed up Query::get_many.

Solution

Previously, get_many and get_many_mut used the method array::map, which tends to optimize very poorly. This PR replaces uses of that method with loops.

Benchmarks

Benchmark name Execution time Change from this PR
query_get_many_2/50000_calls_table 1.3732 ms -24.967%
query_get_many_2/50000_calls_sparse 1.3826 ms -24.572%
query_get_many_5/50000_calls_table 2.6833 ms -30.681%
query_get_many_5/50000_calls_sparse 2.9936 ms -30.672%
query_get_many_10/50000_calls_table 5.7771 ms -36.950%
query_get_many_10/50000_calls_sparse 7.4345 ms -36.987%

@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 labels Oct 28, 2022
@alice-i-cecile alice-i-cecile self-requested a review October 28, 2022 22:27
last_change_tick,
change_tick,
)?;
values[i] = MaybeUninit::new(item);
Copy link
Member

Choose a reason for hiding this comment

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

This does a bounds check. It's a bit more verbose, but slice::get_unchecked_mut might further speed things up a bit. We know the index must be valid because i must be less than N.

Copy link
Member Author

Choose a reason for hiding this comment

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

I ended up using an iterator to remove the bounds checks -- I measured the same performance for both iterators and get_unchecked_mut.

crates/bevy_ecs/src/query/state.rs Outdated Show resolved Hide resolved
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.

Can we get one more round of benchmarks to ensure that the review changes haven't shifted the perf that significantly?

@JoJoJet
Copy link
Member Author

JoJoJet commented Oct 29, 2022

Here's another run:

Benchmark name Execution time Change from this PR
query_get_many_2/50000_calls_table 1.3157 ms -27.165%
query_get_many_2/50000_calls_sparse 1.4198 ms -22.200%
query_get_many_5/50000_calls_table 2.7343 ms -27.511%
query_get_many_5/50000_calls_sparse 3.0702 ms -25.492%
query_get_many_10/50000_calls_table 5.7574 ms -38.111%
query_get_many_10/50000_calls_sparse 7.9845 ms -26.528%

Criterion output: https://github.com/JoJoJet/files/blob/c4b99129978e2566b2139efb5e96462094c77aed/get-many-benches-output.zip

@james7132 james7132 added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Nov 1, 2022
@alice-i-cecile
Copy link
Member

bors r+

bors bot pushed a commit that referenced this pull request Nov 1, 2022
# Objective

* Add benchmarks for `Query::get_many`.
* Speed up `Query::get_many`.

## Solution

Previously, `get_many` and `get_many_mut` used the method `array::map`, which tends to optimize very poorly. This PR replaces uses of that method with loops.

## Benchmarks

| Benchmark name                       | Execution time | Change from this PR |
|--------------------------------------|----------------|---------------------|
| query_get_many_2/50000_calls_table   | 1.3732 ms      | -24.967%            |
| query_get_many_2/50000_calls_sparse  | 1.3826 ms      | -24.572%            |
| query_get_many_5/50000_calls_table   | 2.6833 ms      | -30.681%            |
| query_get_many_5/50000_calls_sparse  | 2.9936 ms      | -30.672%            |
| query_get_many_10/50000_calls_table  | 5.7771 ms      | -36.950%            |
| query_get_many_10/50000_calls_sparse | 7.4345 ms      | -36.987%            |
@bors bors bot changed the title Speed up Query::get_many and add benchmarks [Merged by Bors] - Speed up Query::get_many and add benchmarks Nov 1, 2022
@bors bors bot closed this Nov 1, 2022
@JoJoJet JoJoJet deleted the iter-many branch November 1, 2022 08:40
ItsDoot pushed a commit to ItsDoot/bevy that referenced this pull request Feb 1, 2023
# Objective

* Add benchmarks for `Query::get_many`.
* Speed up `Query::get_many`.

## Solution

Previously, `get_many` and `get_many_mut` used the method `array::map`, which tends to optimize very poorly. This PR replaces uses of that method with loops.

## Benchmarks

| Benchmark name                       | Execution time | Change from this PR |
|--------------------------------------|----------------|---------------------|
| query_get_many_2/50000_calls_table   | 1.3732 ms      | -24.967%            |
| query_get_many_2/50000_calls_sparse  | 1.3826 ms      | -24.572%            |
| query_get_many_5/50000_calls_table   | 2.6833 ms      | -30.681%            |
| query_get_many_5/50000_calls_sparse  | 2.9936 ms      | -30.672%            |
| query_get_many_10/50000_calls_table  | 5.7771 ms      | -36.950%            |
| query_get_many_10/50000_calls_sparse | 7.4345 ms      | -36.987%            |
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 S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants