Skip to content

Better warnings about invalid parameters #15500

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
merged 14 commits into from
Oct 3, 2024

Conversation

MiniaczQ
Copy link
Contributor

@MiniaczQ MiniaczQ commented Sep 28, 2024

Objective

System param validation warnings should be configurable and default to "warn once" (per system).

Fixes: #15391

Solution

SystemMeta is given a new ParamWarnPolicy field.
The policy decides whether warnings will be emitted by each system param when it fails validation.
The policy is updated by the system after param validation fails.

Example warning:

2024-09-30T18:10:04.740749Z  WARN bevy_ecs::system::function_system: System fallible_params::do_nothing_fail_validation will not run because it requested inaccessible system parameter Single<(), (With<Player>, With<Enemy>)>

Currently, only the first invalid parameter is displayed.

Warnings can be disabled on function systems using .param_never_warn().
(there is also .with_param_warn_policy(policy))

Testing

Ran fallible_params example.

@MiniaczQ MiniaczQ added C-Feature A new feature, making something new possible A-ECS Entities, components, systems, and events S-Blocked This cannot move forward until something else changes X-Uncontroversial This work is generally agreed upon labels Sep 28, 2024
@MiniaczQ MiniaczQ added this to the 0.15 milestone Sep 28, 2024
@alice-i-cecile alice-i-cecile added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Blocked This cannot move forward until something else changes labels Sep 28, 2024
@MiniaczQ MiniaczQ force-pushed the better-validate-warnings branch from cd2fe8d to 0bd22bb Compare September 28, 2024 19:56
@MiniaczQ MiniaczQ marked this pull request as ready for review September 28, 2024 20:12
@MiniaczQ MiniaczQ added S-Needs-Review Needs reviewer attention (from anyone!) to move forward and removed S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Sep 28, 2024
@BenjaminBrienen BenjaminBrienen added the D-Straightforward Simple bug fixes and API improvements, docs, test and examples label Sep 28, 2024
@MiniaczQ
Copy link
Contributor Author

I've noticed some problems with this approach, I'll be reworking it

@MiniaczQ MiniaczQ added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Sep 29, 2024
@MiniaczQ MiniaczQ force-pushed the better-validate-warnings branch from d217110 to 8e2c754 Compare September 30, 2024 00:43
@MiniaczQ MiniaczQ added D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes X-Contentious There are nontrivial implications that should be thought through and removed D-Straightforward Simple bug fixes and API improvements, docs, test and examples X-Uncontroversial This work is generally agreed upon labels Sep 30, 2024
github-merge-queue bot pushed a commit that referenced this pull request Sep 30, 2024
…15526)

# Objective

Fixes #15394

## Solution

Observers now validate params.

System registry has a new error variant for when system running fails
due to invalid parameters.

Run once now returns a `Result<Out, RunOnceError>` instead of `Out`.
This is more inline with system registry, which also returns a result.

I'll address warning messages in #15500.

## Testing

Added one test for each case.

---

## Migration Guide

- `RunSystemOnce::run_system_once` and
`RunSystemOnce::run_system_once_with` now return a `Result<Out>` instead
of just `Out`

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
@MiniaczQ MiniaczQ force-pushed the better-validate-warnings branch from c12cb04 to 5f1cdb5 Compare September 30, 2024 01:32
@MiniaczQ MiniaczQ marked this pull request as ready for review September 30, 2024 02:17
@SpecificProtagonist
Copy link
Contributor

SpecificProtagonist commented Sep 30, 2024

Trying to construct a worst-case benchmark, where the systems do no work and there are no parameters to validate or extract:

let mut world = World::new();
let mut schedule = Schedule::default();
for _ in 0..1000 {
    schedule.add_systems(|| ());
}
for _ in 0..1000000 {
    schedule.run(&mut world);
}
With bevy_param_warn:
  Time (mean ± σ):     13.639 s ±  0.147 s    [User: 13.590 s, System: 0.025 s]
  Range (min … max):   13.484 s … 13.982 s    10 runs

Without:
  Time (mean ± σ):     13.817 s ±  0.196 s    [User: 13.772 s, System: 0.025 s]
  Range (min … max):   13.539 s … 14.250 s    10 runs

So there's about a standard deviation difference. But if these numbers were precise, the feature flag would allow removing 0.178ns per system. I don't think that's worth it.

@MiniaczQ
Copy link
Contributor Author

Thank you for your work, I'll remove the flag when im home :)

Copy link
Contributor

@chescock chescock left a comment

Choose a reason for hiding this comment

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

So the warning is now emitted from the param itself, which lets you include the param type in the message. And the warning state is stored on the system, which saves space and is easier to configure. As a consequence, if a system has multiple failing parameters, it only warns on the first one, right? That all seems reasonable, although the final result is a little surprising.

