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

[FVM] Storage check optimisation #2837

Merged
merged 25 commits into from
Jul 27, 2022
Merged

Conversation

janezpodhostnik
Copy link
Contributor

@janezpodhostnik janezpodhostnik commented Jul 20, 2022

Make one storage check for all account at once instead of one per account, reducing the number of ContractFunctionInvocations per transaction.

ref: https://github.com/dapperlabs/flow-go/issues/6308

Depends on cadence runtime.Interface changes from onflow/cadence#1811

Results

The improvement can be seen below in the FVM Benchstat comparison.

All of the benchnet scenarios below check storage of 3 or 4 accounts which is also the most common case on Mainnet.

The touched accounts are:

  • Payer
  • FlowFees
  • FlowToken
  • in case it is a transfer, both the receiver and a sender (but in these bench tests the receiver is always the Payer)

The performance improvement on shorter transactions like RuntimeTransaction/reference_tx-2 is about 15%. Tapering off on long running transactions, where a lot of other things also happens during the transaction. On RuntimeTransaction/transfer_tokens-2 (which does 100 token transfers in 1 transaction between the same 2 users) the benefit is only ~2.5%.

There is one exception, which is RuntimeTransaction/create_new_account this runs about 8% faster even though it is a very long running transaction. The reason for this is that it creates 50 accounts, that all need to be checked for storage in addition to the 3 default ones.

@janezpodhostnik janezpodhostnik added the Execution Cadence Execution Team label Jul 20, 2022
@janezpodhostnik janezpodhostnik self-assigned this Jul 20, 2022
@github-actions
Copy link
Contributor

github-actions bot commented Jul 20, 2022

FVM Benchstat comparison

This branch with compared with the base branch onflow:master commit 5bcb1f3

The command (for i in {1..N}; do go test ./fvm --bench . --tags relic -shuffle=on --benchmem --run ^$; done) was used.

Bench tests were run a total of 10 times on each branch.

Collapsed results for better readability

old.txtnew.txt
time/opdelta
RuntimeTransaction/get_account_and_get_balance-2694ms ± 3%701ms ± 5%~(p=0.356 n=9+10)
RuntimeTransaction/get_account_and_get_available_balance-2587ms ±12%588ms ± 6%~(p=0.796 n=10+10)
RuntimeTransaction/get_account_and_get_storage_capacity-2534ms ± 5%542ms ± 5%~(p=0.400 n=9+10)
RuntimeTransaction/transfer_tokens-2276ms ± 5%280ms ± 5%~(p=0.278 n=10+9)
RuntimeTransaction/borrow_array_from_storage-2153ms ±10%150ms ± 7%~(p=0.481 n=10+10)
RuntimeTransaction/copy_array_from_storage-2154ms ±13%150ms ± 3%~(p=0.968 n=10+9)
RuntimeTransaction/load_and_save_long_string_on_signers_address-298.4ms ± 4%93.6ms ± 3%−4.88%(p=0.000 n=9+10)
RuntimeTransaction/get_signer_receiver-263.0ms ± 3%58.5ms ± 4%−7.13%(p=0.000 n=9+10)
RuntimeNFTBatchTransfer-2151ms ± 1%138ms ± 3%−8.77%(p=0.000 n=7+10)
RuntimeTransaction/emit_event-262.2ms ± 8%56.4ms ± 7%−9.40%(p=0.000 n=10+10)
RuntimeTransaction/load_and_save_empty_string_on_signers_address-248.1ms ± 5%43.0ms ± 5%−10.62%(p=0.000 n=9+10)
RuntimeTransaction/reference_tx-238.7ms ± 6%34.5ms ±19%−10.89%(p=0.010 n=9+10)
RuntimeTransaction/get_signer_vault-248.8ms ± 3%43.5ms ± 5%−11.03%(p=0.000 n=9+9)
RuntimeTransaction/get_account_and_get_storage_used-249.4ms ± 5%43.1ms ± 5%−12.94%(p=0.000 n=10+9)
RuntimeTransaction/get_public_account-243.2ms ± 6%37.4ms ± 5%−13.42%(p=0.000 n=9+10)
RuntimeTransaction/create_new_account-21.40s ± 7%1.18s ± 2%−15.15%(p=0.000 n=10+10)
RuntimeTransaction/convert_int_to_string_and_concatenate_it-242.9ms ± 4%36.3ms ± 3%−15.32%(p=0.000 n=9+9)
RuntimeTransaction/call_empty_contract_function-243.6ms ± 8%36.5ms ± 4%−16.20%(p=0.000 n=10+10)
RuntimeTransaction/get_signer_address-240.1ms ± 6%33.4ms ± 3%−16.87%(p=0.000 n=9+10)
RuntimeTransaction/convert_int_to_string-242.0ms ±18%34.3ms ± 3%−18.31%(p=0.000 n=10+9)
 
alloc/opdelta
RuntimeTransaction/get_account_and_get_balance-2200MB ± 0%198MB ± 0%−0.98%(p=0.000 n=8+10)
RuntimeTransaction/get_account_and_get_available_balance-2150MB ± 0%148MB ± 0%−1.30%(p=0.000 n=7+10)
RuntimeTransaction/get_account_and_get_storage_capacity-2145MB ± 0%143MB ± 0%−1.32%(p=0.000 n=10+10)
RuntimeTransaction/transfer_tokens-250.9MB ± 0%48.7MB ± 0%−4.31%(p=0.000 n=10+10)
RuntimeTransaction/copy_array_from_storage-247.1MB ± 0%45.0MB ± 0%−4.37%(p=0.000 n=10+10)
RuntimeTransaction/borrow_array_from_storage-236.0MB ± 0%33.9MB ± 0%−5.81%(p=0.000 n=10+10)
RuntimeTransaction/load_and_save_long_string_on_signers_address-225.8MB ± 0%23.7MB ± 0%−8.29%(p=0.000 n=8+10)
RuntimeTransaction/get_signer_receiver-215.9MB ± 0%13.8MB ± 0%−13.45%(p=0.000 n=10+10)
RuntimeNFTBatchTransfer-227.8MB ± 0%24.0MB ± 0%−13.79%(p=0.000 n=8+9)
RuntimeTransaction/emit_event-215.1MB ± 1%12.9MB ± 0%−14.42%(p=0.000 n=10+10)
RuntimeTransaction/get_account_and_get_storage_used-212.8MB ± 0%10.6MB ± 1%−16.85%(p=0.000 n=10+10)
RuntimeTransaction/get_signer_vault-212.1MB ± 0%9.9MB ± 0%−18.03%(p=0.000 n=9+10)
RuntimeTransaction/load_and_save_empty_string_on_signers_address-211.6MB ± 0%9.4MB ± 0%−18.64%(p=0.000 n=10+9)
RuntimeTransaction/get_public_account-211.5MB ± 0%9.4MB ± 0%−18.65%(p=0.000 n=10+10)
RuntimeTransaction/convert_int_to_string_and_concatenate_it-210.9MB ± 0%8.7MB ± 0%−19.89%(p=0.000 n=10+10)
RuntimeTransaction/call_empty_contract_function-210.7MB ± 1%8.6MB ± 0%−20.19%(p=0.000 n=10+10)
RuntimeTransaction/create_new_account-2267MB ± 0%212MB ± 0%−20.73%(p=0.000 n=9+10)
RuntimeTransaction/convert_int_to_string-210.4MB ± 0%8.2MB ± 1%−21.12%(p=0.000 n=9+10)
RuntimeTransaction/get_signer_address-210.1MB ± 1%7.9MB ± 0%−21.31%(p=0.000 n=10+10)
RuntimeTransaction/reference_tx-29.86MB ± 1%7.72MB ± 0%−21.78%(p=0.000 n=10+10)
 
allocs/opdelta
RuntimeTransaction/get_account_and_get_balance-23.30M ± 0%3.27M ± 0%−0.89%(p=0.000 n=10+10)
RuntimeTransaction/get_account_and_get_available_balance-22.67M ± 0%2.64M ± 0%−1.06%(p=0.000 n=10+8)
RuntimeTransaction/get_account_and_get_storage_capacity-22.52M ± 0%2.49M ± 0%−1.12%(p=0.000 n=10+10)
RuntimeTransaction/transfer_tokens-21.07M ± 0%1.03M ± 0%−3.02%(p=0.000 n=10+10)
RuntimeTransaction/borrow_array_from_storage-2446k ± 0%414k ± 0%−7.22%(p=0.000 n=10+10)
RuntimeTransaction/copy_array_from_storage-2403k ± 0%370k ± 0%−8.00%(p=0.000 n=10+9)
RuntimeTransaction/load_and_save_long_string_on_signers_address-2303k ± 0%271k ± 0%−10.57%(p=0.000 n=9+10)
RuntimeTransaction/get_signer_receiver-2298k ± 0%265k ± 0%−10.83%(p=0.000 n=10+10)
RuntimeTransaction/emit_event-2219k ± 0%187k ± 0%−14.68%(p=0.000 n=10+10)
RuntimeTransaction/get_account_and_get_storage_used-2214k ± 0%182k ± 0%−15.05%(p=0.000 n=10+10)
RuntimeTransaction/get_signer_vault-2209k ± 0%177k ± 0%−15.43%(p=0.000 n=10+9)
RuntimeTransaction/load_and_save_empty_string_on_signers_address-2207k ± 0%175k ± 0%−15.55%(p=0.000 n=10+10)
RuntimeNFTBatchTransfer-2391k ± 0%327k ± 0%−16.40%(p=0.000 n=8+9)
RuntimeTransaction/get_public_account-2192k ± 0%160k ± 0%−16.75%(p=0.000 n=10+10)
RuntimeTransaction/convert_int_to_string_and_concatenate_it-2184k ± 0%152k ± 0%−17.47%(p=0.000 n=10+10)
RuntimeTransaction/call_empty_contract_function-2173k ± 0%141k ± 0%−18.63%(p=0.000 n=10+10)
RuntimeTransaction/convert_int_to_string-2170k ± 0%138k ± 0%−18.93%(p=0.000 n=10+10)
RuntimeTransaction/create_new_account-24.43M ± 0%3.56M ± 0%−19.70%(p=0.000 n=10+10)
RuntimeTransaction/get_signer_address-2161k ± 0%129k ± 0%−20.00%(p=0.000 n=10+9)
RuntimeTransaction/reference_tx-2156k ± 0%124k ± 0%−20.67%(p=0.000 n=10+10)
 
computationdelta
RuntimeTransaction/reference_tx-2202 ± 0%202 ± 0%~(all equal)
RuntimeTransaction/convert_int_to_string-2402 ± 0%402 ± 0%~(all equal)
RuntimeTransaction/convert_int_to_string_and_concatenate_it-2502 ± 0%502 ± 0%~(all equal)
RuntimeTransaction/get_signer_address-2302 ± 0%302 ± 0%~(all equal)
RuntimeTransaction/get_public_account-2402 ± 0%402 ± 0%~(all equal)
RuntimeTransaction/get_account_and_get_balance-21.00k ± 0%1.00k ± 0%~(all equal)
RuntimeTransaction/get_account_and_get_available_balance-22.50k ± 0%2.50k ± 0%~(all equal)
RuntimeTransaction/get_account_and_get_storage_used-2402 ± 0%402 ± 0%~(all equal)
RuntimeTransaction/get_account_and_get_storage_capacity-21.30k ± 0%1.30k ± 0%~(all equal)
RuntimeTransaction/get_signer_vault-2402 ± 0%402 ± 0%~(all equal)
RuntimeTransaction/get_signer_receiver-2602 ± 0%602 ± 0%~(all equal)
RuntimeTransaction/transfer_tokens-23.50k ± 0%3.50k ± 0%~(all equal)
RuntimeTransaction/load_and_save_empty_string_on_signers_address-2602 ± 0%602 ± 0%~(all equal)
RuntimeTransaction/load_and_save_long_string_on_signers_address-2602 ± 0%602 ± 0%~(all equal)
RuntimeTransaction/create_new_account-2202 ± 0%202 ± 0%~(all equal)
RuntimeTransaction/call_empty_contract_function-2402 ± 0%402 ± 0%~(all equal)
RuntimeTransaction/emit_event-2602 ± 0%602 ± 0%~(all equal)
RuntimeTransaction/borrow_array_from_storage-22.60k ± 0%2.60k ± 0%~(all equal)
RuntimeTransaction/copy_array_from_storage-22.60k ± 0%2.60k ± 0%~(all equal)
 
interactionsdelta
RuntimeTransaction/get_account_and_get_storage_capacity-25.34M ± 0%5.38M ± 0%+0.77%(p=0.000 n=10+10)
RuntimeTransaction/get_account_and_get_available_balance-25.34M ± 0%5.38M ± 0%+0.77%(p=0.000 n=10+10)
RuntimeTransaction/get_account_and_get_balance-216.8M ± 0%16.9M ± 0%+0.49%(p=0.000 n=10+10)
RuntimeTransaction/create_new_account-28.49M ± 0%8.53M ± 0%+0.48%(p=0.000 n=10+10)
RuntimeTransaction/reference_tx-247.8k ± 0%47.8k ± 0%~(all equal)
RuntimeTransaction/convert_int_to_string-247.8k ± 0%47.8k ± 0%~(all equal)
RuntimeTransaction/convert_int_to_string_and_concatenate_it-247.8k ± 0%47.8k ± 0%~(all equal)
RuntimeTransaction/get_signer_address-247.8k ± 0%47.8k ± 0%~(all equal)
RuntimeTransaction/get_public_account-247.8k ± 0%47.8k ± 0%~(all equal)
RuntimeTransaction/get_account_and_get_storage_used-251.4k ± 0%51.4k ± 0%~(all equal)
RuntimeTransaction/get_signer_vault-249.0k ± 0%49.0k ± 0%~(all equal)
RuntimeTransaction/get_signer_receiver-249.4k ± 0%49.4k ± 0%~(all equal)
RuntimeTransaction/transfer_tokens-250.2k ± 0%50.2k ± 0%~(all equal)
RuntimeTransaction/load_and_save_empty_string_on_signers_address-251.2k ± 0%51.2k ± 0%~(all equal)
RuntimeTransaction/load_and_save_long_string_on_signers_address-256.2k ± 0%56.2k ± 0%~(all equal)
RuntimeTransaction/call_empty_contract_function-248.0k ± 0%48.0k ± 0%~(all equal)
RuntimeTransaction/emit_event-248.0k ± 0%48.0k ± 0%~(all equal)
RuntimeTransaction/borrow_array_from_storage-254.1k ± 0%54.1k ± 0%~(all equal)
RuntimeTransaction/copy_array_from_storage-254.1k ± 0%54.1k ± 0%~(all equal)
 

@codecov-commenter
Copy link

codecov-commenter commented Jul 20, 2022

Codecov Report

❗ No coverage uploaded for pull request base (rbtz/OTEL1@5a4bcc8). Click here to learn what that means.
The diff coverage is n/a.

❗ Current head 8c485fd differs from pull request most recent head 38698b5. Consider uploading reports for the commit 38698b5 to get more accurate results

@@              Coverage Diff              @@
##             rbtz/OTEL1    #2837   +/-   ##
=============================================
  Coverage              ?   56.26%           
=============================================
  Files                 ?      690           
  Lines                 ?    63350           
  Branches              ?        0           
=============================================
  Hits                  ?    35641           
  Misses                ?    24725           
  Partials              ?     2984           
Flag Coverage Δ
unittests 56.26% <0.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.


Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5a4bcc8...38698b5. Read the comment docs.

@janezpodhostnik janezpodhostnik changed the base branch from master to supun/cadence-error-refactor July 21, 2022 13:58
@janezpodhostnik janezpodhostnik marked this pull request as ready for review July 21, 2022 14:38
@pattyshack
Copy link
Contributor

looks like you're doing two independent things in the same PR (bumping cadence version & the actual optimization). could you split out the cadence change into a different pr? thx

traceSpan opentracing.Span,
) func(addresses []common.Address) (cadence.Value, error) {
return func(addresses []common.Address) (cadence.Value, error) {
arrayValues := make([]cadence.Value, len(addresses))
Copy link
Contributor

Choose a reason for hiding this comment

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

can we check nil or empty of addresses here to save one invocation if no valid address passed in?

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 am not sure if I want to put this logic here. This is just a wrapper to call the smart contract function. Any conditions like that should be either in the smart contract or better yet (performance wise) in the function calling this one.

I will check that the function calling this one doesn't do it with an empty array.

What do you think?


usage, err := env.GetStorageUsed(commonAddress)
usage, err := env.GetStorageUsed(commonAddresses[i])
Copy link
Contributor

Choose a reason for hiding this comment

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

there's no point in invoking the account storage capacity contract if this fails. maybe collect the usages first in a separate loop (and early exit on error), then invoke the contract and check capacity in this loop.

@Tonix517
Copy link
Contributor

Does existing Benchstat numbers include expected metrics we want? If not, could you publish the metrics before\after this optimization? thanks.

Base automatically changed from supun/cadence-error-refactor to master July 21, 2022 18:07
@janezpodhostnik
Copy link
Contributor Author

@Tonix517 Benchstat numbers do already include the performance comparison here. I added a section to the PR description

fvm/transactionStorageLimiter.go Outdated Show resolved Hide resolved
fvm/transactionStorageLimiter.go Outdated Show resolved Hide resolved
@janezpodhostnik janezpodhostnik changed the base branch from rbtz/cadenceUpdate1 to rbtz/OTEL1 July 25, 2022 19:24
bors bot added a commit that referenced this pull request Jul 25, 2022
2853: [FVM] Update cadence to support Executor pattern r=SaveTheRbtz a=SaveTheRbtz

Factored out cadence update and test fixes out of #2837 so that we can break circular dependency on #2823

Co-authored-by: Janez Podhostnik <janez.podhostnik@gmail.com>

2856: migrate environment to new span api r=pattyshack a=pattyshack



Co-authored-by: Alexey Ivanov <rbtz@dapperlabs.com>
Co-authored-by: Patrick Lee <patrick.lee@dapperlabs.com>
bors bot added a commit that referenced this pull request Jul 25, 2022
2853: [FVM] Update cadence to support Executor pattern r=SaveTheRbtz a=SaveTheRbtz

Factored out cadence update and test fixes out of #2837 so that we can break circular dependency on #2823

Co-authored-by: Janez Podhostnik <janez.podhostnik@gmail.com>

Co-authored-by: Alexey Ivanov <rbtz@dapperlabs.com>
bors bot added a commit that referenced this pull request Jul 26, 2022
2853: [FVM] Update cadence to support Executor pattern r=SaveTheRbtz a=SaveTheRbtz

Factored out cadence update and test fixes out of #2837 so that we can break circular dependency on #2823

Co-authored-by: Janez Podhostnik <janez.podhostnik@gmail.com>

2858: [FVM] cleanup and regenerate mocks r=SaveTheRbtz a=SaveTheRbtz



Co-authored-by: Alexey Ivanov <rbtz@dapperlabs.com>
bors bot added a commit that referenced this pull request Jul 26, 2022
2853: [FVM] Update cadence to support Executor pattern r=SaveTheRbtz a=SaveTheRbtz

Factored out cadence update and test fixes out of #2837 so that we can break circular dependency on #2823

Co-authored-by: Janez Podhostnik <janez.podhostnik@gmail.com>

Co-authored-by: Alexey Ivanov <rbtz@dapperlabs.com>
@SaveTheRbtz SaveTheRbtz force-pushed the rbtz/OTEL1 branch 2 times, most recently from 5e27e69 to 93370c8 Compare July 26, 2022 05:13
Base automatically changed from rbtz/OTEL1 to master July 26, 2022 06:05
@SaveTheRbtz
Copy link
Contributor

#2853 has landed. You can rebase on top of master now.

@bluesign
Copy link
Contributor

maybe naive question, but why don't you filter this list with storage_used ? You should be able to skip a lot of checks where storage_used < N ( N = minimimAccountBalance granted storage ~ 100Kb)

@janezpodhostnik
Copy link
Contributor Author

@bluesign the minimum account balance is defined in the state, so getting it requires a call to GetValue.

A GetValue call is expensive, but not as expensive as a Contract function invocation. With the previous approach fetching minimum account balance once would definitely make sense, but with this approach (only one Contract function invocation) I'm not sure it does. In some cases (the failure ones) this would mean that the check is faster, but the happy path would be a bit longer because of it.

@janezpodhostnik
Copy link
Contributor Author

bors merge

@bors
Copy link
Contributor

bors bot commented Jul 27, 2022

Build succeeded:

@bors bors bot merged commit 3a75f47 into master Jul 27, 2022
@bors bors bot deleted the janez/storage-check-optimisation branch July 27, 2022 16:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Execution Cadence Execution Team Performance
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants