From a6b0da2afb11eebd8ab656cb4aebd49092a6c88f Mon Sep 17 00:00:00 2001 From: Afonso Lage Date: Thu, 2 Sep 2021 18:16:18 -0300 Subject: [PATCH 01/42] Number the reported ambiguities, to make them easier to discuss in a team --- crates/bevy_ecs/src/schedule/stage.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/crates/bevy_ecs/src/schedule/stage.rs b/crates/bevy_ecs/src/schedule/stage.rs index 9d5dda4bdf385..b071374467838 100644 --- a/crates/bevy_ecs/src/schedule/stage.rs +++ b/crates/bevy_ecs/src/schedule/stage.rs @@ -478,11 +478,14 @@ impl SystemStage { systems: &[impl SystemContainer], mut ambiguities: Vec<(usize, usize, Vec)>, world: &World, + output_prefix: &str, ) { - for (index_a, index_b, conflicts) in ambiguities.drain(..) { + for (idx, (index_a, index_b, conflicts)) in ambiguities.drain(..).enumerate() { writeln!( string, - " -- {:?} and {:?}", + "{}.{} - {:?} and {:?}", + output_prefix, + idx, systems[index_a].name(), systems[index_b].name() ) @@ -509,30 +512,32 @@ impl SystemStage { add an explicit dependency relation between some of these systems:\n" .to_owned(); if !parallel.is_empty() { - writeln!(string, " * Parallel systems:").unwrap(); - write_display_names_of_pairs(&mut string, &self.parallel, parallel, world); + writeln!(string, "1. Parallel systems:").unwrap(); + write_display_names_of_pairs(&mut string, &self.parallel, parallel, world, "1"); } if !at_start.is_empty() { - writeln!(string, " * Exclusive systems at start of stage:").unwrap(); + writeln!(string, "2. Exclusive systems at start of stage:").unwrap(); write_display_names_of_pairs( &mut string, &self.exclusive_at_start, at_start, world, + "1", ); } if !before_commands.is_empty() { - writeln!(string, " * Exclusive systems before commands of stage:").unwrap(); + writeln!(string, "3. Exclusive systems before commands of stage:").unwrap(); write_display_names_of_pairs( &mut string, &self.exclusive_before_commands, before_commands, world, + "1", ); } if !at_end.is_empty() { - writeln!(string, " * Exclusive systems at end of stage:").unwrap(); - write_display_names_of_pairs(&mut string, &self.exclusive_at_end, at_end, world); + writeln!(string, "4. Exclusive systems at end of stage:").unwrap(); + write_display_names_of_pairs(&mut string, &self.exclusive_at_end, at_end, world,"1"); } info!("{}", string); } From 735abc5e09fc5747305ad237cecd1a0f00aa8421 Mon Sep 17 00:00:00 2001 From: Afonso Lage Date: Thu, 2 Sep 2021 18:28:31 -0300 Subject: [PATCH 02/42] Fixed formatting --- crates/bevy_ecs/src/schedule/stage.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/schedule/stage.rs b/crates/bevy_ecs/src/schedule/stage.rs index b071374467838..7f2f7c7d8d6cf 100644 --- a/crates/bevy_ecs/src/schedule/stage.rs +++ b/crates/bevy_ecs/src/schedule/stage.rs @@ -485,7 +485,7 @@ impl SystemStage { string, "{}.{} - {:?} and {:?}", output_prefix, - idx, + idx, systems[index_a].name(), systems[index_b].name() ) @@ -537,7 +537,13 @@ impl SystemStage { } if !at_end.is_empty() { writeln!(string, "4. Exclusive systems at end of stage:").unwrap(); - write_display_names_of_pairs(&mut string, &self.exclusive_at_end, at_end, world,"1"); + write_display_names_of_pairs( + &mut string, + &self.exclusive_at_end, + at_end, + world, + "1", + ); } info!("{}", string); } From 889dd59957f4b493ba3ee297ae70b703171302ca Mon Sep 17 00:00:00 2001 From: Afonso Lage Date: Thu, 2 Sep 2021 19:35:11 -0300 Subject: [PATCH 03/42] Explain which components/resources the systems are conflicting on. --- crates/bevy_ecs/src/schedule/stage.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/schedule/stage.rs b/crates/bevy_ecs/src/schedule/stage.rs index 7f2f7c7d8d6cf..f9feae630f5b4 100644 --- a/crates/bevy_ecs/src/schedule/stage.rs +++ b/crates/bevy_ecs/src/schedule/stage.rs @@ -483,7 +483,7 @@ impl SystemStage { for (idx, (index_a, index_b, conflicts)) in ambiguities.drain(..).enumerate() { writeln!( string, - "{}.{} - {:?} and {:?}", + "{}.{} - {:?} and {:?} conflicts on the following components/resources:", output_prefix, idx, systems[index_a].name(), @@ -495,7 +495,7 @@ impl SystemStage { .iter() .map(|id| world.components().get_info(*id).unwrap().name()) .collect::>(); - writeln!(string, " conflicts: {:?}", names).unwrap(); + writeln!(string, "{:?}", names).unwrap(); } } } From b1d49ca12813fbf63e97fd3f7eeb5142288b1e3c Mon Sep 17 00:00:00 2001 From: Afonso Lage Date: Thu, 2 Sep 2021 20:04:19 -0300 Subject: [PATCH 04/42] Fixed wrong output_prefix --- crates/bevy_ecs/src/schedule/stage.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ecs/src/schedule/stage.rs b/crates/bevy_ecs/src/schedule/stage.rs index f9feae630f5b4..72f19a0855d1e 100644 --- a/crates/bevy_ecs/src/schedule/stage.rs +++ b/crates/bevy_ecs/src/schedule/stage.rs @@ -522,7 +522,7 @@ impl SystemStage { &self.exclusive_at_start, at_start, world, - "1", + "2", ); } if !before_commands.is_empty() { @@ -532,7 +532,7 @@ impl SystemStage { &self.exclusive_before_commands, before_commands, world, - "1", + "3", ); } if !at_end.is_empty() { @@ -542,7 +542,7 @@ impl SystemStage { &self.exclusive_at_end, at_end, world, - "1", + "4", ); } info!("{}", string); From 1083583b20a9dd75b5f03ba8a79364194f4e9bce Mon Sep 17 00:00:00 2001 From: Afonso Lage Date: Thu, 2 Sep 2021 21:25:21 -0300 Subject: [PATCH 05/42] Report ambiguities where all pairwise combinations of systems conflict on the same data as a group. --- crates/bevy_ecs/src/schedule/stage.rs | 41 ++++++++++++++++++--------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/crates/bevy_ecs/src/schedule/stage.rs b/crates/bevy_ecs/src/schedule/stage.rs index 72f19a0855d1e..c405d24e207c3 100644 --- a/crates/bevy_ecs/src/schedule/stage.rs +++ b/crates/bevy_ecs/src/schedule/stage.rs @@ -480,23 +480,38 @@ impl SystemStage { world: &World, output_prefix: &str, ) { - for (idx, (index_a, index_b, conflicts)) in ambiguities.drain(..).enumerate() { + use std::collections::hash_map; + + let mut ambiguities_map: hash_map::HashMap, Vec> = + hash_map::HashMap::new(); + + for (index_a, index_b, components) in ambiguities.drain(..) { + let systems = ambiguities_map.entry(components).or_default(); + if !systems.contains(&index_a) { + systems.push(index_a); + } + if !systems.contains(&index_b) { + systems.push(index_b); + } + } + + for (idx, (conflicts, systems_indices)) in ambiguities_map.drain().enumerate() { + let system_names = systems_indices + .iter() + .map(|index| systems[*index].name()) + .collect::>(); + + let system_components = conflicts + .iter() + .map(|id| world.components().get_info(*id).unwrap().name()) + .collect::>(); + writeln!( string, - "{}.{} - {:?} and {:?} conflicts on the following components/resources:", - output_prefix, - idx, - systems[index_a].name(), - systems[index_b].name() + "{}.{} - Systems:\n {:?}\n - Conflicts on the following components/resources:\n {:?}", + output_prefix, idx, system_names, system_components ) .unwrap(); - if !conflicts.is_empty() { - let names = conflicts - .iter() - .map(|id| world.components().get_info(*id).unwrap().name()) - .collect::>(); - writeln!(string, "{:?}", names).unwrap(); - } } } let parallel = find_ambiguities(&self.parallel); From cd439afbe54efe6a2927e3d2cbdf7cede0a37225 Mon Sep 17 00:00:00 2001 From: Afonso Lage Date: Fri, 3 Sep 2021 11:15:54 -0300 Subject: [PATCH 06/42] Create a simple ambiguous method that causes a system to be ignored completely in the ambiguity checker. --- crates/bevy_ecs/src/schedule/stage.rs | 38 ++++++++++++++++++- .../bevy_ecs/src/schedule/system_container.rs | 15 ++++++++ .../src/schedule/system_descriptor.rs | 37 ++++++++++++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/schedule/stage.rs b/crates/bevy_ecs/src/schedule/stage.rs index c405d24e207c3..41975aaa6c5fb 100644 --- a/crates/bevy_ecs/src/schedule/stage.rs +++ b/crates/bevy_ecs/src/schedule/stage.rs @@ -16,7 +16,7 @@ use downcast_rs::{impl_downcast, Downcast}; use fixedbitset::FixedBitSet; use std::fmt::Debug; -use super::IntoSystemDescriptor; +use super::{AmbiguityDetection, IntoSystemDescriptor}; pub trait Stage: Downcast + Send + Sync { /// Runs the stage; this happens once per update. @@ -743,6 +743,16 @@ fn find_ambiguities(systems: &[impl SystemContainer]) -> Vec<(usize, usize, Vec< for index_b in full_bitset.difference(&relations) // .take(index_a) { + match systems[index_a].ambiguity_detection() { + AmbiguityDetection::Ignore => continue, + AmbiguityDetection::Check => (), + } + + match systems[index_b].ambiguity_detection() { + AmbiguityDetection::Ignore => continue, + AmbiguityDetection::Check => (), + } + if !processed.contains(index_b) && all_ambiguity_sets[index_a].is_disjoint(&all_ambiguity_sets[index_b]) { @@ -1953,6 +1963,32 @@ mod tests { stage.rebuild_orders_and_dependencies(); let ambiguities = find_ambiguities_first_labels(&stage.exclusive_at_start); assert_eq!(ambiguities.len(), 0); + + let mut stage = SystemStage::parallel() + .with_system(component.label("0")) + .with_system(resource.label("1").after("0").ambiguous()) + .with_system(empty.label("2")) + .with_system(component.label("3").after("2").before("4")) + .with_system(resource.label("4")); + stage.initialize_systems(&mut world); + stage.rebuild_orders_and_dependencies(); + let ambiguities = find_ambiguities_first_labels(&stage.parallel); + assert!( + ambiguities.contains(&(Box::new("0"), Box::new("3"))) + || ambiguities.contains(&(Box::new("3"), Box::new("0"))) + ); + assert_eq!(ambiguities.len(), 1); + + let mut stage = SystemStage::parallel() + .with_system(component.label("0").ambiguous()) + .with_system(resource.label("1").after("0").ambiguous()) + .with_system(empty.label("2")) + .with_system(component.label("3").after("2").before("4")) + .with_system(resource.label("4")); + stage.initialize_systems(&mut world); + stage.rebuild_orders_and_dependencies(); + let ambiguities = find_ambiguities_first_labels(&stage.parallel); + assert_eq!(ambiguities.len(), 0); } #[test] diff --git a/crates/bevy_ecs/src/schedule/system_container.rs b/crates/bevy_ecs/src/schedule/system_container.rs index 68e493da714b5..6ca8c7cf4296e 100644 --- a/crates/bevy_ecs/src/schedule/system_container.rs +++ b/crates/bevy_ecs/src/schedule/system_container.rs @@ -9,6 +9,8 @@ use crate::{ }; use std::{borrow::Cow, cell::UnsafeCell}; +use super::AmbiguityDetection; + /// System metadata like its name, labels, order requirements and component access. pub trait SystemContainer: GraphNode