Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Benchmarking Compute Units #19

Merged
merged 2 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,38 @@ jobs:

- name: Test Programs
run: pnpm programs:test

bench_program_compute_units:
name: Benchmark Program Compute Units
runs-on: ubuntu-latest
needs: build_programs # Cargo Bench won't build the SBPF binary...
steps:
- name: Git Checkout
uses: actions/checkout@v4

- name: Setup Environment
uses: ./.github/actions/setup
with:
cargo-cache-key: cargo-program-benches
cargo-cache-fallback-key: cargo-programs
solana: true

- name: Restore Program Builds
uses: actions/cache/restore@v4
with:
path: ./**/*.so
key: ${{ runner.os }}-builds-${{ github.sha }}

- name: Benchmark Compute Units
run: pnpm programs:bench

- name: Check Working Directory
run: |
if [ -n "$(git status --porcelain)" ]; then
test -z "$(git status --porcelain)"
echo "CU usage has changed. Please run `cargo bench` and commit the new results.";
exit 1;
fi

generate_clients:
name: Check Client Generation
Expand Down
26 changes: 26 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"scripts": {
"programs:build": "zx ./scripts/program/build.mjs",
"programs:test": "zx ./scripts/program/test.mjs",
"programs:bench": "zx ./scripts/program/bench.mjs",
"programs:clean": "zx ./scripts/program/clean.mjs",
"programs:format": "zx ./scripts/program/format.mjs",
"programs:lint": "zx ./scripts/program/lint.mjs",
Expand Down
5 changes: 5 additions & 0 deletions program/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,17 @@ spl-program-error = "0.5.0"

[dev-dependencies]
mollusk-svm = { version = "0.0.5", features = ["fuzz"] }
mollusk-svm-bencher = "0.0.5"
solana-sdk = "2.0.1"
test-case = "3.3.1"

[lib]
crate-type = ["cdylib", "lib"]

[[bench]]
name = "compute_units"
harness = false

[lints.rust.unexpected_cfgs]
level = "warn"
check-cfg = [
Expand Down
26 changes: 26 additions & 0 deletions program/benches/compute_units.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#### Compute Units: 2024-10-22 17:54:37.721198 UTC

| Name | CUs | Delta |
|------|------|-------|
| create_lookup_table | 10748 | - new - |
| freeze_lookup_table | 1510 | - new - |
| extend_lookup_table_from_0_to_1 | 6216 | - new - |
| extend_lookup_table_from_0_to_10 | 8880 | - new - |
| extend_lookup_table_from_0_to_38 | 17256 | - new - |
| extend_lookup_table_from_1_to_2 | 6216 | - new - |
| extend_lookup_table_from_1_to_10 | 8581 | - new - |
| extend_lookup_table_from_1_to_39 | 17256 | - new - |
| extend_lookup_table_from_5_to_6 | 6216 | - new - |
| extend_lookup_table_from_5_to_15 | 8881 | - new - |
| extend_lookup_table_from_5_to_43 | 17256 | - new - |
| extend_lookup_table_from_25_to_26 | 6219 | - new - |
| extend_lookup_table_from_25_to_35 | 8883 | - new - |
| extend_lookup_table_from_25_to_63 | 17259 | - new - |
| extend_lookup_table_from_50_to_88 | 17262 | - new - |
| extend_lookup_table_from_100_to_138 | 17268 | - new - |
| extend_lookup_table_from_150_to_188 | 17275 | - new - |
| extend_lookup_table_from_200_to_238 | 17281 | - new - |
| extend_lookup_table_from_255_to_256 | 6248 | - new - |
| deactivate_lookup_table | 3143 | - new - |
| close_lookup_table | 2220 | - new - |

49 changes: 49 additions & 0 deletions program/benches/compute_units.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//! Address Lookup Table program compute unit benchmark testing.

mod setup;

use {
crate::setup::{
close_lookup_table, create_lookup_table, deactivate_lookup_table, extend_lookup_table,
freeze_lookup_table, TEST_CLOCK_SLOT,
},
mollusk_svm::Mollusk,
mollusk_svm_bencher::MolluskComputeUnitBencher,
};

fn main() {
std::env::set_var("SBF_OUT_DIR", "../target/deploy");

let mut mollusk = Mollusk::new(
&solana_address_lookup_table_program::id(),
"solana_address_lookup_table_program",
);

mollusk.warp_to_slot(TEST_CLOCK_SLOT);

MolluskComputeUnitBencher::new(mollusk)
.bench(create_lookup_table().bench())
.bench(freeze_lookup_table().bench())
.bench(extend_lookup_table(0, 1).bench())
.bench(extend_lookup_table(0, 10).bench())
.bench(extend_lookup_table(0, 38).bench())
.bench(extend_lookup_table(1, 2).bench())
.bench(extend_lookup_table(1, 10).bench())
.bench(extend_lookup_table(1, 39).bench())
.bench(extend_lookup_table(5, 6).bench())
.bench(extend_lookup_table(5, 15).bench())
.bench(extend_lookup_table(5, 43).bench())
.bench(extend_lookup_table(25, 26).bench())
.bench(extend_lookup_table(25, 35).bench())
.bench(extend_lookup_table(25, 63).bench())
.bench(extend_lookup_table(50, 88).bench())
.bench(extend_lookup_table(100, 138).bench())
.bench(extend_lookup_table(150, 188).bench())
.bench(extend_lookup_table(200, 238).bench())
.bench(extend_lookup_table(255, 256).bench())
.bench(deactivate_lookup_table().bench())
.bench(close_lookup_table().bench())
.must_pass(true)
.out_dir("./benches")
.execute();
}
169 changes: 169 additions & 0 deletions program/benches/setup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
use {
mollusk_svm::program::keyed_account_for_system_program,
mollusk_svm_bencher::Bench,
solana_address_lookup_table_program::{
instruction::{
close_lookup_table as close_lookup_table_ix,
create_lookup_table as create_lookup_table_ix,
deactivate_lookup_table as deactivate_lookup_table_ix,
extend_lookup_table as extend_lookup_table_ix,
freeze_lookup_table as freeze_lookup_table_ix,
},
state::{AddressLookupTable, LookupTableMeta},
},
solana_sdk::{
account::AccountSharedData, instruction::Instruction, pubkey::Pubkey, rent::Rent,
system_program,
},
std::borrow::Cow,
};

pub const TEST_CLOCK_SLOT: u64 = 100_000;

/// Helper struct to convert to a `Bench`.
pub struct BenchContext {
label: String,
instruction: Instruction,
accounts: Vec<(Pubkey, AccountSharedData)>,
}

impl BenchContext {
/// Convert to a `Bench`.
pub fn bench(&self) -> Bench {
(self.label.as_str(), &self.instruction, &self.accounts)
}
}

fn lookup_table_account(
authority: &Pubkey,
num_keys: usize,
deactivated: bool,
) -> AccountSharedData {
let state = {
let mut addresses = Vec::with_capacity(num_keys);
addresses.resize_with(num_keys, Pubkey::new_unique);
AddressLookupTable {
meta: LookupTableMeta {
authority: Some(*authority),
deactivation_slot: if deactivated { 1 } else { u64::MAX },
..LookupTableMeta::default()
},
addresses: Cow::Owned(addresses),
}
};
let data = state.serialize_for_tests().unwrap();
let data_len = data.len();
let lamports = Rent::default().minimum_balance(data_len);
let mut account = AccountSharedData::new(
lamports,
data_len,
&solana_address_lookup_table_program::id(),
);
account.set_data_from_slice(&data);
account
}

pub fn create_lookup_table() -> BenchContext {
let authority = Pubkey::new_unique();
let payer = Pubkey::new_unique();

let (instruction, lookup_table) = create_lookup_table_ix(authority, payer, TEST_CLOCK_SLOT - 1);

let accounts = vec![
(lookup_table, AccountSharedData::default()),
(authority, AccountSharedData::default()),
(
payer,
AccountSharedData::new(100_000_000_000, 0, &system_program::id()),
),
keyed_account_for_system_program(),
];

BenchContext {
label: "create_lookup_table".to_string(),
instruction,
accounts,
}
}

pub fn extend_lookup_table(from: usize, to: usize) -> BenchContext {
let lookup_table = Pubkey::new_unique();
let authority = Pubkey::new_unique();
let payer = Pubkey::new_unique();

let new_addresses = (from..to).map(|_| Pubkey::new_unique()).collect::<Vec<_>>();

let instruction = extend_lookup_table_ix(lookup_table, authority, Some(payer), new_addresses);

let accounts = vec![
(lookup_table, lookup_table_account(&authority, from, false)),
(authority, AccountSharedData::default()),
(
payer,
AccountSharedData::new(100_000_000_000, 0, &system_program::id()),
),
keyed_account_for_system_program(),
];

BenchContext {
label: format!("extend_lookup_table_from_{}_to_{}", from, to),
instruction,
accounts,
}
}

pub fn freeze_lookup_table() -> BenchContext {
let lookup_table = Pubkey::new_unique();
let authority = Pubkey::new_unique();

let instruction = freeze_lookup_table_ix(lookup_table, authority);

let accounts = vec![
(lookup_table, lookup_table_account(&authority, 1, false)),
(authority, AccountSharedData::default()),
];

BenchContext {
label: "freeze_lookup_table".to_string(),
instruction,
accounts,
}
}

pub fn deactivate_lookup_table() -> BenchContext {
let lookup_table = Pubkey::new_unique();
let authority = Pubkey::new_unique();

let instruction = deactivate_lookup_table_ix(lookup_table, authority);

let accounts = vec![
(lookup_table, lookup_table_account(&authority, 1, false)),
(authority, AccountSharedData::default()),
];

BenchContext {
label: "deactivate_lookup_table".to_string(),
instruction,
accounts,
}
}

pub fn close_lookup_table() -> BenchContext {
let lookup_table = Pubkey::new_unique();
let authority = Pubkey::new_unique();
let recipient = Pubkey::new_unique();

let instruction = close_lookup_table_ix(lookup_table, authority, recipient);

let accounts = vec![
(lookup_table, lookup_table_account(&authority, 1, true)),
(authority, AccountSharedData::default()),
(recipient, AccountSharedData::default()),
];

BenchContext {
label: "close_lookup_table".to_string(),
instruction,
accounts,
}
}
29 changes: 29 additions & 0 deletions scripts/program/bench.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env zx
import 'zx/globals';
import {
cliArguments,
getProgramFolders,
workingDirectory,
} from '../utils.mjs';

// Save external programs binaries to the output directory.
import './dump.mjs';

// Configure additional arguments here, e.g.:
// ['--arg1', '--arg2', ...cliArguments()]
const benchArgs = cliArguments();

const hasSolfmt = await which('solfmt', { nothrow: true });

// Test the programs.
await Promise.all(
getProgramFolders().map(async (folder) => {
const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml');

if (hasSolfmt) {
await $`RUST_LOG=error cargo bench --manifest-path ${manifestPath} ${benchArgs} 2>&1 | solfmt`;
} else {
await $`RUST_LOG=error cargo bench --manifest-path ${manifestPath} ${benchArgs}`;
}
})
);
Loading