Skip to content

Commit 94fed8a

Browse files
committed
benchmarking compute
1 parent 6ee8744 commit 94fed8a

File tree

7 files changed

+305
-3
lines changed

7 files changed

+305
-3
lines changed

Cargo.lock

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

program/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ solana-program = "2.0.1"
2222

2323
[dev-dependencies]
2424
mollusk-svm = { version = "0.0.5", features = ["fuzz"] }
25+
mollusk-svm-bencher = "0.0.5"
2526
solana-sdk = "2.0.1"
2627

2728
[lib]
2829
crate-type = ["cdylib", "lib"]
30+
31+
[[bench]]
32+
name = "compute_units"
33+
harness = false

program/benches/compute_units.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#### Compute Units: 2024-10-22 15:36:06.732383 UTC
2+
3+
| Name | CUs | Delta |
4+
|------|------|-------|
5+
| config_small_init_0_keys | 581 | - new - |
6+
| config_small_init_1_keys | 1204 | - new - |
7+
| config_small_init_5_keys | 2799 | - new - |
8+
| config_small_init_10_keys | 4839 | - new - |
9+
| config_small_init_25_keys | 11591 | - new - |
10+
| config_small_init_37_keys | 16522 | - new - |
11+
| config_small_store_0_keys | 581 | - new - |
12+
| config_small_store_1_keys | 1458 | - new - |
13+
| config_small_store_5_keys | 3969 | - new - |
14+
| config_small_store_10_keys | 7154 | - new - |
15+
| config_small_store_25_keys | 17341 | - new - |
16+
| config_small_store_37_keys | 25020 | - new - |
17+
| config_medium_init_0_keys | 572 | - new - |
18+
| config_medium_init_1_keys | 1151 | - new - |
19+
| config_medium_init_5_keys | 2799 | - new - |
20+
| config_medium_init_10_keys | 4839 | - new - |
21+
| config_medium_init_25_keys | 11591 | - new - |
22+
| config_medium_init_37_keys | 16522 | - new - |
23+
| config_medium_store_0_keys | 572 | - new - |
24+
| config_medium_store_1_keys | 1405 | - new - |
25+
| config_medium_store_5_keys | 3969 | - new - |
26+
| config_medium_store_10_keys | 7154 | - new - |
27+
| config_medium_store_25_keys | 17341 | - new - |
28+
| config_medium_store_37_keys | 25020 | - new - |
29+
| config_large_init_0_keys | 572 | - new - |
30+
| config_large_init_1_keys | 1151 | - new - |
31+
| config_large_init_5_keys | 2799 | - new - |
32+
| config_large_init_10_keys | 4839 | - new - |
33+
| config_large_init_25_keys | 11591 | - new - |
34+
| config_large_init_37_keys | 16522 | - new - |
35+
| config_large_store_0_keys | 572 | - new - |
36+
| config_large_store_1_keys | 1405 | - new - |
37+
| config_large_store_5_keys | 3969 | - new - |
38+
| config_large_store_10_keys | 7154 | - new - |
39+
| config_large_store_25_keys | 17341 | - new - |
40+
| config_large_store_37_keys | 25020 | - new - |
41+

program/benches/compute_units.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//! Compute unit benchmark testing.
2+
3+
mod setup;
4+
5+
use {
6+
crate::setup::{BenchSetup, ConfigLarge, ConfigMedium, ConfigSmall},
7+
mollusk_svm::Mollusk,
8+
mollusk_svm_bencher::MolluskComputeUnitBencher,
9+
};
10+
11+
fn main() {
12+
std::env::set_var("SBF_OUT_DIR", "../target/deploy");
13+
let mollusk = Mollusk::new(&solana_config_program::id(), "solana_config_program");
14+
15+
MolluskComputeUnitBencher::new(mollusk)
16+
.bench(ConfigSmall::init(0).bench())
17+
.bench(ConfigSmall::init(1).bench())
18+
.bench(ConfigSmall::init(5).bench())
19+
.bench(ConfigSmall::init(10).bench())
20+
.bench(ConfigSmall::init(25).bench())
21+
.bench(ConfigSmall::init(37).bench())
22+
.bench(ConfigSmall::store(0).bench())
23+
.bench(ConfigSmall::store(1).bench())
24+
.bench(ConfigSmall::store(5).bench())
25+
.bench(ConfigSmall::store(10).bench())
26+
.bench(ConfigSmall::store(25).bench())
27+
.bench(ConfigSmall::store(37).bench())
28+
.bench(ConfigMedium::init(0).bench())
29+
.bench(ConfigMedium::init(1).bench())
30+
.bench(ConfigMedium::init(5).bench())
31+
.bench(ConfigMedium::init(10).bench())
32+
.bench(ConfigMedium::init(25).bench())
33+
.bench(ConfigMedium::init(37).bench())
34+
.bench(ConfigMedium::store(0).bench())
35+
.bench(ConfigMedium::store(1).bench())
36+
.bench(ConfigMedium::store(5).bench())
37+
.bench(ConfigMedium::store(10).bench())
38+
.bench(ConfigMedium::store(25).bench())
39+
.bench(ConfigMedium::store(37).bench())
40+
.bench(ConfigLarge::init(0).bench())
41+
.bench(ConfigLarge::init(1).bench())
42+
.bench(ConfigLarge::init(5).bench())
43+
.bench(ConfigLarge::init(10).bench())
44+
.bench(ConfigLarge::init(25).bench())
45+
.bench(ConfigLarge::init(37).bench())
46+
.bench(ConfigLarge::store(0).bench())
47+
.bench(ConfigLarge::store(1).bench())
48+
.bench(ConfigLarge::store(5).bench())
49+
.bench(ConfigLarge::store(10).bench())
50+
.bench(ConfigLarge::store(25).bench())
51+
.bench(ConfigLarge::store(37).bench())
52+
.must_pass(true)
53+
.out_dir("./benches")
54+
.execute();
55+
}