@MiniaczQ
Copy link
Contributor Author

MiniaczQ commented Sep 30, 2024

if a system has multiple failing parameters, it only warns on the first one, right?

The policy update of a (function) system happens after param validation fails.
But param validation of tuples, etc. currently short circuits, so yes
you will only see the first missing type.

While we can remove the short circuit, this won't patch a hole where missing parameters can change over time and we'll still only get warning about the first one (time-wise).

I guess we could store the warning per system param??
But then routing all the configuration will be hellish

Copy link
Contributor

@bushrat011899 bushrat011899 left a comment

Choose a reason for hiding this comment

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

Looks good to me, love the idea of giving more meaningful feedback to the user without spamming them needlessly. I have a note about a possible future PR, but definitely doesn't need to be in this PR.

/// No warning should ever be emitted.
Never,
/// The warning will be emitted once and status will update to [`Self::Never`].
Once,
Copy link
Contributor

Choose a reason for hiding this comment

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

Future PR: Seems reasonable to add an Always policy as well:

/// State machine for emitting warnings when [system params are invalid](System::validate_param).
#[derive(Clone, Copy)]
pub enum ParamWarnPolicy {
    /// No warning should ever be emitted.
    Never,
    /// The warning will be emitted once and status will update to [`Self::Never`].
    Once,
    /// The warning will be emitted each time the system is run.
    Always,
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I had it but removed it as per previous feedback.
I think Always will be a bit too annoying, but we could certainly use more complex policies:

  • system just stopped running (prev frame valid, this frame invalid)
  • invalid params changed

If we get some higher level logging with editor, we can do stuff like:

