-
Notifications
You must be signed in to change notification settings - Fork 131
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
Update submit finality proof weight formula #981
Conversation
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.
Final results (weighs) are on the "common prefix" sheet of this document.
So something that's still unclear to me is how you're calculating the "actual" column here
I've dropped these parameters from the weight formula - we may try to re-add them later, but for now I haven't found a way to use them (spent 1.5 days on that) + seems that they are not affecting total weight that much.
Yeah, that's fine imo
I've computed approximate cost of submit_finality_proof on the Kusama chain where (I hope) we'll see ~1024*2/3+1 precommits and near to 2 ancestors - the cost is near to 0.37 KSM, given weights that I've computed on my laptop. Initially I've got ~0.2, but I haven't considered forks back then. Hopefully, after updating weights on reference machine, we'll have better results.
If you're running these on a laptop then yeah, this should probably go down by at least half
I've also left JustificationGeneratorParams::common_ancestors field to show what the c parameter represents in the document above. Could remove it if required, but I feel that we may use it later for optimizing the formula (to refund submitter if some forks had duplicate headers => AncestryChain::is_descendant was executed faster).
I think we should drop in. If later on we want to do optimizations we can add it back then
modules/grandpa/src/benchmarking.rs
Outdated
let p in 1..MAX_VALIDATOR_SET_SIZE; | ||
|
||
let v = 1; |
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.
Why are you holding this fixed at v = 1
instead of holding it at MAX_VALIDATOR_SET_SIZE
, or even sweeping through the range? Each of these choices will give us different weights for each additional item
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.
Because there's another benchmark which is responsible for that. This benchmark must build weight(p)
. And while building weight(p)
I don't care about number of headers in the votes ancestry. So here I'm interested in additional weight that comes with additional signature verification + some of the loop checks. With that new custom justification validation there's a guarantee that every header in the ancestry will be only visited once (this doesn't include one additional visit per precommit, weight for which is added here). So we may use formula like that a*A + b*B
. Benchmarks are responsible for computing A
/B
.
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.
So wasn't part of the initial problem here that different values of p
/v
would have different impacts depending on the size of the other variable?
E.g with v=1
every additional p
increases the weights by X
, while with v=1000
every additional p
increases the weights by X + C
?
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.
Yes. Take a look at the new verification code, please - all that happens with ancestry is: (1) every header is hashed and inserted into btree (this is accounted y the weight_per_additional_unique_ancestor
) (2) zero or one header is accessed for every precommit (accounted by weight_per_additional_precommit
) (3) every header in the valid justification is accessed at most one time (accounted by weight_per_additional_unique_ancestor
). So while both parameters are still used inside one loop, it doesn't mean anymore that the weight formula should look something like p*v*W
. Look at the attached doc - if what you're saying was the true, then the formula wouldn't fit that good for both small and large values of (p, v)
.
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 agree with you, the formula shouldn't look like p*v*W
. What it should look like is A*p + B*v
.
What I'm trying to say here is that the values of A
and B
will be different depending on the values of p
and v
used when running the benchmarks. Depending on if we fix v=1
or v=1000
the corresponding constants will be different - so what should we choose?
By executing benchmark with |
Okay so basically what you're doing here is running the benchmarks with submit_finality_proof {
let v in 1..8192;
let p = 1..8192;
let caller: T::AccountId = whitelisted_caller();
let (header, justification) = prepare_benchmark_data::<T, I>(p, v);
}: _(RawOrigin::Signed(caller), header, justification) With If that's the case, given that the actual and computed weights are almost the same, why not just use the actual weight directly? |
No, I'm not doing that. I'm running benchmarks from this file
That's not the case. If I would use benchmarks which iterates both So what must be remembered is that you can only build fn call(origin, p1: u64, p2: u64) {
for _ in 0..p1 {
// do something totally unrelated to the next loop
}
for _ in 0..p2 {
// do something totally unrelated to the previous loop
} If they're used in a single loop, or if they may affect what's happen in the other loop, then single benchmark isn't a good idea. UPD: actually I'm not sure how benchmarking would work in this example ^^^ above. Probably I've made a mistake and actually |
So I know the benchmarks you included weren't run as I said, but the "actual" benches look like what I proposed (imo anyways).
Yeah, that's intentional. The benchmarking framework is trying to compute the weight based off the worst-case scenario, which in our case would be
I don't think you're totally off here. As I said, the bench framework will use |
So I ran the following benchmarks. They're a combination your "actual" benchmarks, the benchmarks you're using for calculations, and my proposed weight calculation. Using the resulting weight.rs output I then plugged them into a spreadsheet as you've done.
So I don't think we need to go through the trouble of deriving some calculated benchmark result if we can use the actual results directly. |
c85feff
to
638638f
Compare
Ok, I've changed to single benchmark. Your results, however, show that the computed result would always be less than actual, which I wanted to avoid. But if you feels that's the correct way - here you are |
Why were you trying to avoid that? The differences, especially at higher values of
I'm not trying to impose my will on you here, I'm just trying to understand the different approaches and presenting what I think is simpler and equally accurate. If you disagree that's fine - let's work through it. We're both trying to work towards the same goal 😄 |
I wanted to avoid that because weight represents computation time. If weight formula returns weight that is less than actual, it would mean that block production may take a longer-than-expected time. In worst case, iiuc, it means missing the slot and slashing. I agree that the single benchmark shows quite accurate results - honestly, I was assuming that it'll behave much worse. Simply because this base weight ( |
(I forgot it is a draft :/ ) |
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.
Looks good! Let me just re-run the benchmarks on standardized hardware.
@tomusdrw any updates with the benches? |
* Move XCM configurations out into its own module * Revert removal of the AccountNonceApi
* updated weight formula for submit_finality_proof * remove common prefix traces * update docs * single benchmark * Re-generate weights. * Update delivery transaction limits Co-authored-by: Tomasz Drwięga <tomasz@parity.io> Co-authored-by: Hernando Castano <hernando@hcastano.com>
* updated weight formula for submit_finality_proof * remove common prefix traces * update docs * single benchmark * Re-generate weights. * Update delivery transaction limits Co-authored-by: Tomasz Drwięga <tomasz@parity.io> Co-authored-by: Hernando Castano <hernando@hcastano.com>
on top of #979 => draft
the only new commit is 6ed0641
Final results (weighs) are on the "common prefix" sheet of this document. There are 4 weight-related parameters in this document -
p
andv
+c
andf
. Thef
parameter represents the number of forks in the precommits ancestry and thec
is the number of shared (among all forks) ancestors. In the end, I've dropped these parameters from the weight formula - we may try to re-add them later, but for now I haven't found a way to use them (spent 1.5 days on that) + seems that they are not affecting total weight that much.From results, you may see that the largest (in percents) error (computed vs actual weight) is 11.5% for the case
(p=2, v=16)
. The larger are parameters (p
andv
), the less is error. On real chains, we'll be seeing justifications that are near to(p=512, v=2)
and(p=1024, v=2)
where error is ~1.4%.I've computed approximate cost of
submit_finality_proof
on the Kusama chain where (I hope) we'll see ~1024*2/3+1 precommits and near to2
ancestors - the cost is near to0.37
KSM, given weights that I've computed on my laptop. Initially I've got ~0.2
, but I haven't considered forks back then. Hopefully, after updating weights on reference machine, we'll have better results.I've also left
JustificationGeneratorParams::common_ancestors
field to show what thec
parameter represents in the document above. Could remove it if required, but I feel that we may use it later for optimizing the formula (to refund submitter if some forks had duplicate headers =>AncestryChain::is_descendant
was executed faster).