Skip to content

Commit

Permalink
Implement State sets
Browse files Browse the repository at this point in the history
  • Loading branch information
TheRawMeatball committed Feb 9, 2021
1 parent d5a7330 commit 091f5a8
Show file tree
Hide file tree
Showing 3 changed files with 404 additions and 215 deletions.
2 changes: 2 additions & 0 deletions crates/bevy_ecs/src/schedule/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod state;
mod system_container;
mod system_descriptor;
mod system_set;
mod state_set;

pub use executor::*;
pub use executor_parallel::*;
Expand All @@ -13,6 +14,7 @@ pub use state::*;
pub use system_container::*;
pub use system_descriptor::*;
pub use system_set::*;
pub use state_set::*;

use crate::{
ArchetypeComponent, BoxedSystem, IntoSystem, Resources, System, SystemId, TypeAccess, World,
Expand Down
245 changes: 30 additions & 215 deletions crates/bevy_ecs/src/schedule/stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,51 +469,34 @@ fn topological_order(
/// Returns vector containing all pairs of indices of systems with ambiguous execution order.
/// Systems must be topologically sorted beforehand.
fn find_ambiguities(systems: &[impl SystemContainer]) -> Vec<(usize, usize)> {
let mut all_dependencies = Vec::<FixedBitSet>::with_capacity(systems.len());
let mut all_dependants = Vec::<FixedBitSet>::with_capacity(systems.len());
let mut all_relations = Vec::<FixedBitSet>::with_capacity(systems.len());
for (index, container) in systems.iter().enumerate() {
let mut dependencies = FixedBitSet::with_capacity(systems.len());
for &dependency in container.dependencies() {
dependencies.union_with(&all_dependencies[dependency]);
dependencies.insert(dependency);
all_dependants[dependency].insert(index);
let mut relations = FixedBitSet::with_capacity(systems.len());
relations.insert(index);
for dependency in container.dependencies() {
relations.union_with(&all_relations[*dependency]);
relations.insert(*dependency);
}
all_dependants.push(FixedBitSet::with_capacity(systems.len()));
all_dependencies.push(dependencies);
all_relations.push(relations);
}
for index in (0..systems.len()).rev() {
let mut dependants = FixedBitSet::with_capacity(systems.len());
for dependant in all_dependants[index].ones() {
dependants.union_with(&all_dependants[dependant]);
dependants.insert(dependant);
for (index, container) in systems.iter().enumerate().rev() {
let relations = all_relations[index].clone();
for dependency in container.dependencies() {
all_relations[*dependency].union_with(&relations);
}
all_dependants[index] = dependants;
}
let mut all_relations = all_dependencies
.drain(..)
.zip(all_dependants.drain(..))
.enumerate()
.map(|(index, (dependencies, dependants))| {
let mut relations = FixedBitSet::with_capacity(systems.len());
relations.union_with(&dependencies);
relations.union_with(&dependants);
relations.insert(index);
relations
})
.collect::<Vec<FixedBitSet>>();
// TODO: There is enough data to group ambiguity pairs into OR blocks,
// as in, "you might want to add a relation to at least one of these pairs".
let mut ambiguities = Vec::new();
let full_bitset: FixedBitSet = (0..systems.len()).collect();
let mut processed = FixedBitSet::with_capacity(systems.len());
for (index_a, relations) in all_relations.drain(..).enumerate() {
// TODO: prove that `.take(index_a)` would be correct here, and uncomment it if so.
for index_b in full_bitset.difference(&relations)
/*.take(index_a)*/
{
if !processed.contains(index_b) && !systems[index_a].is_compatible(&systems[index_b]) {
for index_b in full_bitset.difference(&relations) {
if !systems[index_a].is_compatible(&systems[index_b])
&& !ambiguities.contains(&(index_b, index_a))
{
ambiguities.push((index_a, index_b));
}
}
processed.insert(index_a);
}
ambiguities
}
Expand Down Expand Up @@ -1102,35 +1085,18 @@ mod tests {

#[test]
fn ambiguity_detection() {
use super::{find_ambiguities, SystemContainer};
use std::borrow::Cow;

fn find_ambiguities_labels(
systems: &[impl SystemContainer],
) -> Vec<(Cow<'static, str>, Cow<'static, str>)> {
find_ambiguities(systems)
.drain(..)
.map(|(index_a, index_b)| {
(
systems[index_a].display_name(),
systems[index_b].display_name(),
)
})
.collect()
}

use super::find_ambiguities;
fn empty() {}
fn resource(_: ResMut<usize>) {}
fn component(_: Query<&mut f32>) {}

let mut world = World::new();
let mut resources = Resources::default();

let mut stage = SystemStage::parallel()
.with_system(empty.system().label("0"))
.with_system(empty.system().label("1").after("0"))
.with_system(empty.system().label("2"))
.with_system(empty.system().label("3").after("2").before("4"))
.with_system(empty.system().after("2").before("4"))
.with_system(empty.system().label("4"));
stage.initialize_systems(&mut world, &mut resources);
stage.rebuild_orders_and_dependencies();
Expand All @@ -1140,37 +1106,27 @@ mod tests {
.with_system(empty.system().label("0"))
.with_system(component.system().label("1").after("0"))
.with_system(empty.system().label("2"))
.with_system(empty.system().label("3").after("2").before("4"))
.with_system(empty.system().after("2").before("4"))
.with_system(component.system().label("4"));
stage.initialize_systems(&mut world, &mut resources);
stage.rebuild_orders_and_dependencies();
let ambiguities = find_ambiguities_labels(&stage.parallel);
assert!(
ambiguities.contains(&("1".into(), "4".into()))
|| ambiguities.contains(&("4".into(), "1".into()))
);
assert_eq!(ambiguities.len(), 1);
assert_eq!(find_ambiguities(&stage.parallel).len(), 1);

let mut stage = SystemStage::parallel()
.with_system(empty.system().label("0"))
.with_system(resource.system().label("1").after("0"))
.with_system(empty.system().label("2"))
.with_system(empty.system().label("3").after("2").before("4"))
.with_system(empty.system().after("2").before("4"))
.with_system(resource.system().label("4"));
stage.initialize_systems(&mut world, &mut resources);
stage.rebuild_orders_and_dependencies();
let ambiguities = find_ambiguities_labels(&stage.parallel);
assert!(
ambiguities.contains(&("1".into(), "4".into()))
|| ambiguities.contains(&("4".into(), "1".into()))
);
assert_eq!(ambiguities.len(), 1);
assert_eq!(find_ambiguities(&stage.parallel).len(), 1);

let mut stage = SystemStage::parallel()
.with_system(empty.system().label("0"))
.with_system(resource.system().label("1").after("0"))
.with_system(empty.system().label("2"))
.with_system(empty.system().label("3").after("2").before("4"))
.with_system(empty.system().after("2").before("4"))
.with_system(component.system().label("4"));
stage.initialize_systems(&mut world, &mut resources);
stage.rebuild_orders_and_dependencies();
Expand All @@ -1180,161 +1136,20 @@ mod tests {
.with_system(component.system().label("0"))
.with_system(resource.system().label("1").after("0"))
.with_system(empty.system().label("2"))
.with_system(component.system().label("3").after("2").before("4"))
.with_system(component.system().after("2").before("4"))
.with_system(resource.system().label("4"));
stage.initialize_systems(&mut world, &mut resources);
stage.rebuild_orders_and_dependencies();
let ambiguities = find_ambiguities_labels(&stage.parallel);
assert!(
ambiguities.contains(&("0".into(), "3".into()))
|| ambiguities.contains(&("3".into(), "0".into()))
);
assert!(
ambiguities.contains(&("1".into(), "4".into()))
|| ambiguities.contains(&("4".into(), "1".into()))
);
assert_eq!(ambiguities.len(), 2);

let mut stage = SystemStage::parallel()
.with_system(component.system().label("0").before("2"))
.with_system(component.system().label("1").before("2"))
.with_system(component.system().label("2"));
stage.initialize_systems(&mut world, &mut resources);
stage.rebuild_orders_and_dependencies();
let ambiguities = find_ambiguities_labels(&stage.parallel);
assert!(
ambiguities.contains(&("0".into(), "1".into()))
|| ambiguities.contains(&("1".into(), "0".into()))
);
assert_eq!(ambiguities.len(), 1);

let mut stage = SystemStage::parallel()
.with_system(component.system().label("0"))
.with_system(component.system().label("1").after("0"))
.with_system(component.system().label("2").after("0"));
stage.initialize_systems(&mut world, &mut resources);
stage.rebuild_orders_and_dependencies();
let ambiguities = find_ambiguities_labels(&stage.parallel);
assert!(
ambiguities.contains(&("1".into(), "2".into()))
|| ambiguities.contains(&("2".into(), "1".into()))
);
assert_eq!(ambiguities.len(), 1);

let mut stage = SystemStage::parallel()
.with_system(component.system().label("0").before("1").before("2"))
.with_system(component.system().label("1"))
.with_system(component.system().label("2"))
.with_system(component.system().label("3").after("1").after("2"));
stage.initialize_systems(&mut world, &mut resources);
stage.rebuild_orders_and_dependencies();
let ambiguities = find_ambiguities_labels(&stage.parallel);
assert!(
ambiguities.contains(&("1".into(), "2".into()))
|| ambiguities.contains(&("2".into(), "1".into()))
);
assert_eq!(ambiguities.len(), 1);

let mut stage = SystemStage::parallel()
.with_system(
component
.system()
.label("0")
.before("1")
.before("2")
.before("3")
.before("4"),
)
.with_system(component.system().label("1"))
.with_system(component.system().label("2"))
.with_system(component.system().label("3"))
.with_system(component.system().label("4"))
.with_system(
component
.system()
.label("5")
.after("1")
.after("2")
.after("3")
.after("4"),
);
stage.initialize_systems(&mut world, &mut resources);
stage.rebuild_orders_and_dependencies();
let ambiguities = find_ambiguities_labels(&stage.parallel);
assert!(
ambiguities.contains(&("1".into(), "2".into()))
|| ambiguities.contains(&("2".into(), "1".into()))
);
assert!(
ambiguities.contains(&("1".into(), "3".into()))
|| ambiguities.contains(&("3".into(), "1".into()))
);
assert!(
ambiguities.contains(&("1".into(), "4".into()))
|| ambiguities.contains(&("4".into(), "1".into()))
);
assert!(
ambiguities.contains(&("2".into(), "3".into()))
|| ambiguities.contains(&("3".into(), "2".into()))
);
assert!(
ambiguities.contains(&("2".into(), "4".into()))
|| ambiguities.contains(&("4".into(), "2".into()))
);
assert!(
ambiguities.contains(&("3".into(), "4".into()))
|| ambiguities.contains(&("4".into(), "3".into()))
);
assert_eq!(ambiguities.len(), 6);
assert_eq!(find_ambiguities(&stage.parallel).len(), 2);

let mut stage = SystemStage::parallel()
.with_system(empty.exclusive_system().label("0"))
.with_system(empty.exclusive_system().label("1").after("0"))
.with_system(empty.exclusive_system().label("2").after("1"))
.with_system(empty.exclusive_system().label("3").after("2"))
.with_system(empty.exclusive_system().label("4").after("3"))
.with_system(empty.exclusive_system().label("5").after("4"))
.with_system(empty.exclusive_system().label("6").after("5"))
.with_system(empty.exclusive_system().label("7").after("6"));
stage.initialize_systems(&mut world, &mut resources);
stage.rebuild_orders_and_dependencies();
assert_eq!(find_ambiguities(&stage.exclusive_at_start).len(), 0);

let mut stage = SystemStage::parallel()
.with_system(empty.exclusive_system().label("0").before("1").before("3"))
.with_system(empty.exclusive_system().label("1"))
.with_system(empty.exclusive_system().label("2").after("1"))
.with_system(empty.exclusive_system().label("3"))
.with_system(empty.exclusive_system().label("4").after("3").before("5"))
.with_system(empty.exclusive_system().label("5"))
.with_system(empty.exclusive_system().label("6").after("2").after("5"));
.with_system(empty.exclusive_system().label("2"))
.with_system(empty.exclusive_system().after("2").before("4"))
.with_system(empty.exclusive_system().label("4"));
stage.initialize_systems(&mut world, &mut resources);
stage.rebuild_orders_and_dependencies();
let ambiguities = find_ambiguities_labels(&stage.exclusive_at_start);
assert!(
ambiguities.contains(&("1".into(), "3".into()))
|| ambiguities.contains(&("3".into(), "1".into()))
);
assert!(
ambiguities.contains(&("2".into(), "3".into()))
|| ambiguities.contains(&("3".into(), "2".into()))
);
assert!(
ambiguities.contains(&("1".into(), "4".into()))
|| ambiguities.contains(&("4".into(), "1".into()))
);
assert!(
ambiguities.contains(&("2".into(), "4".into()))
|| ambiguities.contains(&("4".into(), "2".into()))
);
assert!(
ambiguities.contains(&("1".into(), "5".into()))
|| ambiguities.contains(&("5".into(), "1".into()))
);
assert!(
ambiguities.contains(&("2".into(), "5".into()))
|| ambiguities.contains(&("5".into(), "2".into()))
);
assert_eq!(ambiguities.len(), 6);
assert_eq!(find_ambiguities(&stage.exclusive_at_start).len(), 6);
}
}
Loading

0 comments on commit 091f5a8

Please sign in to comment.