소스 검색

Add benchmarking for compute units usage (#2466)

acheron 2 년 전
부모
커밋
5910dd3e2f

+ 2 - 0
.github/workflows/reusable-tests.yaml

@@ -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/

+ 3 - 0
CHANGELOG.md

@@ -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

+ 200 - 0
bench/COMPUTE_UNITS.md

@@ -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 |
+
+---

+ 15 - 0
tests/bench/Anchor.toml

@@ -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"

+ 4 - 0
tests/bench/Cargo.toml

@@ -0,0 +1,4 @@
+[workspace]
+members = [
+    "programs/*"
+]

+ 27 - 0
tests/bench/README.md

@@ -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.

+ 184 - 0
tests/bench/bench.json

@@ -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
+    }
+  }
+}

+ 19 - 0
tests/bench/package.json

@@ -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"
+  }
+}

+ 16 - 0
tests/bench/programs/bench/Cargo.toml

@@ -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" }

+ 2 - 0
tests/bench/programs/bench/Xargo.toml

@@ -0,0 +1,2 @@
+[target.bpfel-unknown-unknown.dependencies.std]
+features = []

+ 1212 - 0
tests/bench/programs/bench/src/lib.rs

@@ -0,0 +1,1212 @@
+//! This program is used to measure the performance of Anchor programs.
+
+use anchor_lang::prelude::*;
+use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface};
+
+declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
+
+#[program]
+pub mod bench {
+    use super::*;
+
+    pub fn account_info1(_ctx: Context<AccountInfo1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_info2(_ctx: Context<AccountInfo2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_info4(_ctx: Context<AccountInfo4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_info8(_ctx: Context<AccountInfo8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_empty_init1(_ctx: Context<AccountEmptyInit1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_empty_init2(_ctx: Context<AccountEmptyInit2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_empty_init4(_ctx: Context<AccountEmptyInit4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_empty_init8(_ctx: Context<AccountEmptyInit8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_empty1(_ctx: Context<AccountEmpty1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_empty2(_ctx: Context<AccountEmpty2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_empty4(_ctx: Context<AccountEmpty4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_empty8(_ctx: Context<AccountEmpty8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_sized_init1(_ctx: Context<AccountSizedInit1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_sized_init2(_ctx: Context<AccountSizedInit2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_sized_init4(_ctx: Context<AccountSizedInit4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_sized_init8(_ctx: Context<AccountSizedInit8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_sized1(_ctx: Context<AccountSized1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_sized2(_ctx: Context<AccountSized2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_sized4(_ctx: Context<AccountSized4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_sized8(_ctx: Context<AccountSized8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_unsized_init1(_ctx: Context<AccountUnsizedInit1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_unsized_init2(_ctx: Context<AccountUnsizedInit2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_unsized_init4(_ctx: Context<AccountUnsizedInit4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_unsized_init8(_ctx: Context<AccountUnsizedInit8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_unsized1(_ctx: Context<AccountUnsized1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_unsized2(_ctx: Context<AccountUnsized2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_unsized4(_ctx: Context<AccountUnsized4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account_unsized8(_ctx: Context<AccountUnsized8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_empty_init1(_ctx: Context<BoxedAccountEmptyInit1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_empty_init2(_ctx: Context<BoxedAccountEmptyInit2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_empty_init4(_ctx: Context<BoxedAccountEmptyInit4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_empty_init8(_ctx: Context<BoxedAccountEmptyInit8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_empty1(_ctx: Context<BoxedAccountEmpty1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_empty2(_ctx: Context<BoxedAccountEmpty2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_empty4(_ctx: Context<BoxedAccountEmpty4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_empty8(_ctx: Context<BoxedAccountEmpty8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_sized_init1(_ctx: Context<BoxedAccountSizedInit1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_sized_init2(_ctx: Context<BoxedAccountSizedInit2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_sized_init4(_ctx: Context<BoxedAccountSizedInit4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_sized_init8(_ctx: Context<BoxedAccountSizedInit8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_sized1(_ctx: Context<BoxedAccountSized1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_sized2(_ctx: Context<BoxedAccountSized2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_sized4(_ctx: Context<BoxedAccountSized4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_sized8(_ctx: Context<BoxedAccountSized8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_unsized_init1(_ctx: Context<BoxedAccountUnsizedInit1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_unsized_init2(_ctx: Context<BoxedAccountUnsizedInit2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_unsized_init4(_ctx: Context<BoxedAccountUnsizedInit4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_unsized_init8(_ctx: Context<BoxedAccountUnsizedInit8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_unsized1(_ctx: Context<BoxedAccountUnsized1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_unsized2(_ctx: Context<BoxedAccountUnsized2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_unsized4(_ctx: Context<BoxedAccountUnsized4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_account_unsized8(_ctx: Context<BoxedAccountUnsized8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_interface_account_mint1(_ctx: Context<BoxedInterfaceAccountMint1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_interface_account_mint2(_ctx: Context<BoxedInterfaceAccountMint2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_interface_account_mint4(_ctx: Context<BoxedInterfaceAccountMint4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_interface_account_mint8(_ctx: Context<BoxedInterfaceAccountMint8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_interface_account_token1(
+        _ctx: Context<BoxedInterfaceAccountToken1>,
+    ) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_interface_account_token2(
+        _ctx: Context<BoxedInterfaceAccountToken2>,
+    ) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_interface_account_token4(
+        _ctx: Context<BoxedInterfaceAccountToken4>,
+    ) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn boxed_interface_account_token8(
+        _ctx: Context<BoxedInterfaceAccountToken8>,
+    ) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn interface_account_mint1(_ctx: Context<InterfaceAccountMint1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn interface_account_mint2(_ctx: Context<InterfaceAccountMint2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn interface_account_mint4(_ctx: Context<InterfaceAccountMint4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn interface_account_mint8(_ctx: Context<InterfaceAccountMint8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn interface_account_token1(_ctx: Context<InterfaceAccountToken1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn interface_account_token2(_ctx: Context<InterfaceAccountToken2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn interface_account_token4(_ctx: Context<InterfaceAccountToken4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn interface1(_ctx: Context<Interface1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn interface2(_ctx: Context<Interface2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn interface4(_ctx: Context<Interface4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn interface8(_ctx: Context<Interface8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn program1(_ctx: Context<Program1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn program2(_ctx: Context<Program2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn program4(_ctx: Context<Program4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn program8(_ctx: Context<Program8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn signer1(_ctx: Context<Signer1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn signer2(_ctx: Context<Signer2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn signer4(_ctx: Context<Signer4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn signer8(_ctx: Context<Signer8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn system_account1(_ctx: Context<SystemAccount1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn system_account2(_ctx: Context<SystemAccount2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn system_account4(_ctx: Context<SystemAccount4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn system_account8(_ctx: Context<SystemAccount8>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn unchecked_account1(_ctx: Context<UncheckedAccount1>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn unchecked_account2(_ctx: Context<UncheckedAccount2>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn unchecked_account4(_ctx: Context<UncheckedAccount4>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn unchecked_account8(_ctx: Context<UncheckedAccount8>) -> Result<()> {
+        Ok(())
+    }
+}
+
+#[account]
+pub struct Empty {}
+
+#[account]
+pub struct Sized {
+    pub field: [u8; 8],
+}
+
+#[account]
+pub struct Unsized {
+    pub field: Vec<u8>,
+}
+
+#[derive(Accounts)]
+pub struct AccountInfo1<'info> {
+    pub account1: AccountInfo<'info>,
+}
+
+#[derive(Accounts)]
+pub struct AccountInfo2<'info> {
+    pub account1: AccountInfo<'info>,
+    pub account2: AccountInfo<'info>,
+}
+
+#[derive(Accounts)]
+pub struct AccountInfo4<'info> {
+    pub account1: AccountInfo<'info>,
+    pub account2: AccountInfo<'info>,
+    pub account3: AccountInfo<'info>,
+    pub account4: AccountInfo<'info>,
+}
+
+#[derive(Accounts)]
+pub struct AccountInfo8<'info> {
+    pub account1: AccountInfo<'info>,
+    pub account2: AccountInfo<'info>,
+    pub account3: AccountInfo<'info>,
+    pub account4: AccountInfo<'info>,
+    pub account5: AccountInfo<'info>,
+    pub account6: AccountInfo<'info>,
+    pub account7: AccountInfo<'info>,
+    pub account8: AccountInfo<'info>,
+}
+
+#[derive(Accounts)]
+pub struct AccountEmptyInit1<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8)]
+    pub account1: Account<'info, Empty>,
+}
+
+#[derive(Accounts)]
+pub struct AccountEmptyInit2<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8)]
+    pub account1: Account<'info, Empty>,
+    #[account(init, payer = payer, space = 8)]
+    pub account2: Account<'info, Empty>,
+}
+
+#[derive(Accounts)]
+pub struct AccountEmptyInit4<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8)]
+    pub account1: Account<'info, Empty>,
+    #[account(init, payer = payer, space = 8)]
+    pub account2: Account<'info, Empty>,
+    #[account(init, payer = payer, space = 8)]
+    pub account3: Account<'info, Empty>,
+    #[account(init, payer = payer, space = 8)]
+    pub account4: Account<'info, Empty>,
+}
+
+#[derive(Accounts)]
+pub struct AccountEmptyInit8<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8)]
+    pub account1: Account<'info, Empty>,
+    #[account(init, payer = payer, space = 8)]
+    pub account2: Account<'info, Empty>,
+    #[account(init, payer = payer, space = 8)]
+    pub account3: Account<'info, Empty>,
+    #[account(init, payer = payer, space = 8)]
+    pub account4: Account<'info, Empty>,
+    #[account(init, payer = payer, space = 8)]
+    pub account5: Account<'info, Empty>,
+    #[account(init, payer = payer, space = 8)]
+    pub account6: Account<'info, Empty>,
+    #[account(init, payer = payer, space = 8)]
+    pub account7: Account<'info, Empty>,
+    #[account(init, payer = payer, space = 8)]
+    pub account8: Account<'info, Empty>,
+}
+
+#[derive(Accounts)]
+pub struct AccountEmpty1<'info> {
+    pub account1: Account<'info, Empty>,
+}
+
+#[derive(Accounts)]
+pub struct AccountEmpty2<'info> {
+    pub account1: Account<'info, Empty>,
+    pub account2: Account<'info, Empty>,
+}
+
+#[derive(Accounts)]
+pub struct AccountEmpty4<'info> {
+    pub account1: Account<'info, Empty>,
+    pub account2: Account<'info, Empty>,
+    pub account3: Account<'info, Empty>,
+    pub account4: Account<'info, Empty>,
+}
+
+#[derive(Accounts)]
+pub struct AccountEmpty8<'info> {
+    pub account1: Account<'info, Empty>,
+    pub account2: Account<'info, Empty>,
+    pub account3: Account<'info, Empty>,
+    pub account4: Account<'info, Empty>,
+    pub account5: Account<'info, Empty>,
+    pub account6: Account<'info, Empty>,
+    pub account7: Account<'info, Empty>,
+    pub account8: Account<'info, Empty>,
+}
+
+#[derive(Accounts)]
+pub struct AccountSizedInit1<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account1: Account<'info, Sized>,
+}
+
+#[derive(Accounts)]
+pub struct AccountSizedInit2<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account1: Account<'info, Sized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account2: Account<'info, Sized>,
+}
+
+#[derive(Accounts)]
+pub struct AccountSizedInit4<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account1: Account<'info, Sized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account2: Account<'info, Sized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account3: Account<'info, Sized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account4: Account<'info, Sized>,
+}
+
+#[derive(Accounts)]
+pub struct AccountSizedInit8<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account1: Account<'info, Sized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account2: Account<'info, Sized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account3: Account<'info, Sized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account4: Account<'info, Sized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account5: Account<'info, Sized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account6: Account<'info, Sized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account7: Account<'info, Sized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account8: Account<'info, Sized>,
+}
+
+#[derive(Accounts)]
+pub struct AccountSized1<'info> {
+    pub account1: Account<'info, Sized>,
+}
+
+#[derive(Accounts)]
+pub struct AccountSized2<'info> {
+    pub account1: Account<'info, Sized>,
+    pub account2: Account<'info, Sized>,
+}
+
+#[derive(Accounts)]
+pub struct AccountSized4<'info> {
+    pub account1: Account<'info, Sized>,
+    pub account2: Account<'info, Sized>,
+    pub account3: Account<'info, Sized>,
+    pub account4: Account<'info, Sized>,
+}
+
+#[derive(Accounts)]
+pub struct AccountSized8<'info> {
+    pub account1: Account<'info, Sized>,
+    pub account2: Account<'info, Sized>,
+    pub account3: Account<'info, Sized>,
+    pub account4: Account<'info, Sized>,
+    pub account5: Account<'info, Sized>,
+    pub account6: Account<'info, Sized>,
+    pub account7: Account<'info, Sized>,
+    pub account8: Account<'info, Sized>,
+}
+
+#[derive(Accounts)]
+pub struct AccountUnsizedInit1<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account1: Account<'info, Unsized>,
+}
+
+#[derive(Accounts)]
+pub struct AccountUnsizedInit2<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account1: Account<'info, Unsized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account2: Account<'info, Unsized>,
+}
+
+#[derive(Accounts)]
+pub struct AccountUnsizedInit4<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account1: Account<'info, Unsized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account2: Account<'info, Unsized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account3: Account<'info, Unsized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account4: Account<'info, Unsized>,
+}
+
+#[derive(Accounts)]
+pub struct AccountUnsizedInit8<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account1: Account<'info, Unsized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account2: Account<'info, Unsized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account3: Account<'info, Unsized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account4: Account<'info, Unsized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account5: Account<'info, Unsized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account6: Account<'info, Unsized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account7: Account<'info, Unsized>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account8: Account<'info, Unsized>,
+}
+
+#[derive(Accounts)]
+pub struct AccountUnsized1<'info> {
+    pub account1: Account<'info, Unsized>,
+}
+
+#[derive(Accounts)]
+pub struct AccountUnsized2<'info> {
+    pub account1: Account<'info, Unsized>,
+    pub account2: Account<'info, Unsized>,
+}
+
+#[derive(Accounts)]
+pub struct AccountUnsized4<'info> {
+    pub account1: Account<'info, Unsized>,
+    pub account2: Account<'info, Unsized>,
+    pub account3: Account<'info, Unsized>,
+    pub account4: Account<'info, Unsized>,
+}
+
+#[derive(Accounts)]
+pub struct AccountUnsized8<'info> {
+    pub account1: Account<'info, Unsized>,
+    pub account2: Account<'info, Unsized>,
+    pub account3: Account<'info, Unsized>,
+    pub account4: Account<'info, Unsized>,
+    pub account5: Account<'info, Unsized>,
+    pub account6: Account<'info, Unsized>,
+    pub account7: Account<'info, Unsized>,
+    pub account8: Account<'info, Unsized>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountEmptyInit1<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8)]
+    pub account1: Box<Account<'info, Empty>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountEmptyInit2<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8)]
+    pub account1: Box<Account<'info, Empty>>,
+    #[account(init, payer = payer, space = 8)]
+    pub account2: Box<Account<'info, Empty>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountEmptyInit4<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8)]
+    pub account1: Box<Account<'info, Empty>>,
+    #[account(init, payer = payer, space = 8)]
+    pub account2: Box<Account<'info, Empty>>,
+    #[account(init, payer = payer, space = 8)]
+    pub account3: Box<Account<'info, Empty>>,
+    #[account(init, payer = payer, space = 8)]
+    pub account4: Box<Account<'info, Empty>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountEmptyInit8<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8)]
+    pub account1: Box<Account<'info, Empty>>,
+    #[account(init, payer = payer, space = 8)]
+    pub account2: Box<Account<'info, Empty>>,
+    #[account(init, payer = payer, space = 8)]
+    pub account3: Box<Account<'info, Empty>>,
+    #[account(init, payer = payer, space = 8)]
+    pub account4: Box<Account<'info, Empty>>,
+    #[account(init, payer = payer, space = 8)]
+    pub account5: Box<Account<'info, Empty>>,
+    #[account(init, payer = payer, space = 8)]
+    pub account6: Box<Account<'info, Empty>>,
+    #[account(init, payer = payer, space = 8)]
+    pub account7: Box<Account<'info, Empty>>,
+    #[account(init, payer = payer, space = 8)]
+    pub account8: Box<Account<'info, Empty>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountEmpty1<'info> {
+    pub account1: Box<Account<'info, Empty>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountEmpty2<'info> {
+    pub account1: Box<Account<'info, Empty>>,
+    pub account2: Box<Account<'info, Empty>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountEmpty4<'info> {
+    pub account1: Box<Account<'info, Empty>>,
+    pub account2: Box<Account<'info, Empty>>,
+    pub account3: Box<Account<'info, Empty>>,
+    pub account4: Box<Account<'info, Empty>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountEmpty8<'info> {
+    pub account1: Box<Account<'info, Empty>>,
+    pub account2: Box<Account<'info, Empty>>,
+    pub account3: Box<Account<'info, Empty>>,
+    pub account4: Box<Account<'info, Empty>>,
+    pub account5: Box<Account<'info, Empty>>,
+    pub account6: Box<Account<'info, Empty>>,
+    pub account7: Box<Account<'info, Empty>>,
+    pub account8: Box<Account<'info, Empty>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountSizedInit1<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account1: Box<Account<'info, Sized>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountSizedInit2<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account1: Box<Account<'info, Sized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account2: Box<Account<'info, Sized>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountSizedInit4<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account1: Box<Account<'info, Sized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account2: Box<Account<'info, Sized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account3: Box<Account<'info, Sized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account4: Box<Account<'info, Sized>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountSizedInit8<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account1: Box<Account<'info, Sized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account2: Box<Account<'info, Sized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account3: Box<Account<'info, Sized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account4: Box<Account<'info, Sized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account5: Box<Account<'info, Sized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account6: Box<Account<'info, Sized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account7: Box<Account<'info, Sized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Sized>())]
+    pub account8: Box<Account<'info, Sized>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountSized1<'info> {
+    pub account1: Box<Account<'info, Sized>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountSized2<'info> {
+    pub account1: Box<Account<'info, Sized>>,
+    pub account2: Box<Account<'info, Sized>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountSized4<'info> {
+    pub account1: Box<Account<'info, Sized>>,
+    pub account2: Box<Account<'info, Sized>>,
+    pub account3: Box<Account<'info, Sized>>,
+    pub account4: Box<Account<'info, Sized>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountSized8<'info> {
+    pub account1: Box<Account<'info, Sized>>,
+    pub account2: Box<Account<'info, Sized>>,
+    pub account3: Box<Account<'info, Sized>>,
+    pub account4: Box<Account<'info, Sized>>,
+    pub account5: Box<Account<'info, Sized>>,
+    pub account6: Box<Account<'info, Sized>>,
+    pub account7: Box<Account<'info, Sized>>,
+    pub account8: Box<Account<'info, Sized>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountUnsizedInit1<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account1: Box<Account<'info, Unsized>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountUnsizedInit2<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account1: Box<Account<'info, Unsized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account2: Box<Account<'info, Unsized>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountUnsizedInit4<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account1: Box<Account<'info, Unsized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account2: Box<Account<'info, Unsized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account3: Box<Account<'info, Unsized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account4: Box<Account<'info, Unsized>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountUnsizedInit8<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account1: Box<Account<'info, Unsized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account2: Box<Account<'info, Unsized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account3: Box<Account<'info, Unsized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account4: Box<Account<'info, Unsized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account5: Box<Account<'info, Unsized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account6: Box<Account<'info, Unsized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account7: Box<Account<'info, Unsized>>,
+    #[account(init, payer = payer, space = 8 + std::mem::size_of::<Unsized>())]
+    pub account8: Box<Account<'info, Unsized>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountUnsized1<'info> {
+    pub account1: Box<Account<'info, Unsized>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountUnsized2<'info> {
+    pub account1: Box<Account<'info, Unsized>>,
+    pub account2: Box<Account<'info, Unsized>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountUnsized4<'info> {
+    pub account1: Box<Account<'info, Unsized>>,
+    pub account2: Box<Account<'info, Unsized>>,
+    pub account3: Box<Account<'info, Unsized>>,
+    pub account4: Box<Account<'info, Unsized>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedAccountUnsized8<'info> {
+    pub account1: Box<Account<'info, Unsized>>,
+    pub account2: Box<Account<'info, Unsized>>,
+    pub account3: Box<Account<'info, Unsized>>,
+    pub account4: Box<Account<'info, Unsized>>,
+    pub account5: Box<Account<'info, Unsized>>,
+    pub account6: Box<Account<'info, Unsized>>,
+    pub account7: Box<Account<'info, Unsized>>,
+    pub account8: Box<Account<'info, Unsized>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedInterfaceAccountMint1<'info> {
+    pub account1: Box<InterfaceAccount<'info, Mint>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedInterfaceAccountMint2<'info> {
+    pub account1: Box<InterfaceAccount<'info, Mint>>,
+    pub account2: Box<InterfaceAccount<'info, Mint>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedInterfaceAccountMint4<'info> {
+    pub account1: Box<InterfaceAccount<'info, Mint>>,
+    pub account2: Box<InterfaceAccount<'info, Mint>>,
+    pub account3: Box<InterfaceAccount<'info, Mint>>,
+    pub account4: Box<InterfaceAccount<'info, Mint>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedInterfaceAccountMint8<'info> {
+    pub account1: Box<InterfaceAccount<'info, Mint>>,
+    pub account2: Box<InterfaceAccount<'info, Mint>>,
+    pub account3: Box<InterfaceAccount<'info, Mint>>,
+    pub account4: Box<InterfaceAccount<'info, Mint>>,
+    pub account5: Box<InterfaceAccount<'info, Mint>>,
+    pub account6: Box<InterfaceAccount<'info, Mint>>,
+    pub account7: Box<InterfaceAccount<'info, Mint>>,
+    pub account8: Box<InterfaceAccount<'info, Mint>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedInterfaceAccountToken1<'info> {
+    pub account1: Box<InterfaceAccount<'info, TokenAccount>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedInterfaceAccountToken2<'info> {
+    pub account1: Box<InterfaceAccount<'info, TokenAccount>>,
+    pub account2: Box<InterfaceAccount<'info, TokenAccount>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedInterfaceAccountToken4<'info> {
+    pub account1: Box<InterfaceAccount<'info, TokenAccount>>,
+    pub account2: Box<InterfaceAccount<'info, TokenAccount>>,
+    pub account3: Box<InterfaceAccount<'info, TokenAccount>>,
+    pub account4: Box<InterfaceAccount<'info, TokenAccount>>,
+}
+
+#[derive(Accounts)]
+pub struct BoxedInterfaceAccountToken8<'info> {
+    pub account1: Box<InterfaceAccount<'info, TokenAccount>>,
+    pub account2: Box<InterfaceAccount<'info, TokenAccount>>,
+    pub account3: Box<InterfaceAccount<'info, TokenAccount>>,
+    pub account4: Box<InterfaceAccount<'info, TokenAccount>>,
+    pub account5: Box<InterfaceAccount<'info, TokenAccount>>,
+    pub account6: Box<InterfaceAccount<'info, TokenAccount>>,
+    pub account7: Box<InterfaceAccount<'info, TokenAccount>>,
+    pub account8: Box<InterfaceAccount<'info, TokenAccount>>,
+}
+
+#[derive(Accounts)]
+pub struct InterfaceAccountMint1<'info> {
+    pub account1: InterfaceAccount<'info, Mint>,
+}
+
+#[derive(Accounts)]
+pub struct InterfaceAccountMint2<'info> {
+    pub account1: InterfaceAccount<'info, Mint>,
+    pub account2: InterfaceAccount<'info, Mint>,
+}
+
+#[derive(Accounts)]
+pub struct InterfaceAccountMint4<'info> {
+    pub account1: InterfaceAccount<'info, Mint>,
+    pub account2: InterfaceAccount<'info, Mint>,
+    pub account3: InterfaceAccount<'info, Mint>,
+    pub account4: InterfaceAccount<'info, Mint>,
+}
+
+#[derive(Accounts)]
+pub struct InterfaceAccountMint8<'info> {
+    pub account1: InterfaceAccount<'info, Mint>,
+    pub account2: InterfaceAccount<'info, Mint>,
+    pub account3: InterfaceAccount<'info, Mint>,
+    pub account4: InterfaceAccount<'info, Mint>,
+    pub account5: InterfaceAccount<'info, Mint>,
+    pub account6: InterfaceAccount<'info, Mint>,
+    pub account7: InterfaceAccount<'info, Mint>,
+    pub account8: InterfaceAccount<'info, Mint>,
+}
+
+#[derive(Accounts)]
+pub struct InterfaceAccountToken1<'info> {
+    pub account1: InterfaceAccount<'info, TokenAccount>,
+}
+
+#[derive(Accounts)]
+pub struct InterfaceAccountToken2<'info> {
+    pub account1: InterfaceAccount<'info, TokenAccount>,
+    pub account2: InterfaceAccount<'info, TokenAccount>,
+}
+
+#[derive(Accounts)]
+pub struct InterfaceAccountToken4<'info> {
+    pub account1: InterfaceAccount<'info, TokenAccount>,
+    pub account2: InterfaceAccount<'info, TokenAccount>,
+    pub account3: InterfaceAccount<'info, TokenAccount>,
+    pub account4: InterfaceAccount<'info, TokenAccount>,
+}
+
+#[derive(Accounts)]
+pub struct Interface1<'info> {
+    pub account1: Interface<'info, TokenInterface>,
+}
+
+#[derive(Accounts)]
+pub struct Interface2<'info> {
+    pub account1: Interface<'info, TokenInterface>,
+    pub account2: Interface<'info, TokenInterface>,
+}
+
+#[derive(Accounts)]
+pub struct Interface4<'info> {
+    pub account1: Interface<'info, TokenInterface>,
+    pub account2: Interface<'info, TokenInterface>,
+    pub account3: Interface<'info, TokenInterface>,
+    pub account4: Interface<'info, TokenInterface>,
+}
+
+#[derive(Accounts)]
+pub struct Interface8<'info> {
+    pub account1: Interface<'info, TokenInterface>,
+    pub account2: Interface<'info, TokenInterface>,
+    pub account3: Interface<'info, TokenInterface>,
+    pub account4: Interface<'info, TokenInterface>,
+    pub account5: Interface<'info, TokenInterface>,
+    pub account6: Interface<'info, TokenInterface>,
+    pub account7: Interface<'info, TokenInterface>,
+    pub account8: Interface<'info, TokenInterface>,
+}
+
+#[derive(Accounts)]
+pub struct Program1<'info> {
+    pub account1: Program<'info, System>,
+}
+
+#[derive(Accounts)]
+pub struct Program2<'info> {
+    pub account1: Program<'info, System>,
+    pub account2: Program<'info, System>,
+}
+
+#[derive(Accounts)]
+pub struct Program4<'info> {
+    pub account1: Program<'info, System>,
+    pub account2: Program<'info, System>,
+    pub account3: Program<'info, System>,
+    pub account4: Program<'info, System>,
+}
+
+#[derive(Accounts)]
+pub struct Program8<'info> {
+    pub account1: Program<'info, System>,
+    pub account2: Program<'info, System>,
+    pub account3: Program<'info, System>,
+    pub account4: Program<'info, System>,
+    pub account5: Program<'info, System>,
+    pub account6: Program<'info, System>,
+    pub account7: Program<'info, System>,
+    pub account8: Program<'info, System>,
+}
+
+#[derive(Accounts)]
+pub struct Signer1<'info> {
+    pub account1: Signer<'info>,
+}
+
+#[derive(Accounts)]
+pub struct Signer2<'info> {
+    pub account1: Signer<'info>,
+    pub account2: Signer<'info>,
+}
+
+#[derive(Accounts)]
+pub struct Signer4<'info> {
+    pub account1: Signer<'info>,
+    pub account2: Signer<'info>,
+    pub account3: Signer<'info>,
+    pub account4: Signer<'info>,
+}
+
+#[derive(Accounts)]
+pub struct Signer8<'info> {
+    pub account1: Signer<'info>,
+    pub account2: Signer<'info>,
+    pub account3: Signer<'info>,
+    pub account4: Signer<'info>,
+    pub account5: Signer<'info>,
+    pub account6: Signer<'info>,
+    pub account7: Signer<'info>,
+    pub account8: Signer<'info>,
+}
+
+#[derive(Accounts)]
+pub struct SystemAccount1<'info> {
+    pub account1: SystemAccount<'info>,
+}
+
+#[derive(Accounts)]
+pub struct SystemAccount2<'info> {
+    pub account1: SystemAccount<'info>,
+    pub account2: SystemAccount<'info>,
+}
+
+#[derive(Accounts)]
+pub struct SystemAccount4<'info> {
+    pub account1: SystemAccount<'info>,
+    pub account2: SystemAccount<'info>,
+    pub account3: SystemAccount<'info>,
+    pub account4: SystemAccount<'info>,
+}
+
+#[derive(Accounts)]
+pub struct SystemAccount8<'info> {
+    pub account1: SystemAccount<'info>,
+    pub account2: SystemAccount<'info>,
+    pub account3: SystemAccount<'info>,
+    pub account4: SystemAccount<'info>,
+    pub account5: SystemAccount<'info>,
+    pub account6: SystemAccount<'info>,
+    pub account7: SystemAccount<'info>,
+    pub account8: SystemAccount<'info>,
+}
+
+#[derive(Accounts)]
+pub struct UncheckedAccount1<'info> {
+    pub account1: UncheckedAccount<'info>,
+}
+
+#[derive(Accounts)]
+pub struct UncheckedAccount2<'info> {
+    pub account1: UncheckedAccount<'info>,
+    pub account2: UncheckedAccount<'info>,
+}
+
+#[derive(Accounts)]
+pub struct UncheckedAccount4<'info> {
+    pub account1: UncheckedAccount<'info>,
+    pub account2: UncheckedAccount<'info>,
+    pub account3: UncheckedAccount<'info>,
+    pub account4: UncheckedAccount<'info>,
+}
+
+#[derive(Accounts)]
+pub struct UncheckedAccount8<'info> {
+    pub account1: UncheckedAccount<'info>,
+    pub account2: UncheckedAccount<'info>,
+    pub account3: UncheckedAccount<'info>,
+    pub account4: UncheckedAccount<'info>,
+    pub account5: UncheckedAccount<'info>,
+    pub account6: UncheckedAccount<'info>,
+    pub account7: UncheckedAccount<'info>,
+    pub account8: UncheckedAccount<'info>,
+}

+ 25 - 0
tests/bench/scripts/bump-version.ts

@@ -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);
+  });
+})();

+ 225 - 0
tests/bench/scripts/generate-ix.ts

@@ -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);
+})();

+ 67 - 0
tests/bench/scripts/update-bench.ts

@@ -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);
+      }
+    }
+  });
+})();

+ 298 - 0
tests/bench/scripts/utils.ts

@@ -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",
+      ""
+    );
+  }
+}

+ 248 - 0
tests/bench/tests/compute-units.ts

@@ -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"]);
+    }
+  });
+});

+ 12 - 0
tests/bench/tsconfig.json

@@ -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
+  }
+}

+ 1 - 0
tests/package.json

@@ -8,6 +8,7 @@
   "workspaces": [
     "anchor-cli-account",
     "anchor-cli-idl",
+    "bench",
     "cashiers-check",
     "cfo",
     "chat",

+ 15 - 7
version-bump.sh

@@ -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"