Skip to content
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

Improves benchmarks for pallet parachain-staking #2317

Merged
merged 19 commits into from
Jun 6, 2023

Conversation

nbaztec
Copy link
Contributor

@nbaztec nbaztec commented May 29, 2023

What does it do?

fixes staking benchmarks to account for worst case weight and possbily refund the excess.

⚠️ Breaking Change ⚠️

❗ Block Underutilization

The PR changes certain staking benchmark which has a direct effect on how many of these transaction types can fit in a block.
Note that this causes block underutilization since we overestimate the weight for these extrinsics.
img

MAX_CANDIDATES benchmark limit

The staking benchmarks utilize a theoretical limit of 200 max candidates, which at the moment IS NOT enforced in the code. However, this is scheduled to be included soon in a subsequent PR. This is purely to compute the

What important points reviewers should know?

Is there something left for follow-up PRs?

What alternative implementations were considered?

Are there relevant PRs or issues in other repositories (Substrate, Polkadot, Frontier, Cumulus)?

What value does it bring to the blockchain users?

@nbaztec nbaztec added B7-runtimenoteworthy Changes should be noted in any runtime-upgrade release notes D9-needsaudit👮 PR contains changes to fund-managing logic that should be properly reviewed and externally audited breaking Needs to be mentioned in breaking changes labels May 29, 2023
@librelois librelois mentioned this pull request May 30, 2023
24 tasks
// Measured: `27979`
// Estimated: `193037`
// Minimum execution time: 131_740_000 picoseconds.
Weight::from_parts(134_429_600, 193037)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

significant 2x ref time, 6x pov_size

Copy link
Contributor

Choose a reason for hiding this comment

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

Did ref time go up because the benchmark is SCALE decoding more items? Or is there more to it than that?

// Measured: `37308`
// Estimated: `330557`
// Minimum execution time: 168_083_000 picoseconds.
Weight::from_parts(168_083_000, 330557)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

significant 2x ref time, 10x pov_size

// Measured: `29930`
// Estimated: `238138`
// Minimum execution time: 137_954_000 picoseconds.
Weight::from_parts(137_954_000, 238138)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

significant 4x ref time, 4x pov_size

// Measured: `48167`
// Estimated: `426257`
// Minimum execution time: 275_279_000 picoseconds.
Weight::from_parts(275_279_000, 426257)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

significant for delegate weight. May not fit in a block.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As per ts-tests we are now able to fit at most 9 delegate calls (was ~50 before).

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this is true only for the worstcase scenario, which test ?

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 added https://github.com/PureStake/moonbeam/pull/2317/files#diff-007387d2d904cb5a8973816c45ce9b11bbfc8c095d0075798fd625ef0a260141R15 which showed the max txs fit within the block.

Since we're overestimating, the block utilization is affected negatively and the test helps us visualize how much.
Results: #2317 (comment) & #2317 (comment)

// Measured: `15515`
// Estimated: `37960`
// Minimum execution time: 55_538_000 picoseconds.
Weight::from_parts(58_365_791, 37960)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

significant 2x ref time, 5x pov_size

// Measured: `27979`
// Estimated: `193037`
// Minimum execution time: 131_740_000 picoseconds.
Weight::from_parts(134_429_600, 193037)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

significant 2x ref time, 6x pov_size

// Measured: `15515`
// Estimated: `37960`
// Minimum execution time: 56_573_000 picoseconds.
Weight::from_parts(58_214_753, 37960)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

significant 2x ref time, 5x pov_size

// Measured: `29930`
// Estimated: `238138`
// Minimum execution time: 137_954_000 picoseconds.
Weight::from_parts(137_954_000, 238138)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

significant 4x ref time, 4x pov_size

@@ -1133,64 +1075,32 @@ pub mod pallet {

/// Temporarily leave the set of collator candidates without unbonding
#[pallet::call_index(11)]
#[pallet::weight(<T as Config>::WeightInfo::go_offline())]
#[pallet::weight(<T as Config>::WeightInfo::go_offline(1_000))]
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the long term solution for this limit? We could define yet-another runtime config for the max, then it could be safely enforced and used as an upper bound here.

Copy link
Contributor

Choose a reason for hiding this comment

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

You could do the same but without a runtime constant (just define a complile-time one). I would suggest using a constant here instead of a magic number anyway.

The question is: do we want to enforce it when joining candidates? It could be used as a DoS vector...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah that would be my choice as well.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I would enforce it when joining, but we have to clearly state that limit in the breaking changes

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 added https://github.com/PureStake/moonbeam/pull/2317/files#diff-007387d2d904cb5a8973816c45ce9b11bbfc8c095d0075798fd625ef0a260141R15 which showed the max txs fit within the block.

Since we're overestimating, the block utilization is affected negatively and the test helps us visualize how much.
Results: #2317 (comment) & #2317 (comment)

.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(x.into())))
.saturating_add(T::DbWeight::get().writes(1_u64))
.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(x.into())))
.saturating_add(Weight::from_parts(0, 31269).saturating_mul(x.into()))
Copy link
Contributor

Choose a reason for hiding this comment

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