program/benches/setup.rs

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
use {
2+
mollusk_svm_bencher::Bench,
3+
serde::{Deserialize, Serialize},
4+
solana_config_program::{
5+
instruction::store,
6+
state::{ConfigKeys, ConfigState},
7+
},
8+
solana_sdk::{
9+
account::AccountSharedData,
10+
hash::Hash,
11+
instruction::{AccountMeta, Instruction},
12+
pubkey::Pubkey,
13+
rent::Rent,
14+
},
15+
};
16+
17+
/// Helper struct to convert to a `Bench`.
18+
pub struct BenchContext {
19+
label: String,
20+
instruction: Instruction,
21+
accounts: Vec<(Pubkey, AccountSharedData)>,
22+
}
23+
24+
impl BenchContext {
25+
/// Convert to a `Bench`.
26+
pub fn bench(&self) -> Bench {
27+
(self.label.as_str(), &self.instruction, &self.accounts)
28+
}
29+
}
30+
31+
/// Trait to avoid re-defining the same instruction and account constructors
32+
/// for each `ConfigState`.
33+
pub trait BenchSetup: ConfigState + Default {
34+
const BENCH_ID: &'static str;
35+
36+
fn default_account_state(keys: Vec<(Pubkey, bool)>) -> (ConfigKeys, Self) {
37+
(ConfigKeys { keys }, Self::default())
38+
}
39+
40+
#[allow(clippy::arithmetic_side_effects)]
41+
fn default_space(keys: Vec<(Pubkey, bool)>) -> usize {
42+
(Self::max_space() + ConfigKeys::serialized_size(keys)) as usize
43+
}
44+
45+
fn keys(keys_len: usize) -> Vec<(Pubkey, bool)> {
46+
(0..keys_len)
47+
.map(|_| (Pubkey::new_unique(), false))
48+
.collect()
49+
}
50+
51+
fn test_store_value() -> Self;
52+
53+
fn init(keys_len: usize) -> BenchContext {
54+
let config_pubkey = Pubkey::new_unique();
55+
let keys = Self::keys(keys_len);
56+
let space = Self::default_space(keys.clone());
57+
let lamports = Rent::default().minimum_balance(space);
58+
59+
let instruction = {
60+
let account_metas = vec![AccountMeta::new(config_pubkey, true)];
61+
let account_data = Self::default_account_state(keys);
62+
Instruction::new_with_bincode(solana_config_program::id(), &account_data, account_metas)
63+
};
64+
65+
let accounts = vec![(
66+
config_pubkey,
67+
AccountSharedData::new(lamports, space, &solana_config_program::id()),
68+
)];
69+
70+
BenchContext {
71+
label: format!("{}_init_{}_keys", Self::BENCH_ID, keys_len),
72+
instruction,
73+
accounts,
74+
}
75+
}
76+
77+
fn store(keys_len: usize) -> BenchContext {
78+
let config_pubkey = Pubkey::new_unique();
79+
let keys = Self::keys(keys_len);
80+
let space = Self::default_space(keys.clone());
81+
let lamports = Rent::default().minimum_balance(space);
82+
83+
let instruction = store(
84+
&config_pubkey,
85+
true,
86+
keys.clone(),
87+
&Self::test_store_value(),
88+
);
89+
90+
let accounts = vec![(
91+
config_pubkey,
92+
AccountSharedData::new_data(
93+
lamports,
94+
&Self::default_account_state(keys),
95+
&solana_config_program::id(),
96+
)
97+
.unwrap(),
98+
)];
99+
100+
BenchContext {
101+
label: format!("{}_store_{}_keys", Self::BENCH_ID, keys_len),
102+
instruction,
103+
accounts,
104+
}
105+
}
106+
}
107+
108+
/// A small config, which just stores 8 bytes.
109+
#[derive(Debug, Default, PartialEq, Deserialize, Serialize)]
110+
pub struct ConfigSmall {
111+
pub item: u64,
112+
}
113+
114+
impl ConfigState for ConfigSmall {
115+
fn max_space() -> u64 {
116+
bincode::serialized_size(&Self::default()).unwrap()
117+
}
118+
}
119+
120+
impl BenchSetup for ConfigSmall {
121+
const BENCH_ID: &'static str = "config_small";
122+
123+
fn test_store_value() -> Self {
124+
Self { item: 42 }
125+
}
126+
}
127+
128+
/// A medium config, which stores 256 bytes.
129+
#[derive(Debug, Default, PartialEq, Deserialize, Serialize)]
130+
pub struct ConfigMedium {
131+
pub hashes: [Hash; 8], // 32 x 8 = 256 bytes
132+
pub rent: Rent,
133+
}
134+
135+
impl ConfigState for ConfigMedium {
136+
fn max_space() -> u64 {
137+
bincode::serialized_size(&Self::default()).unwrap()
138+
}
139+
}
140+
141+
impl BenchSetup for ConfigMedium {
142+
const BENCH_ID: &'static str = "config_medium";
143+
144+
fn test_store_value() -> Self {
145+
Self {
146+
hashes: [[1; 32].into(); 8],
147+
rent: Rent::default(),
148+
}
149+
}
150+
}
151+
152+
/// A large config, which stores 1024 bytes.
153+
#[derive(Debug, Default, PartialEq, Deserialize, Serialize)]
154+
pub struct ConfigLarge {
155+
pub hashes: [Hash; 32], // 32 x 32 = 1024 bytes
156+
pub rent: Rent,
157+
}
158+
159+
impl ConfigState for ConfigLarge {
160+
fn max_space() -> u64 {
161+
bincode::serialized_size(&Self::default()).unwrap()
162+
}
163+
}
164+
165+
impl BenchSetup for ConfigLarge {
166+
const BENCH_ID: &'static str = "config_large";
167+
168+
fn test_store_value() -> Self {
169+
Self {
170+
hashes: [[1; 32].into(); 32],
171+
rent: Rent::default(),
172+
}
173+
}
174+
}

