-
Notifications
You must be signed in to change notification settings - Fork 710
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
Draft benchmark sanity weight test #1493
Conversation
Incident where we needed exactly this: #1589 |
@ggwpez should I still include a flag that can turn the error into a warning? |
Yea maybe something like: |
@Daanvdplas are you still working on this? I'm looking for issues to pick up. |
Yes! I have been blocked for a while but will continue working on it tomorrow! |
@@ -235,7 +238,7 @@ sp_api::decl_runtime_apis! { | |||
/// Parameters | |||
/// - `extra`: Also list benchmarks marked "extra" which would otherwise not be | |||
/// needed for weight calculation. |
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 know the docs here are pretty bad, but could you please explain the return args that you added?
let mut sanity_weight_check_passed = true; | ||
// Loop through all benchmark results. | ||
for ((pallet, instance), results) in all_results.iter() { | ||
println!("Pallet: {}\nInstance: {}\n", pallet, instance); |
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.
Maybe it would make sense to add another level to SanityWeightCheck
: Info
.
Since here you print things that are neither a warning nor an error and are not really important as long as the whole check 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.
I only do not see a reason for only outputting Info
(the above line and weight results, without a warning) when Warning
only adds a warning line above the failing weight results and a line regarding passing / failing the sanity weight check at the end.
If someone would like to inspect its weight results, personally I would like an indicator that clearly indicates which weight function is failing and if no failing weight results I would like formatting that gives a clear view to inspect my weight results. The above line is just to format the sanity weight check results the most clear to my opinion.
Please let me know if I'm understanding your incorrectly and/or what you think of the above :)
return (list, storage_info) | ||
let max_extrinsic_weight = BlockWeights::get().per_class.get(DispatchClass::Normal).max_extrinsic.unwrap(); | ||
let db_weight: frame_support::weights::RuntimeDbWeight = <Self as frame_system::Config>::DbWeight::get(); | ||
(list, storage_info, max_extrinsic_weight, db_weight) |
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 hoped that we could somehow around doing a breaking change for all runtimes, but it seems unavoidable, unless we want to squeeze this into into any of the vectors.
Maybe you can create a single struct that holds the Weight
and RuntimeDbWeight
. Then we can extend that in the future and avoid more breaking changes.
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.
Creating a single struct for Weight
and RuntimeDbWeight
is either way a better solution. Would you prefer to have it included in BenchmarkList
/ StorageInfo
and make it backwards compatible or add an additional parameter which results in a breaking change?
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 it would need one breaking change, yes. But from then on we can avoid further breaking changes by using the following pattern:
struct AllBenchmarkData { // not a good name
list: Vec<frame_benchmarking::BenchmarkList>,
info: Vec<frame_support::traits::StorageInfo>,
max_ext_weight: Option<..>,
db_weights: Option<..>
}
and having Default
on that thing. The runtime devs can use ..Default::default()
to stay forward compatible and we can keep adding Option
s without directly breaking their code.
Nice ! |
// value) and compares it with the max. extrinsic weight allowed in a single block. | ||
// | ||
// `max_extrinsic_weight` & `db_weight` are obtained from the runtime configuration. | ||
pub(crate) fn sanity_weight_check( |
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.
Conceptually, the way to avoid all of these breaking changes is to do this check in the runtime. Is there a reason why it was chosen in the way that it is now?
As in, there is a single new runtime API through which you pass in all the computed weights, and it would do any checking necessary for it.
Ofc this is also a breaking change differently, but possibly an alternative design.
I think the current design is also good, but something to keep in mind.
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.
Reading the code, I guess the runtime also doesn't know the maximum value for each component..
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.
After looking at it again, the component ranges are coming from the runtime actually: parameter list
I'm investigating another approach
total_weight = total_weight.saturating_add( | ||
Weight::from_parts(component.slope.try_into().unwrap(), 0) | ||
.saturating_mul(max_component(&component, &result.component_ranges)), | ||
); |
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.
total_weight = total_weight.saturating_add( | |
Weight::from_parts(component.slope.try_into().unwrap(), 0) | |
.saturating_mul(max_component(&component, &result.component_ranges)), | |
); | |
total_weight.saturating_accrue( | |
Weight::from_parts(component.slope.try_into().unwrap(), 0) | |
.saturating_mul(max_component(&component, &result.component_ranges)), | |
); |
Weight::from_parts(0, component.slope.try_into().unwrap()) | ||
.saturating_mul(max_component(&component, &result.component_ranges)), | ||
); | ||
} |
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.
kinda baffled that all of this math to calculate the final weight of a weight-fn, for a given parameter, needs to be re-created here. Is this really the only place where we have this logic?
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.
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.
All in all looks good, modulo some comments from me and Oliver. I would consider making the default in fact be Warn
or something that lets as many teams out there know about their misconfig.
@chevdor I'm not sure how to determine such |
I am not convinced you can use the remark as reference. |
@chevdor sorry I do not follow what you mean with "previous values", could you kindly elaborate? |
I am afraid my suggestion goes beyond the scope of this PR. |
@Daanvdplas do you intend to finish this? happy to delegate to someone else if otherwise. |
PR also needs a better description that is targeted toward externals rather than internals + prdoc. |
The CI pipeline was cancelled due to failure one of the required jobs. |
still keen on this, but still missing the CI to be green :) |
@philoniare this one could also be a good issue for you 😄 |
Also raising this again as something that we'd be highly interested in having. I would suggest a large tip for the champion to finish this :) |
hey @kianenigma would like to work on this. can you please assign this to me? |
I completed resolving open comments and fixing CI errors. Opened a new PR to this branch since I don't have write access. let me know if you have any more comments |
Closing in fav of the one above. Thank you @Daanvdplas. |
This PR introduces a sanity weight check during the benchmark execution. It checks whether the max weight of a given extrinsic exceeds that of the (
DispatchClass::Normal
)max_extrinsic_weight
obtained from the runtime. The max weight of an extrinsic can be default (no complexity parameter) or else, the max component is used.I have included the
benchmark_sanity_check
in the frame-benchmarking-cli because the component range is available. In addition, a flag:sanity-check
is included to have the cli user choose whether the benchmark execution should fail when themax_extrinsic_weight
exceeds. A warning message will always be printed when themax_extrinsic_weight
is exceeded. Warning example:This is a draft PR to get confirmation on my approach. If approved, things that are left to do:
benchmark_sanity_check
for other benchmark operations than benchmarking a pallet.Closes #152