-
Notifications
You must be signed in to change notification settings - Fork 66
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
Optimize by introducing stages #33
Conversation
src/lib.rs
Outdated
@@ -58,18 +58,18 @@ extern crate fnv; | |||
extern crate mopa; | |||
#[cfg(not(target_os = "emscripten"))] | |||
extern crate pulse; | |||
extern crate rayon; | |||
#[cfg(not(target_os = "emscripten"))] | |||
extern crate rayon_core; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rayon_core probably not needed anymore?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that rayon_core
is stable and rayon
is not, we can just use rayon_core
where possible I guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well rayon
itself uses rayon_core
, and reexports all parts of it, so using this parts from rayon_core
is all the same.
src/dispatch/builder.rs
Outdated
{ | ||
let id = self.id_gen.next(); | ||
let mut reads: Vec<_> = unsafe { T::SystemData::reads(0) }; | ||
let writes = unsafe { T::SystemData::writes(0) }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these calls unsafe? Yes if returned ids are invalid it will cause a undefined behavior, but i doesn't mean that it must be marked as unsafe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, this should be changed. My initial version of shred didn't check borrow rules in release mode, but it does now..let's remove the unsafe
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It won't be undefined behaviour. If it was, unsafe would be just right.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually data race is undefined behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is, but we don't have any data races, it panics.
This optimization is big! 🎉 Benchmark running time decreased by 74%
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice to see so good speed up!
src/dispatch/builder.rs
Outdated
} | ||
|
||
/// Adds a new system with a given name and a list of dependencies. | ||
/// Please not that the dependency should be added before |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/not/note
src/dispatch/builder.rs
Outdated
reads.sort(); | ||
reads.dedup(); | ||
|
||
let mut reads = SmallVec::from_vec(reads); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason that SystemData::reads
and SystemData::writes
don't return SmallVec
s?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two reasons:
- Didn't want to make it a public dependency
- The system data may read from a resource several times. Therefore, the stack storage would often be too small at first, but not necessary anymore later. That's why I do the conversion after removing duplicates
I didn't yet check if it makes sense to use SmallVec
for reads / writes at all. It's only used for building the stages, after all.
src/dispatch/builder.rs
Outdated
{ | ||
let id = self.id_gen.next(); | ||
let mut reads: Vec<_> = T::SystemData::reads(0); | ||
let writes = T::SystemData::writes(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't these 0
s be id
instead? Or am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for reviewing, @WaDelma!
My code is correct, however it's not obvious why I did it like that, because I never wrote my design decision down.
First of all, in case you don't know, system data most likely consists of other structs implementing SystemData
, so for example:
#[derive(SystemData)]
struct Data<'a> {
a: ReadStorage<'a, A>,
b: WriteStorage<'a, B>,
}
Now, I'd like resources to have additional ids (in Specs these were called component ids). So fetch
/ reads
/ writes
should be parameterized over this resource id. However, the system data directly associated with a system, doesn't need such an id. It just gets passed 0
for that reason.
Shouldn't these 0s be id instead?
The id
you're seeing here is the system id, which is totally unrelated to the resource id.
src/dispatch/builder.rs
Outdated
let dependencies: SystemDependencies = dep.iter() | ||
.map(|x| { | ||
*self.map | ||
.get(x.to_owned()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because how HashMap::get
is defined &str
can be used for HashMap<String, _>::get
and to_owned
is unnessary here.
I got another idea how to optimize this even more, hold on. |
Yeah! I finally got it finished. |
457f86c
to
f8ae782
Compare
|
||
(self.barrier..self.stages.len()) | ||
.map(|stage| { | ||
let conflict = Self::find_conflict(&*self.ids, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any reason this is not just self.find_conflict(stage, new_reads.clone(), new_writes.clone(), new_dep)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, easier to test.
.find(|&(stage, conflict)| match conflict { | ||
Conflict::None => true, | ||
Conflict::Single(group) => { | ||
self.stages[stage].groups[group].len() < MAX_SYSTEMS_PER_GROUP - 1 && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why MAX_SYSTEMS_PER_GROUP - 1
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ArrayVec
only supports up to MAX_SYSTEMS_PER_GROUP
, so any additional system would just be discarded. So I check if there's enough space left.
src/dispatch/stage.rs
Outdated
.map(|(stage, conflict)| match conflict { | ||
Conflict::None => InsertionTarget::Stage(stage), | ||
Conflict::Single(group) => InsertionTarget::Group(stage, group), | ||
_ => unreachable!(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's have Conflict::Multiple
here explicitly instead of _
fn remove_ids(&self, stage: usize, new_dep: &mut SmallVec<[SystemId; 4]>) { | ||
if !new_dep.is_empty() { | ||
for id in self.ids[stage].iter().flat_map(|id_group| id_group) { | ||
if let Some(index) = new_dep.iter().position(|x| *x == *id) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there SmallVec::retain()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wanted to use that, but no, unfortunately there isn't.
Add rayon and arrayvec dependencies Removes rayon_core Add RunningTime and System::running_time This allows for further optimizations. Do not rustfmt macro invocations in system module Reexport RunningTime Removed debug printlns Remove typ annotation Make match exhaustive
bors r+ Thanks @Object905 @WaDelma @kvark for reviewing! |
Build succeeded |
166: Update to shred 0.4 r=torkleyy Now specs can make use of [a major optimization](amethyst/shred#33) in `shred` and [a bugfix](amethyst/shred#35) in `shred-derive`. Also improves bench by specifying running time.
126: Update hashbrown requirement from 0.1.7 to 0.2.0 r=torkleyy a=dependabot[bot] Updates the requirements on [hashbrown](https://github.com/Amanieu/hashbrown) to permit the latest version. <details> <summary>Changelog</summary> *Sourced from [hashbrown's changelog](https://github.com/Amanieu/hashbrown/blob/master/CHANGELOG.md).* > ## [v0.2.0] - 2019-03-31 > > ### Changed > - The code has been updated to Rust 2018 edition. This means that the minimum > Rust version has been bumped to 1.31 (2018 edition). > > ### Added > - Added `insert_with_hasher` to the raw_entry API to allow `K: !(Hash + Eq)`. ([#54](https://github-redirect.dependabot.com/Amanieu/hashbrown/issues/54)) > - Added support for using hashbrown as the hash table implementation in libstd. ([#46](https://github-redirect.dependabot.com/Amanieu/hashbrown/issues/46)) > > ### Fixed > - Fixed cargo build with minimal-versions. ([#45](https://github-redirect.dependabot.com/Amanieu/hashbrown/issues/45)) > - Fixed `#[may_dangle]` attributes to match the libstd `HashMap`. ([#46](https://github-redirect.dependabot.com/Amanieu/hashbrown/issues/46)) > - ZST keys and values are now handled properly. ([#46](https://github-redirect.dependabot.com/Amanieu/hashbrown/issues/46)) > > ## [v0.1.8] - 2019-01-14 > > ### Added > - Rayon parallel iterator support ([#37](https://github-redirect.dependabot.com/Amanieu/hashbrown/issues/37)) > - `raw_entry` support ([#31](https://github-redirect.dependabot.com/Amanieu/hashbrown/issues/31)) > - `#[may_dangle]` on nightly ([#31](https://github-redirect.dependabot.com/Amanieu/hashbrown/issues/31)) > - `try_reserve` support ([#31](https://github-redirect.dependabot.com/Amanieu/hashbrown/issues/31)) > > ### Fixed > - Fixed variance on `IterMut`. ([#31](https://github-redirect.dependabot.com/Amanieu/hashbrown/issues/31)) > > ## [v0.1.7] - 2018-12-05 > > ### Fixed > - Fixed non-SSE version of convert_special_to_empty_and_full_to_deleted. ([#32](https://github-redirect.dependabot.com/Amanieu/hashbrown/issues/32)) > - Fixed overflow in rehash_in_place. ([#33](https://github-redirect.dependabot.com/Amanieu/hashbrown/issues/33)) > > ## [v0.1.6] - 2018-11-17 > > ### Fixed > - Fixed compile error on nightly. ([#29](https://github-redirect.dependabot.com/Amanieu/hashbrown/issues/29)) > > ## [v0.1.5] - 2018-11-08 > > ### Fixed > - Fixed subtraction overflow in generic::Group::match_byte. ([#28](https://github-redirect.dependabot.com/Amanieu/hashbrown/issues/28)) > > ## [v0.1.4] - 2018-11-04 > > ### Fixed > - Fixed a bug in the `erase_no_drop` implementation. ([#26](https://github-redirect.dependabot.com/Amanieu/hashbrown/issues/26)) > > ## [v0.1.3] - 2018-11-01 > > ### Added ></tr></table> ... (truncated) </details> <details> <summary>Commits</summary> - [`af90bc9`](Amanieu/hashbrown@af90bc9) Version 0.2.0 - [`83ce3d5`](Amanieu/hashbrown@83ce3d5) Merge [#46](https://github-redirect.dependabot.com/Amanieu/hashbrown/issues/46) - [`f9bcc42`](Amanieu/hashbrown@f9bcc42) Add #[may_dangle] to RawIntoIter - [`b11f8cd`](Amanieu/hashbrown@b11f8cd) Upgrade to 2018 edition - [`2bd15ed`](Amanieu/hashbrown@2bd15ed) Apply feedback from https://github-redirect.dependabot.com/rust-lang/rust/pull/56241 - [`91d3e4a`](Amanieu/hashbrown@91d3e4a) Merge [#55](https://github-redirect.dependabot.com/Amanieu/hashbrown/issues/55) - [`49a9d6c`](Amanieu/hashbrown@49a9d6c) use --exclude-should-panic - [`c36d49a`](Amanieu/hashbrown@c36d49a) install Miri via rustup - [`332db4d`](Amanieu/hashbrown@332db4d) Prepare hashbrown for inclusion in the standard library - [`edf79d0`](Amanieu/hashbrown@edf79d0) Merge [#54](https://github-redirect.dependabot.com/Amanieu/hashbrown/issues/54) - Additional commits viewable in [compare view](Amanieu/hashbrown@v0.1.7...v0.2.0) </details> <br /> Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot ignore this [patch|minor|major] version` will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) - `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language - `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language - `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language - `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language - `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme Additionally, you can set the following in your Dependabot [dashboard](https://app.dependabot.com): - Update frequency (including time of day and day of week) - Automerge options (never/patch/minor, and dev/runtime dependencies) - Pull request limits (per update run and/or open at any time) - Out-of-range updates (receive only lockfile updates, if desired) - Security updates (receive only security updates, if desired) Finally, you can contact us by mentioning @dependabot. </details> Co-authored-by: dependabot[bot] <[email protected]>
This optimization is big! 🎉 Benchmark running time decreased by 74%.
Fixes #6