Skip to content

Commit 6d3c671

Browse files
authored
tests: add compute convenience function (#179)
1 parent 7b1ffcd commit 6d3c671

File tree

4 files changed

+106
-17
lines changed

4 files changed

+106
-17
lines changed

Cargo.lock

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

README.md

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,24 +54,24 @@ Previously, the Stake Program was essentially free, costing 1500 Compute Units i
5454

5555
For the initial 1.0.0 release, we followed the existing Agave code as closely as possible, to minimize the possibility of introducing any bugs or changing any behaviors in the port because of the total rewrite of the calling interface the port necessitated. This means the existing program is expected to be non-optimal. With the ability to test more thoroughly against this 1.0.0 version, we expect to be able to optimize these costs in the future.
5656

57-
Based on the sample invocations in `program/tests/interface.rs`, approximate costs as of 2025-07-28 are as follows. These should be treated as baselines and are rounded to thousands; instructions may do less or more work depending on arguments and account states.
57+
Based on the sample invocations in `program/tests/interface.rs`, approximate costs as of 2025-11-14 are as follows. These should be treated as baselines and are rounded to hundreds; instructions may do less or more work depending on arguments and account states.
5858

5959
| Instruction | Estimated Cost |
6060
| --- | --- |
61-
| `Initialize` | 9000 |
62-
| `Authorize` | 12000 |
63-
| `DelegateStake` | 15000 |
64-
| `Split` | 20000 |
65-
| `Withdraw` | 8000 |
66-
| `Deactivate` | 13000 |
67-
| `SetLockup` | 11000 |
68-
| `Merge` | 21000 |
69-
| `AuthorizeWithSeed` | 14000 |
70-
| `InitializeChecked` | 6000 |
71-
| `AuthorizeChecked` | 12000 |
72-
| `AuthorizeCheckedWithSeed` | 14000 |
73-
| `SetLockupChecked` | 11000 |
61+
| `Authorize` | 10500 |
62+
| `AuthorizeChecked` | 10200 |
63+
| `AuthorizeCheckedWithSeed` | 11500 |
64+
| `AuthorizeWithSeed` | 11700 |
65+
| `Deactivate` | 10600 |
66+
| `DeactivateDelinquent` | 11400 |
67+
| `DelegateStake` | 10800 |
7468
| `GetMinimumDelegation` | (negligible) |
75-
| `DeactivateDelinquent` | 18000 |
76-
| `MoveStake` | 25000 |
77-
| `MoveLamports` | 15000 |
69+
| `Initialize` | 7500 |
70+
| `InitializeChecked` | 5200 |
71+
| `Merge` | 17600 |
72+
| `MoveLamports` | 12500 |
73+
| `MoveStake` | 21700 |
74+
| `SetLockup` | 9300 |
75+
| `SetLockupChecked` | 9100 |
76+
| `Split` | 16900 |
77+
| `Withdraw` | 7300 |

program/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ solana-program-test = "3.0.10"
4141
solana-sdk-ids = "3.0.0"
4242
solana-signature = "3.0.0"
4343
solana-signer = "3.0.0"
44+
solana-svm-log-collector = "3.0.0"
4445
solana-system-interface = { version = "2.0.0", features = ["bincode"] }
4546
solana-sysvar-id = "3.0.0"
4647
solana-transaction = "3.0.0"

program/tests/interface.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use {
2222
},
2323
},
2424
solana_stake_program::{get_minimum_delegation, id},
25+
solana_svm_log_collector::LogCollector,
2526
solana_sysvar_id::SysvarId,
2627
solana_vote_interface::{
2728
program as vote_program,
@@ -1123,3 +1124,89 @@ fn test_no_use_dealloc() {
11231124
}
11241125
}
11251126
}
1127+
1128+
// this prints ballpark compute unit costs suitable for insertion in README.md
1129+
// run with `cargo test --test interface show_compute_usage -- --nocapture --ignored`
1130+
#[test]
1131+
#[ignore]
1132+
fn show_compute_usage() {
1133+
let mut env = Env::init();
1134+
solana_logger::setup_with("");
1135+
env.mollusk.logger = Some(LogCollector::new_ref());
1136+
let mut compute_tracker = ComputeTracker::new();
1137+
1138+
for declaration in &*INSTRUCTION_DECLARATIONS {
1139+
let instruction = declaration.to_instruction(&mut env);
1140+
env.process_success(&instruction);
1141+
1142+
let logs = env
1143+
.mollusk
1144+
.logger
1145+
.as_ref()
1146+
.unwrap()
1147+
.replace(LogCollector::default())
1148+
.into_messages();
1149+
1150+
compute_tracker.add(&logs);
1151+
env.reset();
1152+
}
1153+
1154+
compute_tracker.show();
1155+
}
1156+
1157+
struct ComputeTracker(HashMap<String, u64>);
1158+
impl ComputeTracker {
1159+
fn new() -> Self {
1160+
Self(HashMap::from([("GetMinimumDelegation".to_string(), 0)]))
1161+
}
1162+
1163+
fn add(&mut self, logs: &[String]) {
1164+
const IX_PREFIX: &str = "Program log: Instruction: ";
1165+
const CU_PREFIX: &str = "Program Stake11111111111111111111111111111111111111 consumed ";
1166+
1167+
let instruction = logs
1168+
.iter()
1169+
.find_map(|line| {
1170+
line.strip_prefix(IX_PREFIX)
1171+
.map(|rest| rest.split_whitespace().next().unwrap().to_string())
1172+
})
1173+
.unwrap();
1174+
1175+
let compute_units = logs
1176+
.iter()
1177+
.find_map(|line| {
1178+
line.strip_prefix(CU_PREFIX).map(|rest| {
1179+
rest.split_whitespace()
1180+
.next()
1181+
.unwrap()
1182+
.parse::<u64>()
1183+
.unwrap()
1184+
})
1185+
})
1186+
.unwrap();
1187+
1188+
self.0
1189+
.entry(instruction)
1190+
.and_modify(|v| *v = std::cmp::max(compute_units, *v))
1191+
.or_insert(compute_units);
1192+
}
1193+
1194+
fn show(&self) {
1195+
let mut instructions = self.0.keys().collect::<Vec<_>>();
1196+
instructions.sort();
1197+
1198+
println!("\n| Instruction | Estimated Cost |");
1199+
println!("| --- | --- |");
1200+
1201+
for instruction in instructions.into_iter() {
1202+
let compute_units = match self.0[instruction] {
1203+
n if n < 100 => "(negligible)".to_string(),
1204+
n => ((n + 50) / 100 * 100).to_string(),
1205+
};
1206+
1207+
println!("| `{}` | {} |", instruction, compute_units);
1208+
}
1209+
1210+
println!();
1211+
}
1212+
}

0 commit comments

Comments
 (0)