5

Is there any best practice how to count the weights in on_initialize correctly?

I read through the Polkadot and Substrate on_initialize weight calculations and couldn't always figure out: When to benchmark? When to use benchmark components? When to use manual read and write additions?


Just an example here. There the length of Leases was not taken into account of the weight benchmark.


In regards to benchmark components: Why does the component MaxApprovals affect the weight here?


Why do we return 0 weight here, when there was at least the calculation of (n % T::SpendPeriod::get()).is_zero() (which also should consume a little bit processing time)?


This is a pretty good example, that the length of Approvals affect the weight and should be a component.


Here only T::DbWeight::get(). is used. But isn't there some processing time for the assert call? Why wasn't benchmarking taken into account there? When using this style. Why couldn't I just use T::DbWeight::get().reads_writes(proposals_approvals_len, proposals_approvals_len) here?


I count the following reads_writes in on_initialize and on_finalize here:

READS: StoragePeriod, ChunkCount, ProofChecked (take), BlockTransactions

WRITES: Transactions, ChunkCount, ProofChecked (take), BlockTransactions

But it is T::DbWeight::get().reads_writes(2, 4), why?


I would expect T::DbWeight::get().writes(1) here. Why it only takes the weight of check_xcm_version_change into the overall weight?


Can you provide any best practices how to correctly count the weights of on_initialize?

1 Answer 1

3

I will try to answer most of the Qs.

When to benchmark? When to use manual read and write additions?

The short answer: use benchmarks and not manual guesstimates for hooks' weights.
I can't really justify the practice since its error-prone and breaks easily.

When to use benchmark components?

I think your observations are correct. Benchmarking components should be used when the weight has a dependency on the size or length of a specific value.
There are obviously bugs in the code; developers don't always take all variables into account or a later amendment invalidates it.

One exception exists for storage. The storage weights are benchmarked with a full snapshot and therefore always worst case. So you don't have to populate all maps every time you write a benchmark.

Why do we return 0 weight here, when there was at least the calculation of (n % T::SpendPeriod::get()).is_zero() (which also should consume a little bit processing time)?

Yes ideally this should have a benchmark. The effort for this is currently ignored.
The scheduler pallet has a lot of on_initialize benchmarks if you need inspiration.

Can you provide any best practices how to correctly count the weights of on_initialize?

Best not to do it.
Anyway, a relay chain will not really suffer from slightly incorrect weights since its blocks always execute. Sure there could be longer block times, but then it can be fixed.
For a para-chain this is not a good idea, since a grossly overweight on_initialize could lead collators to miss their block production slot and stall the chain.

I will go through your posted cases and open an issue (link: TBD).

2
  • Are the storage weights also benchmarked in a snapshot for a parachain? So do I need as parachain developer need to think about the weight of a child tree access for example? According to this github.com/paritytech/polkadot/issues/5928
    – Chralt
    Aug 25, 2022 at 15:10
  • Parachains should benchmark their own storage weights instead of using the Polkadot defaults, yet. The procedure is not nicely explained yet, but most is covered here. Related issue: #12081. The weights are defined here. Aug 25, 2022 at 15:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.