-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
Simple improvements to ambiguity reporting clarity #2766
Simple improvements to ambiguity reporting clarity #2766
Conversation
Thanks a ton for doing this! This should help a ton. @davidscherer @concavesphere I'd love reviews from you two on this once it's ready; I think this will be a very nice incremental improvement to a friendlier scheduler. |
I wasn't able to find a reliable way to get the system signature as stated in task "Display function signatures of conflicting systems.". Rust doesn't provide a way to get function signature and I wasn't able to do so using bevy internals. The most acceptable way was using pub fn camera_system<T: CameraProjection + Component>(
mut window_resized_events: EventReader<WindowResized>,
mut window_created_events: EventReader<WindowCreated>,
windows: Res<Windows>,
mut queries: QuerySet<(
QueryState<(Entity, &mut Camera, &mut T)>,
QueryState<Entity, Added<Camera>>,
)>,
) { is reported as:
If anyone knows a reliable way to reconstruct or get the system function signature, I'll be happy to address the task 2. |
…ompletely in the ambiguity checker.
…ent ambiguity sets without being forced to invent an ambiguity set label.
The current implementation of task 7 (Provide an "X unresolved ambiguities detected" message that runs by default) currently produces the following output:
This isn't very descriptive for new users, but I wasn't able to find a way to get the current stage label, so we would need to add this information on The following code currently produces the mentioned warnings: use bevy::prelude::*;
fn main() {
env_logger::init();
App::new()
.add_plugins(DefaultPlugins)
.insert_resource(MyStartupResource(0))
.add_startup_system(startup_system_a)
.add_startup_system(startup_system_b)
.insert_resource(MyParallelResource(0))
.add_system(parallel_system_a)
.add_system(parallel_system_b)
.run();
}
struct MyStartupResource(i32);
fn startup_system_a(mut res: ResMut<MyStartupResource>) {
res.0 += 1;
}
fn startup_system_b(mut res: ResMut<MyStartupResource>) {
res.0 += 1;
}
struct MyParallelResource(i32);
fn parallel_system_a(mut res: ResMut<MyParallelResource>) {
res.0 += 1;
}
fn parallel_system_b(mut res: ResMut<MyParallelResource>) {
res.0 += 1;
} |
The main work is done, waiting for reviews. I'll just add those changes on |
@@ -45,7 +52,39 @@ impl_downcast!(Stage); | |||
/// | |||
/// The checker may report a system more times than the amount of constraints it would actually need | |||
/// to have unambiguous order with regards to a group of already-constrained systems. | |||
pub struct ReportExecutionOrderAmbiguities; | |||
pub struct ReportExecutionOrderAmbiguities { | |||
level: AmbiguityReportLevel, |
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.
I would be fine just exposing this field directly. That would save on boilerplate and the enum will give us a type-safe API.
Is there some reason why this isn't safe?
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.
On the latest commit, I made it public, so users which wanna more control over ReportExecutionOrderAmbiguities
may create the resource directly. I've also kept the .off()
, .minimal()
and .verbose()
to keep things easier to user (at least I think so)
pub struct ReportExecutionOrderAmbiguities {
pub level: AmbiguityReportLevel,
pub ignore_crates: Vec<String>,
}
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.
I've also kept the .off(), .minimal() and .verbose() to keep things easier to user (at least I think so)
I'd like to avoid API duplication where possible. I'd definitely accept it if Cart feels otherwise in a final review though, so don't worry about it for now.
I think everything is done, I'll set it as ready for review. I've added an example also. For reference, here is the output of the example:
|
} | ||
|
||
/// Adds the given crates to be ignored by ambiguity checker. Check [`ReportExecutionOrderAmbiguities`] for more details. | ||
pub fn ignore(mut self, create_prefix: &[&str]) -> Self { |
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.
I think this should take a single string instead of a list. We could also have an "ignore_all" function that takes an iterator.
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.
Done. Renamed this one to ignore_all
and added a new one ignore
which just takes a single &str
pub ignore_crates: Vec<String>, | ||
} | ||
|
||
const BEVY_CRATES: [&str; 109] = [ |
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.
Having thought about this a bit more, I think this is moving us in the wrong direction for a number of reasons:
- Moves "bevy engine" crate info "upstream" into
bevy_ecs
, which should be standalone - Compiles a big list of strings into bevy_ecs binaries
- Centralizes what should be decentralized
I personally think we should remove this list in favor of each individual crate calling ambiguities.ignore("CRATE_NAME_HERE")
if we agree that ambiguities should be ignored for a given crate.
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.
Clever. I think this is the best path forward here.
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.
Fair points, but since the ignored crates list are stored in a resource, all crates should have a startup system which will add their crate names to it?
Also, we should add this to all bevy internal crates or only the ones which already have ambiguities reported?
And lastly, is on the scope of this PR add this info on all needed crates (I can do it, just wanna organize)?
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.
Fair points, but since the ignored crates list are stored in a resource, all crates should have a startup system which will add their crate names to it?
I think it should be a part of Plugin init (prior to the schedule running).
Also, we should add this to all bevy internal crates or only the ones which already have ambiguities reported?
Yeah I think this is the right call. It encourages us to be more precise about suppressing these. It also cuts down on the amount of work we're doing at startup.
And lastly, is on the scope of this PR add this info on all needed crates (I can do it, just wanna organize)?
Whatever works best for you!
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.
Done. I've added the ignore call on following plugins:
- bevy_audio
- bevy_render
- bevy_sprite
- bevy_text
- bevy_ui
- bevy_transform
- bevy_winit
The only "trick" part is if users add the ReportExecutionOrderAmbiguities
after adding DefaultPlugins
or so, the default ignored crates will be overwritten. I've added this on docs and on example, informing users that if they need to customize the resource, it must be done before the plugins
…s, bevy_text, bevy_ui, bevy_transform, bevy_winit
… doesn't exists anymore
Maybe I'll need that help again with the spelling 😃 |
What to do when the CI fails with a code that I haven't touched?
|
That was already fixed by #2811 and can thus be ignored. |
@@ -90,6 +90,12 @@ impl IntoSystemDescriptor<()> for ExclusiveSystemCoerced { | |||
} | |||
} | |||
|
|||
pub enum AmbiguityDetection { |
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.
This should have a default value.
bors try |
tryMerge conflict. |
@afonsolage; I'd like to try and get this merged early next week. Are you able to fix up the few remaining issues and makes sure CI passes? |
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.
- Report ambiguities where all pairwise combinations of systems conflict on the same data as a group.
This change (as implemented) makes things less clear (increasingly so with larger stages).
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::<Vec<_>>(); | ||
|
||
let system_components = conflicts | ||
.iter() | ||
.map(|id| world.components().get_info(*id).unwrap().name()) | ||
.collect::<Vec<_>>(); |
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.
While it makes for fewer warning messages, "all systems that have a conflict involving T
" is not the same as "all systems that conflict on T
".
Reporting this way will make it harder to parse which systems actually conflict (which was obvious before), since not all systems being grouped together are actually running at the same time.
I think you maybe intended for "all systems that conflict on T
at the same time" but I don't think that's easy to solve.
(edit: I also prefer how we currently report pairs with all their conflicts.)
Closing in favor of the rebased #4299, which builds on this work. @afonsolage: thank you so, so much for this contribution, I'm very excited to see it in the engine. |
Objective
Simple improvements to ambiguity reporting clarity, as discussed on #1484.
Fixes #1484
Solution
2. Display function signatures of conflicting systems.(see Simple improvements to ambiguity reporting clarity #2766 (comment))