Add benchmarking for compute units usage (#2466)
This commit is contained in:
parent
2e89b79c51
commit
5910dd3e2f
|
@ -437,6 +437,8 @@ jobs:
|
|||
path: tests/anchor-cli-idl
|
||||
- cmd: cd tests/anchor-cli-account && anchor test --skip-lint
|
||||
path: tests/anchor-cli-account
|
||||
- cmd: cd tests/bench && anchor test --skip-lint
|
||||
path: tests/bench
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/setup/
|
||||
|
|
|
@ -15,12 +15,15 @@ The minor version will be incremented upon a breaking change and the patch versi
|
|||
- spl: Add metadata wrappers `approve_collection_authority`, `bubblegum_set_collection_size`, `burn_edition_nft`, `burn_nft`, `revoke_collection_authority`, `set_token_standard`, `utilize`, `unverify_sized_collection_item`, `unverify_collection` ([#2430](https://github.com/coral-xyz/anchor/pull/2430))
|
||||
- spl: Add `token_program` constraint to `Token`, `Mint`, and `AssociatedToken` accounts in order to override required `token_program` fields and use different token interface implementations in the same instruction ([#2460](https://github.com/coral-xyz/anchor/pull/2460))
|
||||
- cli: Add support for Solidity programs. `anchor init` and `anchor new` take an option `--solidity` which creates solidity code rather than rust. `anchor build` and `anchor test` work accordingly ([#2421](https://github.com/coral-xyz/anchor/pull/2421))
|
||||
- bench: Add benchmarking for compute units usage ([#2466](https://github.com/coral-xyz/anchor/pull/2466))
|
||||
|
||||
### Fixes
|
||||
|
||||
- ts: Narrowed `AccountClient` type to it's appropriate account type ([#2440](https://github.com/coral-xyz/anchor/pull/2440))
|
||||
- lang: Fix inability to use identifiers `program_id`, `accounts`, `ix_data`, `remaining_accounts` in instruction arguments ([#2464](https://github.com/coral-xyz/anchor/pull/2464))
|
||||
|
||||
### Breaking
|
||||
|
||||
- lang: Identifiers that are intended for internal usage(`program_id`, `accounts`, `ix_data`, `remaining_accounts`) have been renamed with `__` prefix ([#2464](https://github.com/coral-xyz/anchor/pull/2464))
|
||||
|
||||
## [0.27.0] - 2023-03-08
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
# Compute Units
|
||||
|
||||
All notable changes in compute units usage will be documented in this file.
|
||||
|
||||
The changes are calculated by comparing the current results with the last version's results. Increase in usage is shown with 🔴 and decrease is shown with 🟢.
|
||||
|
||||
The programs and their tests are located in [/tests/bench](https://github.com/coral-xyz/anchor/tree/master/tests/bench).
|
||||
|
||||
> **Note**
|
||||
> The results documented in this file are autogenerated. Running the tests will update the current results when necessary, manually editing the results should be avoided.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
| Instruction | Compute Units | +/- |
|
||||
| --------------------------- | ------------- | --- |
|
||||
| accountInfo1 | 954 | - |
|
||||
| accountInfo2 | 1567 | - |
|
||||
| accountInfo4 | 2059 | - |
|
||||
| accountInfo8 | 3856 | - |
|
||||
| accountEmptyInit1 | 5958 | - |
|
||||
| accountEmpty1 | 1090 | - |
|
||||
| accountEmptyInit2 | 10583 | - |
|
||||
| accountEmpty2 | 1852 | - |
|
||||
| accountEmptyInit4 | 19557 | - |
|
||||
| accountEmpty4 | 2646 | - |
|
||||
| accountEmptyInit8 | 37541 | - |
|
||||
| accountEmpty8 | 5043 | - |
|
||||
| accountSizedInit1 | 6063 | - |
|
||||
| accountSized1 | 1135 | - |
|
||||
| accountSizedInit2 | 10783 | - |
|
||||
| accountSized2 | 1966 | - |
|
||||
| accountSizedInit4 | 19975 | - |
|
||||
| accountSized4 | 2787 | - |
|
||||
| accountSizedInit8 | 38381 | - |
|
||||
| accountSized8 | 5359 | - |
|
||||
| accountUnsizedInit1 | 6193 | - |
|
||||
| accountUnsized1 | 1243 | - |
|
||||
| accountUnsizedInit2 | 11042 | - |
|
||||
| accountUnsized2 | 1893 | - |
|
||||
| accountUnsizedInit4 | 20495 | - |
|
||||
| accountUnsized4 | 3104 | - |
|
||||
| accountUnsizedInit8 | 39419 | - |
|
||||
| accountUnsized8 | 6051 | - |
|
||||
| boxedAccountEmptyInit1 | 6160 | - |
|
||||
| boxedAccountEmpty1 | 976 | - |
|
||||
| boxedAccountEmptyInit2 | 10784 | - |
|
||||
| boxedAccountEmpty2 | 1499 | - |
|
||||
| boxedAccountEmptyInit4 | 19500 | - |
|
||||
| boxedAccountEmpty4 | 2530 | - |
|
||||
| boxedAccountEmptyInit8 | 37415 | - |
|
||||
| boxedAccountEmpty8 | 4780 | - |
|
||||
| boxedAccountSizedInit1 | 6256 | - |
|
||||
| boxedAccountSized1 | 1003 | - |
|
||||
| boxedAccountSizedInit2 | 10975 | - |
|
||||
| boxedAccountSized2 | 1554 | - |
|
||||
| boxedAccountSizedInit4 | 19884 | - |
|
||||
| boxedAccountSized4 | 2642 | - |
|
||||
| boxedAccountSizedInit8 | 38182 | - |
|
||||
| boxedAccountSized8 | 5003 | - |
|
||||
| boxedAccountUnsizedInit1 | 6374 | - |
|
||||
| boxedAccountUnsized1 | 1069 | - |
|
||||
| boxedAccountUnsizedInit2 | 11211 | - |
|
||||
| boxedAccountUnsized2 | 1679 | - |
|
||||
| boxedAccountUnsizedInit4 | 20351 | - |
|
||||
| boxedAccountUnsized4 | 2899 | - |
|
||||
| boxedAccountUnsizedInit8 | 39118 | - |
|
||||
| boxedAccountUnsized8 | 5517 | - |
|
||||
| boxedInterfaceAccountMint1 | 2299 | - |
|
||||
| boxedInterfaceAccountMint2 | 4053 | - |
|
||||
| boxedInterfaceAccountMint4 | 7538 | - |
|
||||
| boxedInterfaceAccountMint8 | 14699 | - |
|
||||
| boxedInterfaceAccountToken1 | 1737 | - |
|
||||
| boxedInterfaceAccountToken2 | 2928 | - |
|
||||
| boxedInterfaceAccountToken4 | 5291 | - |
|
||||
| boxedInterfaceAccountToken8 | 10205 | - |
|
||||
| interfaceAccountMint1 | 2530 | - |
|
||||
| interfaceAccountMint2 | 4726 | - |
|
||||
| interfaceAccountMint4 | 9431 | - |
|
||||
| interfaceAccountMint8 | 17709 | - |
|
||||
| interfaceAccountToken1 | 1755 | - |
|
||||
| interfaceAccountToken2 | 3211 | - |
|
||||
| interfaceAccountToken4 | 6006 | - |
|
||||
| interface1 | 999 | - |
|
||||
| interface2 | 1574 | - |
|
||||
| interface4 | 1996 | - |
|
||||
| interface8 | 3651 | - |
|
||||
| program1 | 999 | - |
|
||||
| program2 | 1573 | - |
|
||||
| program4 | 1998 | - |
|
||||
| program8 | 3651 | - |
|
||||
| signer1 | 958 | - |
|
||||
| signer2 | 1576 | - |
|
||||
| signer4 | 2079 | - |
|
||||
| signer8 | 3895 | - |
|
||||
| systemAccount1 | 1013 | - |
|
||||
| systemAccount2 | 1686 | - |
|
||||
| systemAccount4 | 2298 | - |
|
||||
| systemAccount8 | 4336 | - |
|
||||
| uncheckedAccount1 | 953 | - |
|
||||
| uncheckedAccount2 | 1567 | - |
|
||||
| uncheckedAccount4 | 2060 | - |
|
||||
| uncheckedAccount8 | 3855 | - |
|
||||
|
||||
### Notable changes
|
||||
|
||||
---
|
||||
|
||||
## [0.27.0]
|
||||
|
||||
| Instruction | Compute Units | +/- |
|
||||
| --------------------------- | ------------- | --- |
|
||||
| accountInfo1 | 954 | N/A |
|
||||
| accountInfo2 | 1567 | N/A |
|
||||
| accountInfo4 | 2059 | N/A |
|
||||
| accountInfo8 | 3856 | N/A |
|
||||
| accountEmptyInit1 | 5958 | N/A |
|
||||
| accountEmpty1 | 1090 | N/A |
|
||||
| accountEmptyInit2 | 10574 | N/A |
|
||||
| accountEmpty2 | 1852 | N/A |
|
||||
| accountEmptyInit4 | 19557 | N/A |
|
||||
| accountEmpty4 | 2646 | N/A |
|
||||
| accountEmptyInit8 | 37541 | N/A |
|
||||
| accountEmpty8 | 5043 | N/A |
|
||||
| accountSizedInit1 | 6063 | N/A |
|
||||
| accountSized1 | 1135 | N/A |
|
||||
| accountSizedInit2 | 10783 | N/A |
|
||||
| accountSized2 | 1966 | N/A |
|
||||
| accountSizedInit4 | 19975 | N/A |
|
||||
| accountSized4 | 2787 | N/A |
|
||||
| accountSizedInit8 | 38381 | N/A |
|
||||
| accountSized8 | 5359 | N/A |
|
||||
| accountUnsizedInit1 | 6193 | N/A |
|
||||
| accountUnsized1 | 1243 | N/A |
|
||||
| accountUnsizedInit2 | 11042 | N/A |
|
||||
| accountUnsized2 | 1893 | N/A |
|
||||
| accountUnsizedInit4 | 20495 | N/A |
|
||||
| accountUnsized4 | 3104 | N/A |
|
||||
| accountUnsizedInit8 | 39419 | N/A |
|
||||
| accountUnsized8 | 6051 | N/A |
|
||||
| boxedAccountEmptyInit1 | 6160 | N/A |
|
||||
| boxedAccountEmpty1 | 976 | N/A |
|
||||
| boxedAccountEmptyInit2 | 10784 | N/A |
|
||||
| boxedAccountEmpty2 | 1499 | N/A |
|
||||
| boxedAccountEmptyInit4 | 19500 | N/A |
|
||||
| boxedAccountEmpty4 | 2530 | N/A |
|
||||
| boxedAccountEmptyInit8 | 37415 | N/A |
|
||||
| boxedAccountEmpty8 | 4780 | N/A |
|
||||
| boxedAccountSizedInit1 | 6256 | N/A |
|
||||
| boxedAccountSized1 | 1003 | N/A |
|
||||
| boxedAccountSizedInit2 | 10975 | N/A |
|
||||
| boxedAccountSized2 | 1554 | N/A |
|
||||
| boxedAccountSizedInit4 | 19884 | N/A |
|
||||
| boxedAccountSized4 | 2642 | N/A |
|
||||
| boxedAccountSizedInit8 | 38182 | N/A |
|
||||
| boxedAccountSized8 | 5003 | N/A |
|
||||
| boxedAccountUnsizedInit1 | 6374 | N/A |
|
||||
| boxedAccountUnsized1 | 1069 | N/A |
|
||||
| boxedAccountUnsizedInit2 | 11211 | N/A |
|
||||
| boxedAccountUnsized2 | 1679 | N/A |
|
||||
| boxedAccountUnsizedInit4 | 20351 | N/A |
|
||||
| boxedAccountUnsized4 | 2899 | N/A |
|
||||
| boxedAccountUnsizedInit8 | 39118 | N/A |
|
||||
| boxedAccountUnsized8 | 5517 | N/A |
|
||||
| boxedInterfaceAccountMint1 | 2299 | N/A |
|
||||
| boxedInterfaceAccountMint2 | 4053 | N/A |
|
||||
| boxedInterfaceAccountMint4 | 7538 | N/A |
|
||||
| boxedInterfaceAccountMint8 | 14699 | N/A |
|
||||
| boxedInterfaceAccountToken1 | 1737 | N/A |
|
||||
| boxedInterfaceAccountToken2 | 2928 | N/A |
|
||||
| boxedInterfaceAccountToken4 | 5291 | N/A |
|
||||
| boxedInterfaceAccountToken8 | 10205 | N/A |
|
||||
| interfaceAccountMint1 | 2530 | N/A |
|
||||
| interfaceAccountMint2 | 4726 | N/A |
|
||||
| interfaceAccountMint4 | 9431 | N/A |
|
||||
| interfaceAccountMint8 | 17709 | N/A |
|
||||
| interfaceAccountToken1 | 1755 | N/A |
|
||||
| interfaceAccountToken2 | 3211 | N/A |
|
||||
| interfaceAccountToken4 | 6006 | N/A |
|
||||
| interface1 | 999 | N/A |
|
||||
| interface2 | 1574 | N/A |
|
||||
| interface4 | 1996 | N/A |
|
||||
| interface8 | 3651 | N/A |
|
||||
| program1 | 999 | N/A |
|
||||
| program2 | 1573 | N/A |
|
||||
| program4 | 1998 | N/A |
|
||||
| program8 | 3651 | N/A |
|
||||
| signer1 | 958 | N/A |
|
||||
| signer2 | 1576 | N/A |
|
||||
| signer4 | 2079 | N/A |
|
||||
| signer8 | 3895 | N/A |
|
||||
| systemAccount1 | 1013 | N/A |
|
||||
| systemAccount2 | 1686 | N/A |
|
||||
| systemAccount4 | 2298 | N/A |
|
||||
| systemAccount8 | 4336 | N/A |
|
||||
| uncheckedAccount1 | 953 | N/A |
|
||||
| uncheckedAccount2 | 1567 | N/A |
|
||||
| uncheckedAccount4 | 2060 | N/A |
|
||||
| uncheckedAccount8 | 3855 | N/A |
|
||||
|
||||
---
|
|
@ -0,0 +1,15 @@
|
|||
[provider]
|
||||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
bench = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
|
||||
[workspace]
|
||||
members = ["programs/bench"]
|
||||
|
||||
[scripts]
|
||||
test = "yarn run ts-mocha -t 1000000 -p ./tsconfig.json -t 1000000 tests/**/*.ts"
|
||||
update-bench = "yarn run ts-node scripts/update-bench.ts"
|
||||
generate-ix = "yarn run ts-node scripts/generate-ix.ts"
|
||||
bump-version = "yarn run ts-node scripts/bump-version.ts"
|
|
@ -0,0 +1,4 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"programs/*"
|
||||
]
|
|
@ -0,0 +1,27 @@
|
|||
# Benchmark tests
|
||||
|
||||
The bench program and its tests are used to measure the performance of Anchor programs.
|
||||
|
||||
## How
|
||||
|
||||
Create a program -> Write tests that measure usage -> Compare the results -> Save the new result
|
||||
|
||||
The script will check whether there is a difference between the current result and the last saved result(in `bench.json`) at the end of the tests. If the difference between the results is greater than 1%, the new data will be saved in `bench.json` and Markdown files in [/bench](https://github.com/coral-xyz/anchor/tree/master/bench) will be updated accordingly.
|
||||
|
||||
## Scripts
|
||||
|
||||
`anchor test --skip-lint`: Run all tests and update benchmark files when necessary. This is the only command that needs to be run for most use cases.
|
||||
|
||||
---
|
||||
|
||||
The following scripts are useful when making changes to how benchmarking works.
|
||||
|
||||
`anchor run update-bench`: Update Markdown files in [/bench](https://github.com/coral-xyz/anchor/tree/master/bench) based on the data from `bench.json`.
|
||||
|
||||
`anchor run generate-ix`: Generate instructions with repetitive accounts.
|
||||
|
||||
---
|
||||
|
||||
The following script is only for the maintainer(s) of Anchor.
|
||||
|
||||
`anchor run bump-version -- <VERSION>`: Bump the version in all benchmark files.
|
|
@ -0,0 +1,184 @@
|
|||
{
|
||||
"0.27.0": {
|
||||
"computeUnits": {
|
||||
"accountInfo1": 954,
|
||||
"accountInfo2": 1567,
|
||||
"accountInfo4": 2059,
|
||||
"accountInfo8": 3856,
|
||||
"accountEmptyInit1": 5958,
|
||||
"accountEmpty1": 1090,
|
||||
"accountEmptyInit2": 10574,
|
||||
"accountEmpty2": 1852,
|
||||
"accountEmptyInit4": 19557,
|
||||
"accountEmpty4": 2646,
|
||||
"accountEmptyInit8": 37541,
|
||||
"accountEmpty8": 5043,
|
||||
"accountSizedInit1": 6063,
|
||||
"accountSized1": 1135,
|
||||
"accountSizedInit2": 10783,
|
||||
"accountSized2": 1966,
|
||||
"accountSizedInit4": 19975,
|
||||
"accountSized4": 2787,
|
||||
"accountSizedInit8": 38381,
|
||||
"accountSized8": 5359,
|
||||
"accountUnsizedInit1": 6193,
|
||||
"accountUnsized1": 1243,
|
||||
"accountUnsizedInit2": 11042,
|
||||
"accountUnsized2": 1893,
|
||||
"accountUnsizedInit4": 20495,
|
||||
"accountUnsized4": 3104,
|
||||
"accountUnsizedInit8": 39419,
|
||||
"accountUnsized8": 6051,
|
||||
"boxedAccountEmptyInit1": 6160,
|
||||
"boxedAccountEmpty1": 976,
|
||||
"boxedAccountEmptyInit2": 10784,
|
||||
"boxedAccountEmpty2": 1499,
|
||||
"boxedAccountEmptyInit4": 19500,
|
||||
"boxedAccountEmpty4": 2530,
|
||||
"boxedAccountEmptyInit8": 37415,
|
||||
"boxedAccountEmpty8": 4780,
|
||||
"boxedAccountSizedInit1": 6256,
|
||||
"boxedAccountSized1": 1003,
|
||||
"boxedAccountSizedInit2": 10975,
|
||||
"boxedAccountSized2": 1554,
|
||||
"boxedAccountSizedInit4": 19884,
|
||||
"boxedAccountSized4": 2642,
|
||||
"boxedAccountSizedInit8": 38182,
|
||||
"boxedAccountSized8": 5003,
|
||||
"boxedAccountUnsizedInit1": 6374,
|
||||
"boxedAccountUnsized1": 1069,
|
||||
"boxedAccountUnsizedInit2": 11211,
|
||||
"boxedAccountUnsized2": 1679,
|
||||
"boxedAccountUnsizedInit4": 20351,
|
||||
"boxedAccountUnsized4": 2899,
|
||||
"boxedAccountUnsizedInit8": 39118,
|
||||
"boxedAccountUnsized8": 5517,
|
||||
"boxedInterfaceAccountMint1": 2299,
|
||||
"boxedInterfaceAccountMint2": 4053,
|
||||
"boxedInterfaceAccountMint4": 7538,
|
||||
"boxedInterfaceAccountMint8": 14699,
|
||||
"boxedInterfaceAccountToken1": 1737,
|
||||
"boxedInterfaceAccountToken2": 2928,
|
||||
"boxedInterfaceAccountToken4": 5291,
|
||||
"boxedInterfaceAccountToken8": 10205,
|
||||
"interfaceAccountMint1": 2530,
|
||||
"interfaceAccountMint2": 4726,
|
||||
"interfaceAccountMint4": 9431,
|
||||
"interfaceAccountMint8": 17709,
|
||||
"interfaceAccountToken1": 1755,
|
||||
"interfaceAccountToken2": 3211,
|
||||
"interfaceAccountToken4": 6006,
|
||||
"interface1": 999,
|
||||
"interface2": 1574,
|
||||
"interface4": 1996,
|
||||
"interface8": 3651,
|
||||
"program1": 999,
|
||||
"program2": 1573,
|
||||
"program4": 1998,
|
||||
"program8": 3651,
|
||||
"signer1": 958,
|
||||
"signer2": 1576,
|
||||
"signer4": 2079,
|
||||
"signer8": 3895,
|
||||
"systemAccount1": 1013,
|
||||
"systemAccount2": 1686,
|
||||
"systemAccount4": 2298,
|
||||
"systemAccount8": 4336,
|
||||
"uncheckedAccount1": 953,
|
||||
"uncheckedAccount2": 1567,
|
||||
"uncheckedAccount4": 2060,
|
||||
"uncheckedAccount8": 3855
|
||||
}
|
||||
},
|
||||
"unreleased": {
|
||||
"computeUnits": {
|
||||
"accountInfo1": 954,
|
||||
"accountInfo2": 1567,
|
||||
"accountInfo4": 2059,
|
||||
"accountInfo8": 3856,
|
||||
"accountEmptyInit1": 5958,
|
||||
"accountEmpty1": 1090,
|
||||
"accountEmptyInit2": 10583,
|
||||
"accountEmpty2": 1852,
|
||||
"accountEmptyInit4": 19557,
|
||||
"accountEmpty4": 2646,
|
||||
"accountEmptyInit8": 37541,
|
||||
"accountEmpty8": 5043,
|
||||
"accountSizedInit1": 6063,
|
||||
"accountSized1": 1135,
|
||||
"accountSizedInit2": 10783,
|
||||
"accountSized2": 1966,
|
||||
"accountSizedInit4": 19975,
|
||||
"accountSized4": 2787,
|
||||
"accountSizedInit8": 38381,
|
||||
"accountSized8": 5359,
|
||||
"accountUnsizedInit1": 6193,
|
||||
"accountUnsized1": 1243,
|
||||
"accountUnsizedInit2": 11042,
|
||||
"accountUnsized2": 1893,
|
||||
"accountUnsizedInit4": 20495,
|
||||
"accountUnsized4": 3104,
|
||||
"accountUnsizedInit8": 39419,
|
||||
"accountUnsized8": 6051,
|
||||
"boxedAccountEmptyInit1": 6160,
|
||||
"boxedAccountEmpty1": 976,
|
||||
"boxedAccountEmptyInit2": 10784,
|
||||
"boxedAccountEmpty2": 1499,
|
||||
"boxedAccountEmptyInit4": 19500,
|
||||
"boxedAccountEmpty4": 2530,
|
||||
"boxedAccountEmptyInit8": 37415,
|
||||
"boxedAccountEmpty8": 4780,
|
||||
"boxedAccountSizedInit1": 6256,
|
||||
"boxedAccountSized1": 1003,
|
||||
"boxedAccountSizedInit2": 10975,
|
||||
"boxedAccountSized2": 1554,
|
||||
"boxedAccountSizedInit4": 19884,
|
||||
"boxedAccountSized4": 2642,
|
||||
"boxedAccountSizedInit8": 38182,
|
||||
"boxedAccountSized8": 5003,
|
||||
"boxedAccountUnsizedInit1": 6374,
|
||||
"boxedAccountUnsized1": 1069,
|
||||
"boxedAccountUnsizedInit2": 11211,
|
||||
"boxedAccountUnsized2": 1679,
|
||||
"boxedAccountUnsizedInit4": 20351,
|
||||
"boxedAccountUnsized4": 2899,
|
||||
"boxedAccountUnsizedInit8": 39118,
|
||||
"boxedAccountUnsized8": 5517,
|
||||
"boxedInterfaceAccountMint1": 2299,
|
||||
"boxedInterfaceAccountMint2": 4053,
|
||||
"boxedInterfaceAccountMint4": 7538,
|
||||
"boxedInterfaceAccountMint8": 14699,
|
||||
"boxedInterfaceAccountToken1": 1737,
|
||||
"boxedInterfaceAccountToken2": 2928,
|
||||
"boxedInterfaceAccountToken4": 5291,
|
||||
"boxedInterfaceAccountToken8": 10205,
|
||||
"interfaceAccountMint1": 2530,
|
||||
"interfaceAccountMint2": 4726,
|
||||
"interfaceAccountMint4": 9431,
|
||||
"interfaceAccountMint8": 17709,
|
||||
"interfaceAccountToken1": 1755,
|
||||
"interfaceAccountToken2": 3211,
|
||||
"interfaceAccountToken4": 6006,
|
||||
"interface1": 999,
|
||||
"interface2": 1574,
|
||||
"interface4": 1996,
|
||||
"interface8": 3651,
|
||||
"program1": 999,
|
||||
"program2": 1573,
|
||||
"program4": 1998,
|
||||
"program8": 3651,
|
||||
"signer1": 958,
|
||||
"signer2": 1576,
|
||||
"signer4": 2079,
|
||||
"signer8": 3895,
|
||||
"systemAccount1": 1013,
|
||||
"systemAccount2": 1686,
|
||||
"systemAccount4": 2298,
|
||||
"systemAccount8": 4336,
|
||||
"uncheckedAccount1": 953,
|
||||
"uncheckedAccount2": 1567,
|
||||
"uncheckedAccount4": 2060,
|
||||
"uncheckedAccount8": 3855
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "bench",
|
||||
"version": "0.27.0",
|
||||
"license": "(MIT OR Apache-2.0)",
|
||||
"homepage": "https://github.com/coral-xyz/anchor#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/coral-xyz/anchor/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/coral-xyz/anchor.git"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=17"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "anchor test"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "bench"
|
||||
version = "0.1.0"
|
||||
description = "Created with Anchor"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "lib"]
|
||||
|
||||
[features]
|
||||
no-entrypoint = []
|
||||
cpi = ["no-entrypoint"]
|
||||
|
||||
[dependencies]
|
||||
anchor-lang = { path = "../../../../lang" }
|
||||
anchor-spl = { path = "../../../../spl" }
|
|
@ -0,0 +1,2 @@
|
|||
[target.bpfel-unknown-unknown.dependencies.std]
|
||||
features = []
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* Bump the version of all benchmark related files by changing the `Unreleased`
|
||||
* version to a new version and adding a new `Unreleased` version.
|
||||
*/
|
||||
|
||||
import { BenchData } from "./utils";
|
||||
|
||||
(async () => {
|
||||
const newVersion = process.argv[2];
|
||||
|
||||
if (!newVersion) {
|
||||
console.error("Usage: anchor run bump-version -- <VERSION>");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Bump bench data
|
||||
const bench = await BenchData.open();
|
||||
bench.bumpVersion(newVersion);
|
||||
await bench.save();
|
||||
|
||||
// Bump markdown files
|
||||
await BenchData.forEachMarkdown((markdown) => {
|
||||
markdown.bumpVersion(newVersion);
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,225 @@
|
|||
/**
|
||||
* Generate instructions with repetitive accounts and add them to the bench program.
|
||||
*/
|
||||
|
||||
import * as fs from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
type Instruction = {
|
||||
/** Instruction name */
|
||||
name: string;
|
||||
/** Each account type in accounts struct */
|
||||
accountType: string;
|
||||
/** Account macro(`#[account(..)]`) */
|
||||
accountMacro?: {
|
||||
init: true;
|
||||
space?: number | string;
|
||||
};
|
||||
/** Number of accounts to create per instruction */
|
||||
accountCounts?: number[];
|
||||
};
|
||||
|
||||
/**
|
||||
* The following instructions will be added to the program.
|
||||
*
|
||||
* If an instruction already exists, it will be skipped.
|
||||
*/
|
||||
const INSTRUCTIONS: Instruction[] = [
|
||||
{
|
||||
name: "account_info",
|
||||
accountType: "AccountInfo<'info>",
|
||||
},
|
||||
{
|
||||
name: "account_empty_init",
|
||||
accountType: "Account<'info, Empty>",
|
||||
accountMacro: {
|
||||
init: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "account_empty",
|
||||
accountType: "Account<'info, Empty>",
|
||||
},
|
||||
{
|
||||
name: "account_sized_init",
|
||||
accountType: "Account<'info, Sized>",
|
||||
accountMacro: {
|
||||
init: true,
|
||||
space: "8 + std::mem::size_of::<Sized>()",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "account_sized",
|
||||
accountType: "Account<'info, Sized>",
|
||||
},
|
||||
{
|
||||
name: "account_unsized_init",
|
||||
accountType: "Account<'info, Unsized>",
|
||||
accountMacro: {
|
||||
init: true,
|
||||
space: "8 + std::mem::size_of::<Unsized>()",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "account_unsized",
|
||||
accountType: "Account<'info, Unsized>",
|
||||
},
|
||||
{
|
||||
name: "boxed_account_empty_init",
|
||||
accountType: "Box<Account<'info, Empty>>",
|
||||
accountMacro: {
|
||||
init: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "boxed_account_empty",
|
||||
accountType: "Box<Account<'info, Empty>>",
|
||||
},
|
||||
{
|
||||
name: "boxed_account_sized_init",
|
||||
accountType: "Box<Account<'info, Sized>>",
|
||||
accountMacro: {
|
||||
init: true,
|
||||
space: "8 + std::mem::size_of::<Sized>()",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "boxed_account_sized",
|
||||
accountType: "Box<Account<'info, Sized>>",
|
||||
},
|
||||
{
|
||||
name: "boxed_account_unsized_init",
|
||||
accountType: "Box<Account<'info, Unsized>>",
|
||||
accountMacro: {
|
||||
init: true,
|
||||
space: "8 + std::mem::size_of::<Unsized>()",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "boxed_account_unsized",
|
||||
accountType: "Box<Account<'info, Unsized>>",
|
||||
},
|
||||
{
|
||||
name: "boxed_interface_account_mint",
|
||||
accountType: "Box<InterfaceAccount<'info, Mint>>",
|
||||
},
|
||||
{
|
||||
name: "boxed_interface_account_token",
|
||||
accountType: "Box<InterfaceAccount<'info, TokenAccount>>",
|
||||
},
|
||||
{
|
||||
name: "interface_account_mint",
|
||||
accountType: "InterfaceAccount<'info, Mint>",
|
||||
},
|
||||
{
|
||||
name: "interface_account_token",
|
||||
accountType: "InterfaceAccount<'info, TokenAccount>",
|
||||
accountCounts: [1, 2, 4],
|
||||
},
|
||||
{
|
||||
name: "interface",
|
||||
accountType: "Interface<'info, TokenInterface>",
|
||||
},
|
||||
{
|
||||
name: "program",
|
||||
accountType: "Program<'info, System>",
|
||||
},
|
||||
{
|
||||
name: "signer",
|
||||
accountType: "Signer<'info>",
|
||||
},
|
||||
{
|
||||
name: "system_account",
|
||||
accountType: "SystemAccount<'info>",
|
||||
},
|
||||
{
|
||||
name: "unchecked_account",
|
||||
accountType: "UncheckedAccount<'info>",
|
||||
},
|
||||
];
|
||||
|
||||
(async () => {
|
||||
// Get the program file
|
||||
const programPath = path.join("programs", "bench", "src", "lib.rs");
|
||||
let file = await fs.readFile(programPath, {
|
||||
encoding: "utf8",
|
||||
});
|
||||
|
||||
const create = (
|
||||
ix: Omit<Instruction, "accountCounts"> & { count: number }
|
||||
) => {
|
||||
// Get the title case of the name for the accounts struct
|
||||
const accountsName =
|
||||
ix.name[0].toUpperCase() +
|
||||
ix.name.slice(1).replace(/_\w/g, (match) => match[1].toUpperCase());
|
||||
|
||||
// Generate accounts
|
||||
let accounts = "";
|
||||
let accountMacro = "";
|
||||
const INDENT = "\n ";
|
||||
|
||||
if (ix.accountMacro?.init) {
|
||||
accounts += `${INDENT}#[account(mut)]${INDENT}pub payer: Signer<'info>,`;
|
||||
accounts += `${INDENT}pub system_program: Program<'info, System>,`;
|
||||
accountMacro += `init, payer = payer, space = ${
|
||||
ix.accountMacro.space ?? 8
|
||||
}`;
|
||||
}
|
||||
|
||||
accountMacro = `${INDENT}#[account(${accountMacro})]`;
|
||||
|
||||
for (let i = 0; i < ix.count; i++) {
|
||||
if (ix.accountMacro) {
|
||||
accounts += accountMacro;
|
||||
}
|
||||
|
||||
accounts += `${INDENT}pub account${i + 1}: ${ix.accountType},`;
|
||||
}
|
||||
|
||||
return {
|
||||
ix: `
|
||||
pub fn ${ix.name}(_ctx: Context<${accountsName}>) -> Result<()> {
|
||||
Ok(())
|
||||
}`,
|
||||
accounts: `
|
||||
#[derive(Accounts)]
|
||||
pub struct ${accountsName}<'info> {${accounts}\n}`,
|
||||
};
|
||||
};
|
||||
|
||||
const insert = (index: number, text: string) => {
|
||||
file = file.slice(0, index) + "\n" + text + file.slice(index);
|
||||
};
|
||||
|
||||
for (const instruction of INSTRUCTIONS) {
|
||||
// Default count
|
||||
instruction.accountCounts ??= [1, 2, 4, 8];
|
||||
|
||||
for (const count of instruction.accountCounts) {
|
||||
// Append count to the end of the instruction name
|
||||
const ixName = instruction.name + count;
|
||||
|
||||
// Skip existing instructions
|
||||
if (file.includes(`fn ${ixName}`)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const { ix, accounts } = create({ ...instruction, name: ixName, count });
|
||||
|
||||
// Get the ix index to start from
|
||||
const programIndex = file.indexOf("#[program]");
|
||||
const fileStartingFromProgram = file.slice(programIndex);
|
||||
|
||||
// Add instruction
|
||||
const ixIndex = programIndex + fileStartingFromProgram.indexOf("\n}");
|
||||
insert(ixIndex, ix);
|
||||
|
||||
// Add accounts
|
||||
const accountsIndex = file.length - 1;
|
||||
insert(accountsIndex, accounts);
|
||||
}
|
||||
}
|
||||
|
||||
// Save
|
||||
await fs.writeFile(programPath, file);
|
||||
})();
|
|
@ -0,0 +1,67 @@
|
|||
/** Update Markdown files in /bench */
|
||||
|
||||
import { BenchData, Markdown } from "./utils";
|
||||
|
||||
(async () => {
|
||||
const bench = await BenchData.open();
|
||||
|
||||
await BenchData.forEachMarkdown((markdown, fileName) => {
|
||||
if (fileName === "COMPUTE_UNITS.md") {
|
||||
const versions = bench.getVersions();
|
||||
|
||||
// On the first version, compare with itself to update it with no changes
|
||||
versions.unshift(versions[0]);
|
||||
|
||||
for (const i in versions) {
|
||||
const currentVersion = versions[i];
|
||||
const nextVersion = versions[+i + 1];
|
||||
|
||||
if (currentVersion === "unreleased") {
|
||||
return;
|
||||
}
|
||||
|
||||
const newComputeUnitsResult = bench.get(nextVersion).computeUnits;
|
||||
const oldComputeUnitsResult = bench.get(currentVersion).computeUnits;
|
||||
|
||||
// Create table
|
||||
const table = Markdown.createTable(
|
||||
"Instruction",
|
||||
"Compute Units",
|
||||
"+/-"
|
||||
);
|
||||
|
||||
bench.compareComputeUnits(
|
||||
newComputeUnitsResult,
|
||||
oldComputeUnitsResult,
|
||||
(ixName, newComputeUnits, oldComputeUnits) => {
|
||||
const percentChange = (
|
||||
(newComputeUnits / oldComputeUnits - 1) *
|
||||
100
|
||||
).toFixed(2);
|
||||
|
||||
let changeText;
|
||||
if (isNaN(oldComputeUnits)) {
|
||||
changeText = "N/A";
|
||||
} else if (+percentChange > 0) {
|
||||
changeText = `🔴 **+${percentChange}%**`;
|
||||
} else {
|
||||
changeText = `🟢 **${percentChange}%**`;
|
||||
}
|
||||
|
||||
table.insert(ixName, newComputeUnits.toString(), changeText);
|
||||
},
|
||||
(ixName, computeUnits) => {
|
||||
table.insert(
|
||||
ixName,
|
||||
computeUnits.toString(),
|
||||
+i === 0 ? "N/A" : "-"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// Update version's table
|
||||
markdown.updateTable(nextVersion, table);
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,298 @@
|
|||
import * as fs from "fs/promises";
|
||||
import path from "path";
|
||||
import { spawnSync } from "child_process";
|
||||
|
||||
/** Persistent benchmark data(mapping of `Version -> Data`) */
|
||||
type Bench = {
|
||||
[key: string]: {
|
||||
/** Benchmark result for compute units consumed */
|
||||
computeUnits: ComputeUnits;
|
||||
};
|
||||
};
|
||||
|
||||
/** `instruction name -> compute units consumed` */
|
||||
export type ComputeUnits = { [key: string]: number };
|
||||
|
||||
/**
|
||||
* How much of a percentage difference between the current and the previous data
|
||||
* should be significant. Any difference above this number should be noted in
|
||||
* the benchmark file.
|
||||
*/
|
||||
export const THRESHOLD_PERCENTAGE = 1;
|
||||
|
||||
/** Path to the benchmark Markdown files */
|
||||
export const BENCH_DIR_PATH = "../../bench";
|
||||
|
||||
/** Utility class to handle benchmark data related operations */
|
||||
export class BenchData {
|
||||
/** Benchmark data filepath */
|
||||
static #PATH = "bench.json";
|
||||
|
||||
/** Benchmark data */
|
||||
#data: Bench;
|
||||
|
||||
constructor(data: Bench) {
|
||||
this.#data = data;
|
||||
}
|
||||
|
||||
/** Open the benchmark data file */
|
||||
static async open() {
|
||||
let bench: Bench;
|
||||
try {
|
||||
const benchFile = await fs.readFile(BenchData.#PATH, {
|
||||
encoding: "utf8",
|
||||
});
|
||||
bench = JSON.parse(benchFile);
|
||||
} catch {
|
||||
bench = {};
|
||||
}
|
||||
|
||||
return new BenchData(bench);
|
||||
}
|
||||
|
||||
/** Save the benchmark data file */
|
||||
async save() {
|
||||
await fs.writeFile(BenchData.#PATH, JSON.stringify(this.#data, null, 2));
|
||||
}
|
||||
|
||||
/** Get the stored results based on version */
|
||||
get(version: string) {
|
||||
return this.#data[version];
|
||||
}
|
||||
|
||||
/** Get unreleased version results */
|
||||
getUnreleased() {
|
||||
return this.get("unreleased");
|
||||
}
|
||||
|
||||
/** Get all versions */
|
||||
getVersions() {
|
||||
return Object.keys(this.#data);
|
||||
}
|
||||
|
||||
/** Compare and update compute units changes */
|
||||
compareComputeUnits(
|
||||
newComputeUnitsResult: ComputeUnits,
|
||||
oldComputeUnitsResult: ComputeUnits,
|
||||
changeCb: (
|
||||
ixName: string,
|
||||
newComputeUnits: number,
|
||||
oldComputeUnits: number
|
||||
) => void,
|
||||
noChangeCb?: (ixName: string, computeUnits: number) => void
|
||||
) {
|
||||
let needsUpdate = false;
|
||||
|
||||
// Compare compute units changes
|
||||
for (const ixName in newComputeUnitsResult) {
|
||||
const oldComputeUnits = oldComputeUnitsResult[ixName];
|
||||
const newComputeUnits = newComputeUnitsResult[ixName];
|
||||
if (!oldComputeUnits) {
|
||||
console.log(`New instruction '${ixName}'`);
|
||||
needsUpdate = true;
|
||||
changeCb(ixName, newComputeUnits, NaN);
|
||||
continue;
|
||||
}
|
||||
|
||||
const percentage = THRESHOLD_PERCENTAGE / 100;
|
||||
const oldMaximumAllowedDelta = oldComputeUnits * percentage;
|
||||
const newMaximumAllowedDelta = newComputeUnits * percentage;
|
||||
|
||||
const delta = newComputeUnits - oldComputeUnits;
|
||||
const absDelta = Math.abs(delta);
|
||||
|
||||
if (
|
||||
absDelta > oldMaximumAllowedDelta ||
|
||||
absDelta > newMaximumAllowedDelta
|
||||
) {
|
||||
// Throw in CI
|
||||
if (process.env.CI) {
|
||||
throw new Error(
|
||||
[
|
||||
`Compute units for instruction '${ixName}' has changed more than ${THRESHOLD_PERCENTAGE}% but is not saved.`,
|
||||
"Run `anchor test --skip-lint` in tests/bench and commit the changes.",
|
||||
].join(" ")
|
||||
);
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Compute units change '${ixName}' (${oldComputeUnits} -> ${newComputeUnits})`
|
||||
);
|
||||
|
||||
needsUpdate = true;
|
||||
changeCb(ixName, newComputeUnits, oldComputeUnits);
|
||||
} else {
|
||||
noChangeCb?.(ixName, newComputeUnits);
|
||||
}
|
||||
}
|
||||
|
||||
return { needsUpdate };
|
||||
}
|
||||
|
||||
/** Bump benchmark data version to the given version */
|
||||
bumpVersion(newVersion: string) {
|
||||
const versions = Object.keys(this.#data);
|
||||
const unreleasedVersion = versions[versions.length - 1];
|
||||
|
||||
if (this.#data[newVersion]) {
|
||||
console.error(`Version '${newVersion}' already exists!`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Add the new version
|
||||
this.#data[newVersion] = this.get(unreleasedVersion);
|
||||
|
||||
// Delete the unreleased version
|
||||
delete this.#data[unreleasedVersion];
|
||||
|
||||
// Add new unreleased version
|
||||
this.#data[unreleasedVersion] = this.#data[newVersion];
|
||||
}
|
||||
|
||||
/**
|
||||
* Loop through all of the markdown files and run the given callback before
|
||||
* saving the file.
|
||||
*/
|
||||
static async forEachMarkdown(
|
||||
cb: (markdown: Markdown, fileName: string) => void
|
||||
) {
|
||||
const fileNames = await fs.readdir(BENCH_DIR_PATH);
|
||||
const markdownFileNames = fileNames.filter((n) => n.endsWith(".md"));
|
||||
|
||||
for (const fileName of markdownFileNames) {
|
||||
const markdown = await Markdown.open(path.join(BENCH_DIR_PATH, fileName));
|
||||
cb(markdown, fileName);
|
||||
await markdown.save();
|
||||
}
|
||||
|
||||
// Format
|
||||
spawnSync("yarn", [
|
||||
"run",
|
||||
"prettier",
|
||||
"--write",
|
||||
path.join(BENCH_DIR_PATH, "*.md"),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Utility class to handle markdown related operations */
|
||||
export class Markdown {
|
||||
/** Unreleased version string */
|
||||
static #UNRELEASED_VERSION = "[Unreleased]";
|
||||
|
||||
/** Markdown filepath */
|
||||
#path: string;
|
||||
|
||||
/** Markdown text */
|
||||
#text: string;
|
||||
|
||||
constructor(path: string, text: string) {
|
||||
this.#path = path;
|
||||
this.#text = text;
|
||||
}
|
||||
|
||||
/** Open the markdown file */
|
||||
static async open(path: string) {
|
||||
const text = await fs.readFile(path, { encoding: "utf8" });
|
||||
return new Markdown(path, text);
|
||||
}
|
||||
|
||||
/** Create a markdown table */
|
||||
static createTable(...args: string[]) {
|
||||
return new MarkdownTable([args]);
|
||||
}
|
||||
|
||||
/** Save the markdown file */
|
||||
async save() {
|
||||
await fs.writeFile(this.#path, this.#text);
|
||||
}
|
||||
|
||||
/** Change version table with the given table */
|
||||
updateTable(version: string, table: MarkdownTable) {
|
||||
const md = this.#text;
|
||||
|
||||
let titleStartIndex = md.indexOf(`[${version}]`);
|
||||
if (titleStartIndex === -1) {
|
||||
titleStartIndex = md.indexOf(Markdown.#UNRELEASED_VERSION);
|
||||
}
|
||||
|
||||
const startIndex = titleStartIndex + md.slice(titleStartIndex).indexOf("|");
|
||||
const endIndex = startIndex + md.slice(startIndex).indexOf("\n\n");
|
||||
|
||||
this.#text =
|
||||
md.slice(0, startIndex) + table.toString() + md.slice(endIndex + 1);
|
||||
}
|
||||
|
||||
/** Bump the version to the given version */
|
||||
bumpVersion(newVersion: string) {
|
||||
newVersion = `[${newVersion}]`;
|
||||
if (this.#text.includes(newVersion)) {
|
||||
console.error(`Version '${newVersion}' already exists!`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const startIndex = this.#text.indexOf(`## ${Markdown.#UNRELEASED_VERSION}`);
|
||||
const endIndex =
|
||||
startIndex + this.#text.slice(startIndex).indexOf("\n---") + 4;
|
||||
let unreleasedSection = this.#text.slice(startIndex, endIndex);
|
||||
|
||||
// Update unreleased version to `newVersion`
|
||||
const newSection = unreleasedSection.replace(
|
||||
Markdown.#UNRELEASED_VERSION,
|
||||
newVersion
|
||||
);
|
||||
|
||||
// Reset unreleased version changes
|
||||
unreleasedSection = unreleasedSection
|
||||
.split("\n")
|
||||
.map((line, i) => {
|
||||
// First 4 lines don't change
|
||||
if ([0, 1, 2, 3].includes(i)) return line;
|
||||
|
||||
const regex = /\|.*\|.*\|(.*)\|/;
|
||||
const result = regex.exec(line);
|
||||
|
||||
const changeStr = result?.[1];
|
||||
if (!changeStr) {
|
||||
if (line.startsWith("#")) return line;
|
||||
else if (line.startsWith("---")) return line + "\n";
|
||||
else return "";
|
||||
}
|
||||
|
||||
return line.replace(changeStr, "-");
|
||||
})
|
||||
.join("\n");
|
||||
|
||||
// Update the text
|
||||
this.#text =
|
||||
this.#text.slice(0, startIndex) +
|
||||
unreleasedSection +
|
||||
newSection +
|
||||
this.#text.slice(endIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/** Utility class to handle markdown table related operations */
|
||||
class MarkdownTable {
|
||||
/** Markdown rows stored as array of arrays */
|
||||
#rows: string[][];
|
||||
|
||||
constructor(rows: string[][]) {
|
||||
this.#rows = rows;
|
||||
this.insert("-", "-", "-");
|
||||
}
|
||||
|
||||
/** Insert a new row to the markdown table */
|
||||
insert(...args: string[]) {
|
||||
this.#rows.push(args);
|
||||
}
|
||||
|
||||
/** Convert the stored rows to a markdown table */
|
||||
toString() {
|
||||
return this.#rows.reduce(
|
||||
(acc, row) =>
|
||||
acc + row.reduce((acc, cur) => `${acc} ${cur} |`, "|") + "\n",
|
||||
""
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,248 @@
|
|||
import * as anchor from "@coral-xyz/anchor";
|
||||
import * as token from "@coral-xyz/spl-token";
|
||||
import { spawnSync } from "child_process";
|
||||
|
||||
import { Bench, IDL } from "../target/types/bench";
|
||||
import { BenchData, ComputeUnits } from "../scripts/utils";
|
||||
|
||||
describe(IDL.name, () => {
|
||||
// Configure the client to use the local cluster
|
||||
anchor.setProvider(anchor.AnchorProvider.env());
|
||||
|
||||
const program = anchor.workspace.Bench as anchor.Program<Bench>;
|
||||
const owner = program.provider.publicKey!;
|
||||
|
||||
let mintPk: anchor.web3.PublicKey;
|
||||
let tokenPk: anchor.web3.PublicKey;
|
||||
|
||||
const computeUnits: ComputeUnits = {};
|
||||
|
||||
const measureComputeUnits = async (
|
||||
ixName: string,
|
||||
options?: Partial<{
|
||||
accountCounts: number[];
|
||||
generateKeypair: (accountName: string) => anchor.web3.Keypair;
|
||||
generatePublicKey: (accountName: string) => anchor.web3.PublicKey;
|
||||
}>
|
||||
) => {
|
||||
options ??= {};
|
||||
options.accountCounts ??= [1, 2, 4, 8];
|
||||
options.generateKeypair ??= () => anchor.web3.Keypair.generate();
|
||||
|
||||
for (const accountCount of options.accountCounts) {
|
||||
// Check whether the init version of the instruction exists
|
||||
const ixNameInit = `${ixName}Init`;
|
||||
const hasInitVersion = IDL.instructions.some((ix) =>
|
||||
ix.name.startsWith(ixNameInit)
|
||||
);
|
||||
|
||||
const ixNames = [ixName];
|
||||
if (hasInitVersion) {
|
||||
// Init version has priority
|
||||
ixNames.unshift(ixNameInit);
|
||||
}
|
||||
|
||||
const accounts: { [key: string]: anchor.web3.PublicKey } = {};
|
||||
const signers = [];
|
||||
|
||||
for (const ixName of ixNames) {
|
||||
const method =
|
||||
`${ixName}${accountCount}` as keyof typeof program.methods;
|
||||
|
||||
// Remove signers when it's not init instruction
|
||||
if (ixName !== ixNameInit) {
|
||||
signers.splice(0);
|
||||
}
|
||||
|
||||
for (const ix of IDL.instructions) {
|
||||
if (ix.name !== method) continue;
|
||||
|
||||
for (const account of ix.accounts) {
|
||||
// Only set account keys if it hasn't been set before
|
||||
if (accounts[account.name]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (account.name === "payer") {
|
||||
accounts[account.name] = owner;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip other accounts to not override Anchor defaults
|
||||
if (!account.name.startsWith("account")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (options.generatePublicKey) {
|
||||
accounts[account.name] = options.generatePublicKey(account.name);
|
||||
continue;
|
||||
}
|
||||
|
||||
const keypair = options.generateKeypair(account.name);
|
||||
accounts[account.name] = keypair.publicKey;
|
||||
|
||||
if (account.isSigner) {
|
||||
signers.push(keypair);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send tx
|
||||
console.log({ method });
|
||||
const txHash = await program.methods[method]()
|
||||
.accounts(accounts)
|
||||
.signers(signers)
|
||||
.rpc();
|
||||
|
||||
// Confirm tx
|
||||
await program.provider.connection.confirmTransaction(
|
||||
txHash,
|
||||
"confirmed"
|
||||
);
|
||||
|
||||
// Get tx
|
||||
const tx = await program.provider.connection.getTransaction(txHash, {
|
||||
commitment: "confirmed",
|
||||
});
|
||||
|
||||
computeUnits[method] = tx!.meta!.computeUnitsConsumed!;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
before(async () => {
|
||||
const tokenProgram = token.splTokenProgram({
|
||||
provider: anchor.AnchorProvider.local(),
|
||||
});
|
||||
|
||||
const tx = new anchor.web3.Transaction();
|
||||
|
||||
// Create mint account
|
||||
const mintKp = new anchor.web3.Keypair();
|
||||
mintPk = mintKp.publicKey;
|
||||
const createMintIx = await tokenProgram.account.mint.createInstruction(
|
||||
mintKp
|
||||
);
|
||||
const initMintIx = await tokenProgram.methods
|
||||
.initializeMint2(0, owner, null)
|
||||
.accounts({ mint: mintPk })
|
||||
.instruction();
|
||||
tx.add(createMintIx, initMintIx);
|
||||
|
||||
// Create token account
|
||||
const tokenKp = new anchor.web3.Keypair();
|
||||
tokenPk = tokenKp.publicKey;
|
||||
const createTokenIx = await tokenProgram.account.account.createInstruction(
|
||||
tokenKp
|
||||
);
|
||||
const initTokenIx = await tokenProgram.methods
|
||||
.initializeAccount3(owner)
|
||||
.accounts({ account: tokenPk, mint: mintPk })
|
||||
.instruction();
|
||||
tx.add(createTokenIx, initTokenIx);
|
||||
|
||||
await tokenProgram.provider.sendAndConfirm!(tx, [mintKp, tokenKp]);
|
||||
});
|
||||
|
||||
it("AccountInfo", async () => {
|
||||
await measureComputeUnits("accountInfo");
|
||||
});
|
||||
|
||||
it("Account Empty", async () => {
|
||||
await measureComputeUnits("accountEmpty");
|
||||
});
|
||||
|
||||
it("Account Sized", async () => {
|
||||
await measureComputeUnits("accountSized");
|
||||
});
|
||||
|
||||
it("Account Unsized", async () => {
|
||||
await measureComputeUnits("accountUnsized");
|
||||
});
|
||||
|
||||
it("Boxed Account Empty", async () => {
|
||||
await measureComputeUnits("boxedAccountEmpty");
|
||||
});
|
||||
|
||||
it("Boxed Account Sized", async () => {
|
||||
await measureComputeUnits("boxedAccountSized");
|
||||
});
|
||||
|
||||
it("Boxed Account Unsized", async () => {
|
||||
await measureComputeUnits("boxedAccountUnsized");
|
||||
});
|
||||
|
||||
it("Boxed Interface Account Mint", async () => {
|
||||
await measureComputeUnits("boxedInterfaceAccountMint", {
|
||||
generatePublicKey: () => mintPk,
|
||||
});
|
||||
});
|
||||
|
||||
it("Boxed Interface Account Token", async () => {
|
||||
await measureComputeUnits("boxedInterfaceAccountToken", {
|
||||
generatePublicKey: () => tokenPk,
|
||||
});
|
||||
});
|
||||
|
||||
it("Interface Account Mint", async () => {
|
||||
await measureComputeUnits("interfaceAccountMint", {
|
||||
generatePublicKey: () => mintPk,
|
||||
});
|
||||
});
|
||||
|
||||
it("Interface Account Token", async () => {
|
||||
await measureComputeUnits("interfaceAccountToken", {
|
||||
generatePublicKey: () => tokenPk,
|
||||
accountCounts: [1, 2, 4],
|
||||
});
|
||||
});
|
||||
|
||||
it("Interface", async () => {
|
||||
await measureComputeUnits("interface", {
|
||||
generatePublicKey: () => token.SPL_TOKEN_PROGRAM_ID,
|
||||
});
|
||||
});
|
||||
|
||||
it("Program", async () => {
|
||||
await measureComputeUnits("program", {
|
||||
generatePublicKey: () => anchor.web3.SystemProgram.programId,
|
||||
});
|
||||
});
|
||||
|
||||
it("Signer", async () => {
|
||||
await measureComputeUnits("signer");
|
||||
});
|
||||
|
||||
it("SystemAccount", async () => {
|
||||
await measureComputeUnits("systemAccount");
|
||||
});
|
||||
|
||||
it("UncheckedAccount", async () => {
|
||||
await measureComputeUnits("uncheckedAccount");
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
// Read the bench data file
|
||||
const bench = await BenchData.open();
|
||||
|
||||
// Compare and update compute units changes
|
||||
const oldComputeUnits = bench.getUnreleased().computeUnits;
|
||||
const { needsUpdate } = bench.compareComputeUnits(
|
||||
computeUnits,
|
||||
oldComputeUnits,
|
||||
(ixName, newComputeUnits) => {
|
||||
oldComputeUnits[ixName] = newComputeUnits;
|
||||
}
|
||||
);
|
||||
|
||||
if (needsUpdate) {
|
||||
console.log("Updating benchmark files...");
|
||||
|
||||
// Save bench data file
|
||||
// (needs to happen before running the `update-bench` script)
|
||||
await bench.save();
|
||||
|
||||
spawnSync("anchor", ["run", "update-bench"]);
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"types": ["mocha", "chai", "node"],
|
||||
"typeRoots": ["./node_modules/@types"],
|
||||
"lib": ["es2015", "dom"],
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
"workspaces": [
|
||||
"anchor-cli-account",
|
||||
"anchor-cli-idl",
|
||||
"bench",
|
||||
"cashiers-check",
|
||||
"cfo",
|
||||
"chat",
|
||||
|
|
|
@ -7,7 +7,9 @@ if [ $# -eq 0 ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
echo "Bumping versions to $1"
|
||||
version=$1
|
||||
|
||||
echo "Bumping versions to $version"
|
||||
|
||||
# GNU/BSD compat
|
||||
sedi=(-i)
|
||||
|
@ -16,28 +18,34 @@ case "$(uname)" in
|
|||
Darwin*) sedi=(-i "")
|
||||
esac
|
||||
|
||||
git grep -l $(cat VERSION) -- ':!**/yarn.lock' ':!CHANGELOG.md' ':!Cargo.lock' ':!package.json' | \
|
||||
# Don't replace version with the following globs
|
||||
skip_globs=":!**/yarn.lock :!Cargo.lock :!package.json :!tests/bench/bench.json :!bench/*.md"
|
||||
|
||||
git grep -l $(cat VERSION) -- $skip_globs |
|
||||
xargs sed "${sedi[@]}" \
|
||||
-e "s/$(cat VERSION)/$1/g"
|
||||
-e "s/$(cat VERSION)/$version/g"
|
||||
|
||||
# Potential for collisions in package.json files, handle those separately
|
||||
# Replace only matching "version": "x.xx.x" and "@coral-xyz/anchor": "x.xx.x"
|
||||
git grep -l $(cat VERSION) -- '**/package.json' | \
|
||||
xargs sed "${sedi[@]}" \
|
||||
-e "s/@coral-xyz\/anchor\": \"$(cat VERSION)\"/@coral-xyz\/anchor\": \"$1\"/g" \
|
||||
-e "s/\"version\": \"$(cat VERSION)\"/\"version\": \"$1\"/g"
|
||||
-e "s/@coral-xyz\/anchor\": \"$(cat VERSION)\"/@coral-xyz\/anchor\": \"$version\"/g" \
|
||||
-e "s/\"version\": \"$(cat VERSION)\"/\"version\": \"$version\"/g"
|
||||
|
||||
# Potential for collisions in Cargo.lock, use cargo update to update it
|
||||
cargo update --workspace
|
||||
|
||||
# Insert version number into CHANGELOG.md
|
||||
sed "${sedi[@]}" -e "s/## \[Unreleased\]/## [Unreleased]\n\n## [$1] - $(date '+%Y-%m-%d')/g" CHANGELOG.md
|
||||
sed "${sedi[@]}" -e "s/## \[Unreleased\]/## [Unreleased]\n\n## [$version] - $(date '+%Y-%m-%d')/g" CHANGELOG.md
|
||||
|
||||
pushd ts && yarn && popd
|
||||
pushd tests && yarn && popd
|
||||
pushd examples && yarn && pushd tutorial && yarn && popd && popd
|
||||
|
||||
echo $1 > VERSION
|
||||
# Bump benchmark files
|
||||
pushd tests/bench && anchor run bump-version -- $version && popd
|
||||
|
||||
echo $version > VERSION
|
||||
|
||||
echo "$(git diff --stat | tail -n1) files modified"
|
||||
|
||||
|
|
Loading…
Reference in New Issue