  • system X stopped running at frame N because of invalid param P and is still not running till frame M

@bushrat011899 bushrat011899 added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Oct 2, 2024
Copy link
Contributor

@SpecificProtagonist SpecificProtagonist left a comment

Choose a reason for hiding this comment

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

Hm, I don't think we have a good way to test whether the right things get logged?

btw the PR description still mentions bevy_param_warn

Anyway, the implementation is looking good to me!

@alice-i-cecile alice-i-cecile added this pull request to the merge queue Oct 3, 2024
Merged via the queue into bevyengine:main with commit acea4e7 Oct 3, 2024
26 checks passed
ItsDoot pushed a commit to ItsDoot/bevy that referenced this pull request Oct 4, 2024
# Objective

System param validation warnings should be configurable and default to
"warn once" (per system).

Fixes: bevyengine#15391

## Solution

`SystemMeta` is given a new `ParamWarnPolicy` field.
The policy decides whether warnings will be emitted by each system param
when it fails validation.
The policy is updated by the system after param validation fails.

Example warning:
```
2024-09-30T18:10:04.740749Z  WARN bevy_ecs::system::function_system: System fallible_params::do_nothing_fail_validation will not run because it requested inaccessible system parameter Single<(), (With<Player>, With<Enemy>)>
```

Currently, only the first invalid parameter is displayed.

Warnings can be disabled on function systems using
`.param_never_warn()`.
(there is also `.with_param_warn_policy(policy)`)

## Testing

Ran `fallible_params` example.

---------

Co-authored-by: SpecificProtagonist <vincentjunge@posteo.net>
robtfm pushed a commit to robtfm/bevy that referenced this pull request Oct 4, 2024
…evyengine#15526)

# Objective

Fixes bevyengine#15394

## Solution

Observers now validate params.

System registry has a new error variant for when system running fails
due to invalid parameters.

Run once now returns a `Result<Out, RunOnceError>` instead of `Out`.
This is more inline with system registry, which also returns a result.

I'll address warning messages in bevyengine#15500.

## Testing

Added one test for each case.

---

## Migration Guide

- `RunSystemOnce::run_system_once` and
`RunSystemOnce::run_system_once_with` now return a `Result<Out>` instead
of just `Out`

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
robtfm pushed a commit to robtfm/bevy that referenced this pull request Oct 4, 2024
# Objective

System param validation warnings should be configurable and default to
"warn once" (per system).

Fixes: bevyengine#15391

## Solution

`SystemMeta` is given a new `ParamWarnPolicy` field.
The policy decides whether warnings will be emitted by each system param
when it fails validation.
The policy is updated by the system after param validation fails.

Example warning:
```
2024-09-30T18:10:04.740749Z  WARN bevy_ecs::system::function_system: System fallible_params::do_nothing_fail_validation will not run because it requested inaccessible system parameter Single<(), (With<Player>, With<Enemy>)>
```

Currently, only the first invalid parameter is displayed.

Warnings can be disabled on function systems using
`.param_never_warn()`.
(there is also `.with_param_warn_policy(policy)`)

## Testing

Ran `fallible_params` example.

---------

Co-authored-by: SpecificProtagonist <vincentjunge@posteo.net>
github-merge-queue bot pushed a commit that referenced this pull request Mar 24, 2025
…ia the GLOBAL_ERROR_HANDLER (#18454)

# Objective

There are two related problems here:

1. Users should be able to change the fallback behavior of *all*
ECS-based errors in their application by setting the
`GLOBAL_ERROR_HANDLER`. See #18351 for earlier work in this vein.
2. The existing solution (#15500) for customizing this behavior is high
on boilerplate, not global and adds a great deal of complexity.

The consensus is that the default behavior when a parameter fails
validation should be set based on the kind of system parameter in
question: `Single` / `Populated` should silently skip the system, but
`Res` should panic. Setting this behavior at the system level is a
bandaid that makes getting to that ideal behavior more painful, and can
mask real failures (if a resource is missing but you've ignored a system
to make the Single stop panicking you're going to have a bad day).

## Solution

I've removed the existing `ParamWarnPolicy`-based configuration, and
wired up the `GLOBAL_ERROR_HANDLER`/`default_error_handler` to the
various schedule executors to properly plumb through errors .

Additionally, I've done a small cleanup pass on the corresponding
example.

## Testing

I've run the `fallible_params` example, with both the default and a
custom global error handler. The former panics (as expected), and the
latter spams the error console with warnings 🥲

## Questions for reviewers

1. Currently, failed system param validation will result in endless
console spam. Do you want me to implement a solution for warn_once-style
debouncing somehow?
2. Currently, the error reporting for failed system param validation is
very limited: all we get is that a system param failed validation and
the name of the system. Do you want me to implement improved error
reporting by bubbling up errors in this PR?
3. There is broad consensus that the default behavior for failed system
param validation should be set on a per-system param basis. Would you
like me to implement that in this PR?

My gut instinct is that we absolutely want to solve 2 and 3, but it will
be much easier to do that work (and review it) if we split the PRs
apart.

## Migration Guide

`ParamWarnPolicy` and the `WithParamWarnPolicy` have been removed
completely. Failures during system param validation are now handled via
the `GLOBAL_ERROR_HANDLER`: please see the `bevy_ecs::error` module docs
for more information.

---------

Co-authored-by: MiniaczQ <xnetroidpl@gmail.com>
mockersf pushed a commit that referenced this pull request Mar 25, 2025
…ia the GLOBAL_ERROR_HANDLER (#18454)

There are two related problems here:

1. Users should be able to change the fallback behavior of *all*
ECS-based errors in their application by setting the
`GLOBAL_ERROR_HANDLER`. See #18351 for earlier work in this vein.
2. The existing solution (#15500) for customizing this behavior is high
on boilerplate, not global and adds a great deal of complexity.

The consensus is that the default behavior when a parameter fails
validation should be set based on the kind of system parameter in
question: `Single` / `Populated` should silently skip the system, but
`Res` should panic. Setting this behavior at the system level is a
bandaid that makes getting to that ideal behavior more painful, and can
mask real failures (if a resource is missing but you've ignored a system
to make the Single stop panicking you're going to have a bad day).

I've removed the existing `ParamWarnPolicy`-based configuration, and
wired up the `GLOBAL_ERROR_HANDLER`/`default_error_handler` to the
various schedule executors to properly plumb through errors .

Additionally, I've done a small cleanup pass on the corresponding
example.

I've run the `fallible_params` example, with both the default and a
custom global error handler. The former panics (as expected), and the
latter spams the error console with warnings 🥲

1. Currently, failed system param validation will result in endless
console spam. Do you want me to implement a solution for warn_once-style
debouncing somehow?
2. Currently, the error reporting for failed system param validation is
very limited: all we get is that a system param failed validation and
the name of the system. Do you want me to implement improved error
reporting by bubbling up errors in this PR?
3. There is broad consensus that the default behavior for failed system
param validation should be set on a per-system param basis. Would you
like me to implement that in this PR?

My gut instinct is that we absolutely want to solve 2 and 3, but it will
be much easier to do that work (and review it) if we split the PRs
apart.

`ParamWarnPolicy` and the `WithParamWarnPolicy` have been removed
completely. Failures during system param validation are now handled via
the `GLOBAL_ERROR_HANDLER`: please see the `bevy_ecs::error` module docs
for more information.

---------

Co-authored-by: MiniaczQ <xnetroidpl@gmail.com>
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-Feature A new feature, making something new possible D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it X-Contentious There are nontrivial implications that should be thought through
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Logging for system parameter validation should be configurable
6 participants