program/tests/functional.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ fn setup() -> Mollusk {
4141
Mollusk::new(&solana_config_program::id(), "solana_config_program")
4242
}
4343

44+
#[allow(clippy::arithmetic_side_effects)]
4445
fn get_config_space(key_len: usize) -> usize {
4546
let entry_size = bincode::serialized_size(&(Pubkey::default(), true)).unwrap() as usize;
4647
bincode::serialized_size(&(ConfigKeys::default(), MyConfig::default())).unwrap() as usize
@@ -49,7 +50,7 @@ fn get_config_space(key_len: usize) -> usize {
4950

5051
fn create_config_account(mollusk: &Mollusk, keys: Vec<(Pubkey, bool)>) -> AccountSharedData {
5152
let space = get_config_space(keys.len());
52-
let lamports = mollusk.sysvars.rent.minimum_balance(space as usize);
53+
let lamports = mollusk.sysvars.rent.minimum_balance(space);
5354
AccountSharedData::new_data(
5455
lamports,
5556
&(ConfigKeys { keys }, MyConfig::default()),
@@ -66,7 +67,7 @@ fn test_process_create_ok() {
6667
let config_account = {
6768
let space = get_config_space(0);
6869
let lamports = mollusk.sysvars.rent.minimum_balance(space);
69-
AccountSharedData::new(lamports, space as usize, &solana_config_program::id())
70+
AccountSharedData::new(lamports, space, &solana_config_program::id())
7071
};
7172

7273
// `instruction::initialize_account` without making it public...
@@ -518,7 +519,7 @@ fn test_config_bad_owner() {
518519
// Store a config account with the wrong owner.
519520
let config_account = {
520521
let space = get_config_space(keys.len());
521-
let lamports = mollusk.sysvars.rent.minimum_balance(space as usize);
522+
let lamports = mollusk.sysvars.rent.minimum_balance(space);
522523
AccountSharedData::new(lamports, 0, &Pubkey::new_unique())
523524
};
524525

scripts/program/lint.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
// ['--arg1', '--arg2', ...cliArguments()]
1313
const lintArgs = [
1414
'-Zunstable-options',
15+
'--tests',
16+
'--benches',
1517
'--features',
1618
'bpf-entrypoint,test-sbf',
1719
'--',

0 commit comments

Comments
 (0)