I think 31269.saturating_mul(x) is going to be problematic here because x = 100 in our runtimes and 31_269 * 100 is way too close to our block limit.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

One thing to note is that, we have deprecated these methods in favor of batch schedule revoke, so perhaps it's alright for it to have a high enough weight to incentivize people to move away from it.

Additionally now that I notice it this functionality has already passed 6 months of time and should be marked for removal #1760

@github-actions
Copy link
Contributor

github-actions bot commented May 31, 2023

Coverage generated "Mon Jun 5 11:34:18 UTC 2023":
https://s3.amazonaws.com/moonbeam-coverage/pulls/2317/html/index.html

Master coverage: 70.87%
Pull coverage: 70.91%

notlesh and others added 2 commits May 31, 2023 20:49
* Properly use scaling parameter in benchmarks

* Include updated weights

* Undo execute_leave_delegators_worst changes
@nbaztec
Copy link
Contributor Author

nbaztec commented Jun 1, 2023

@notlesh I added the benchmark test (conditional). Let me know if there's any other extrinsics you'd wanna see up there

image

@notlesh
Copy link
Contributor

notlesh commented Jun 1, 2023

@notlesh I added the benchmark test (conditional). Let me know if there's any other extrinsics you'd wanna see up there

Interesting, I got slightly different results -- maybe it is highly dependent on hardware (which wouldn't surprise me):

image

cb: (context: DevTestContext) => Promise<void>
) {
describeDevMoonbeam(`${title} - ${method}`, (context) => {
it("should fit minimum 2", async function () {
Copy link
Contributor

Choose a reason for hiding this comment

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

We could parameterize this (2) and make these a permanent test. It might add a lot of time to the tests, though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There's a conditional env variable STAKING_BENCHMARK=1 that is checked whether or not to run this test, but I'm all up for parameterizing if it adds value.

@notlesh
Copy link
Contributor

notlesh commented Jun 1, 2023

f4a91db adds weight and proof normal class utilization metrics to the output. It's pretty telling:

image

Notice that weight is very underutilized, and also that scheduleLeaveDelegators doesn't seem to use either metric fully.

@nbaztec
Copy link
Contributor Author

nbaztec commented Jun 2, 2023

f4a91db adds weight and proof normal class utilization metrics to the output. It's pretty telling:

image

Notice that weight is very underutilized, and also that scheduleLeaveDelegators doesn't seem to use either metric fully.

Yeah this is a common theme here, certain "old" extrinsics do not have a weigh hint parameter and were historically underestimating the weight. Currently we assume in the upfront weight that a delegator is having MaxDelegationsPerDelegator which we refund afterwards, and also that all of these delegations are towards collators that have their scheduled requests (Top + Bottom) full upto the brim.

Copy link
Collaborator

@crystalin crystalin 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.
Can you answer some of the questions left please?
Also please open a ticket for each follow-up tasks that are mentioned in the discussion or the code.

Awesome work !

tests/tests/test-staking/test-rewards-auto-compound.ts Outdated Show resolved Hide resolved
@@ -59,7 +59,14 @@ describeDevMoonbeam("Staking - Consts - MaxDelegationsPerDelegator", (context) =
context.createBlock(
randomCandidatesChunk.map((randomCandidate) =>
context.polkadotApi.tx.parachainStaking
.delegate(randomCandidate.address, MIN_GLMR_DELEGATOR, 1, maxDelegationsPerDelegator)
.delegateWithAutoCompound(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Any reason this was changed to autocompound and not the other delegates (like the previous ) ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Probably missed it changing it back, initially the chunks were failing with Transaction Ancient error since the txs were generated before the createBlock and we could only fit at most 8, so I was instead using delegateWithAutoCompound since the delegate method is set for removal now (I didn't wanna remove it in this PR). I can change it back and generate tx within the chunk but it's pretty inconsequential since the next RT should effectively swap out all delegate calls with delegateWithAutoCompound

@nbaztec
Copy link
Contributor Author

nbaztec commented Jun 5, 2023

Created

/cc @notlesh think I was wrong we never marked delegate as deprecated so we unfortunately cannot remove it soon, do you see any issues related to removing it in December?

@notlesh
Copy link
Contributor

notlesh commented Jun 5, 2023

do you see any issues related to removing it in December?

Seems fine to me

@crystalin crystalin merged commit 3e0c95c into master Jun 6, 2023
26 checks passed
@crystalin crystalin deleted the nish-staking-new-benchmarks branch June 6, 2023 09:53
@crystalin crystalin changed the title staking new benchmarks Improves benchmarks for pallet parachain-staking Jun 15, 2023
@notlesh notlesh added D1-audited👍 PR contains changes to fund-managing logic that has been properly reviewed and externally audited and removed D9-needsaudit👮 PR contains changes to fund-managing logic that should be properly reviewed and externally audited labels Jul 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B7-runtimenoteworthy Changes should be noted in any runtime-upgrade release notes breaking Needs to be mentioned in breaking changes D1-audited👍 PR contains changes to fund-managing logic that has been properly reviewed and externally audited
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants