Skip to content

Commit

Permalink
Merge pull request #1015 from oasisprotocol/jberci/feature/gas-costs
Browse files Browse the repository at this point in the history
Update gas costs
  • Loading branch information
jberci committed Oct 6, 2022
2 parents 7b57df2 + bfe85a3 commit 2c5f24d
Show file tree
Hide file tree
Showing 19 changed files with 1,933 additions and 106 deletions.
78 changes: 77 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 11 additions & 6 deletions client-sdk/go/modules/contracts/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,12 +300,17 @@ type GasCosts struct {

SubcallDispatch uint64 `json:"subcall_dispatch"`

WASMStorageGetBase uint64 `json:"wasm_storage_get_base"`
WASMStorageInsertBase uint64 `json:"wasm_storage_insert_base"`
WASMStorageRemoveBase uint64 `json:"wasm_storage_remove_base"`
WASMStorageKeyByte uint64 `json:"wasm_storage_key_byte"`
WASMStorageValueByte uint64 `json:"wasm_storage_value_byte"`
WASMEnvQueryBase uint64 `json:"wasm_env_query_base"`
WASMPublicStorageGetBase uint64 `json:"wasm_public_storage_get_base"`
WASMPublicStorageInsertBase uint64 `json:"wasm_public_storage_insert_base"`
WASMPublicStorageRemoveBase uint64 `json:"wasm_public_storage_remove_base"`
WASMPublicStorageKeyByte uint64 `json:"wasm_public_storage_key_byte"`
WASMPublicStorageValueByte uint64 `json:"wasm_public_storage_value_byte"`
WASMConfidentialStorageGetBase uint64 `json:"wasm_confidential_storage_get_base"`
WASMConfidentialStorageInsertBase uint64 `json:"wasm_confidential_storage_insert_base"`
WASMConfidentialStorageRemoveBase uint64 `json:"wasm_confidential_storage_remove_base"`
WASMConfidentialStorageKeyByte uint64 `json:"wasm_confidential_storage_key_byte"`
WASMConfidentialStorageValueByte uint64 `json:"wasm_confidential_storage_value_byte"`
WASMEnvQueryBase uint64 `json:"wasm_env_query_base"`

WASMCryptoECDSARecover uint64 `json:"wasm_crypto_ecdsa_recover"`
WASMCryptoSignatureVerifyEd25519 uint64 `json:"wasm_crypto_signature_verify_ed25519"`
Expand Down
5 changes: 5 additions & 0 deletions runtime-sdk/modules/contracts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ walrus = "0.19.0"

[dev-dependencies]
wat = "1.0"
k256 = { version = "0.9.6", default-features = false, features = ["keccak256", "ecdsa"] }
hex = "0.4.2"
wasmprinter = "0.2.41"
pretty_assertions = "1.3.0"

[features]
debug-utils = []
benchmarks = [] # Enable inline benchmarks for use with `cargo bench`.
76 changes: 76 additions & 0 deletions runtime-sdk/modules/contracts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Gas Cost Derivation

The `wasm_*` gas cost defaults as defined in this crate are derived from
the relative performance of various WASM instructions and the linked-in
functions provided by the Runtime SDK.

To replicate, start by running benchmarks from the top of the cargo
workspace:

# To run all benchmarks:
$ cargo bench --features benchmarks -- --nocapture
# To run only the cost-related wasm benchmarks:
$ cargo bench --features benchmarks -p oasis-runtime-sdk-contracts -- --nocapture wasm

The `--nocapture` flag to the test runner is needed due to the two
single-run benchmarks (the signature verification compiled to WASM and
the time waster test), which print some run statistics to stdout --
these serve as a baseline for what is possible within a given amount of
time.

## Instruction Costs

To determine the cost function for single instructions, examine the
`bench_loop_*` statistics in the `wasm` module. `add` is one of the
simplest instructions and is taken as a base for all other instructions;
its cost is fixed to 1.

The benchmarks are written such that they differ in as few instructions
as possible. While not perfect, the relative performance should serve as
a rule of thumb for how much gas/time their respective instructions
cost. The `bench_loop_*_skel` tests show approximately how much time is
taken by the skeleton of each type of benchmark -- the difference
between these and the instruction-specific ones show how much a given
sequence of instructions takes to execute.

Note that the instruction benchmarks include repetition on two levels:
the WASM code executes the main body in a loop, and the function call
into WASM itself is repeated by the `Bencher` class.

The total gas usage expected to be possible during computation for a
single block can then be derived from the time waster benchmark, meant
to run for roughly the time of one block. The amount of gas used for
that benchmark gives an optimistic upper limit, since the instructions
making it up are simple arithmetic, comparisons and calls (all
relatively cheap instructions). An appropriate gas limit can be
determined from it by applying some margin to allow for speed variations
and other uncertainties as desired (for the defaults here, the
assumption was to take a quarter of the measurement; half to approximate
actual block time and another half as margin).

## Operation Costs

Based on the set gas usage limit per block and the expected real time
available to the contract per block, check the storage and crypto
benchmarks in the `abi::oasis` module.

The crypto benchmarks provide an estimation of how much slower a
WASM-native signature verification would be compared to the
implementation provided by the SDK (`called_from_wasm_included` vs.
`computed_in_wasm`) as well as how the SDK-provided functions compare to
one another (the other benchmarks).

Similarly, the storage benchmarks provide an estimation for how the
three MKVS store operations perform relative to each other and how much
the overhead is to call an operation from WASM (including copying bytes
to and from instance memory).

Regarding the difference between public and confidential storage, refer
to the benchmarks in the `oasis_runtime_sdk` package, in the
`storage::confidential` module.

For guidance regarding per-byte costs for storage operations, see the
storage waster benchmark
(`abi::oasis::storage::test::bench_wasm_reach_gas_limit`). This tests
how much storage can be used up in a single block given a set of
default-constructed gas costs.

0 comments on commit 2c5f24d

Please sign in to comment.