sui_aws_orchestrator/protocol/
sui.rs1use std::{
5 fmt::{Debug, Display},
6 path::PathBuf,
7 str::FromStr,
8};
9
10use serde::{Deserialize, Serialize};
11use sui_swarm_config::genesis_config::GenesisConfig;
12use sui_types::{base_types::SuiAddress, multiaddr::Multiaddr};
13
14use crate::{
15 benchmark::{BenchmarkParameters, BenchmarkType},
16 client::Instance,
17 settings::Settings,
18};
19
20use super::{ProtocolCommands, ProtocolMetrics};
21
22#[derive(Serialize, Deserialize, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
23pub struct SuiBenchmarkType {
24 shared_objects_ratio: u16,
27}
28
29impl Debug for SuiBenchmarkType {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 write!(f, "{}", self.shared_objects_ratio)
32 }
33}
34
35impl Display for SuiBenchmarkType {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 write!(f, "{}% shared objects", self.shared_objects_ratio)
38 }
39}
40
41impl FromStr for SuiBenchmarkType {
42 type Err = std::num::ParseIntError;
43
44 fn from_str(s: &str) -> Result<Self, Self::Err> {
45 Ok(Self {
46 shared_objects_ratio: s.parse::<u16>()?.min(100),
47 })
48 }
49}
50
51impl BenchmarkType for SuiBenchmarkType {}
52
53pub struct SuiProtocol {
55 working_dir: PathBuf,
56}
57
58impl ProtocolCommands<SuiBenchmarkType> for SuiProtocol {
59 fn protocol_dependencies(&self) -> Vec<&'static str> {
60 vec![
61 "sudo apt-get -y install curl git-all clang cmake gcc libssl-dev pkg-config libclang-dev",
63 "sudo apt-get -y install libpq-dev",
65 ]
66 }
67
68 fn db_directories(&self) -> Vec<PathBuf> {
69 let authorities_db = [&self.working_dir, &sui_config::AUTHORITIES_DB_NAME.into()]
70 .iter()
71 .collect();
72 let consensus_db = [&self.working_dir, &sui_config::CONSENSUS_DB_NAME.into()]
73 .iter()
74 .collect();
75 vec![authorities_db, consensus_db]
76 }
77
78 fn genesis_command<'a, I>(&self, instances: I) -> String
79 where
80 I: Iterator<Item = &'a Instance>,
81 {
82 let working_dir = self.working_dir.display();
83 let ips = instances
84 .map(|x| x.main_ip.to_string())
85 .collect::<Vec<_>>()
86 .join(" ");
87 let genesis = [
88 "cargo run --release --bin sui --",
89 "genesis",
90 &format!("-f --working-dir {working_dir} --benchmark-ips {ips}"),
91 ]
92 .join(" ");
93
94 [
95 &format!("mkdir -p {working_dir}"),
96 "source $HOME/.cargo/env",
97 &genesis,
98 ]
99 .join(" && ")
100 }
101
102 fn monitor_command<I>(&self, _instances: I) -> Vec<(Instance, String)>
103 where
104 I: IntoIterator<Item = Instance>,
105 {
106 vec![]
116 }
117
118 fn node_command<I>(
119 &self,
120 instances: I,
121 _parameters: &BenchmarkParameters<SuiBenchmarkType>,
122 ) -> Vec<(Instance, String)>
123 where
124 I: IntoIterator<Item = Instance>,
125 {
126 let working_dir = self.working_dir.clone();
127 let network_addresses = Self::resolve_network_addresses(instances);
128
129 network_addresses
130 .into_iter()
131 .enumerate()
132 .map(|(i, (instance, network_address))| {
133 let validator_config =
134 sui_config::validator_config_file(network_address.clone(), i);
135 let config_path: PathBuf = working_dir.join(validator_config);
136
137 let run = [
138 "cargo run --release --bin sui-node --",
139 &format!(
140 "--config-path {} --listen-address {}",
141 config_path.display(),
142 network_address.with_zero_ip()
143 ),
144 ]
145 .join(" ");
146 let command = ["source $HOME/.cargo/env", &run].join(" && ");
147
148 (instance, command)
149 })
150 .collect()
151 }
152
153 fn client_command<I>(
154 &self,
155 instances: I,
156 parameters: &BenchmarkParameters<SuiBenchmarkType>,
157 ) -> Vec<(Instance, String)>
158 where
159 I: IntoIterator<Item = Instance>,
160 {
161 let genesis_path: PathBuf = [&self.working_dir, &sui_config::SUI_GENESIS_FILENAME.into()]
162 .iter()
163 .collect();
164 let keystore_path: PathBuf = [
165 &self.working_dir,
166 &sui_config::SUI_BENCHMARK_GENESIS_GAS_KEYSTORE_FILENAME.into(),
167 ]
168 .iter()
169 .collect();
170
171 let committee_size = parameters.nodes;
172 let clients: Vec<_> = instances.into_iter().collect();
173 let load_share = parameters.load / clients.len();
174 let shared_counter = parameters.benchmark_type.shared_objects_ratio;
175 let transfer_objects = 100 - shared_counter;
176 let metrics_port = Self::CLIENT_METRICS_PORT;
177 let gas_keys = GenesisConfig::benchmark_gas_keys(committee_size);
178
179 clients
180 .into_iter()
181 .enumerate()
182 .map(|(i, instance)| {
183 let genesis = genesis_path.display();
184 let keystore = keystore_path.display();
185 let gas_key = &gas_keys[i % committee_size];
186 let gas_address = SuiAddress::from(&gas_key.public());
187
188 let run = [
190 "cargo run --release --bin stress --",
191 "--num-client-threads 24 --num-server-threads 1",
192 "--num-transfer-accounts 2",
193 &format!("--genesis-blob-path {genesis} --keystore-path {keystore}",),
194 &format!("--primary-gas-owner-id {gas_address}"),
195 "bench",
196 &format!("--in-flight-ratio 30 --num-workers 24 --target-qps {load_share}"),
197 &format!(
198 "--shared-counter {shared_counter} --transfer-object {transfer_objects}"
199 ),
200 "--shared-counter-hotness-factor 50",
201 &format!("--client-metric-host 0.0.0.0 --client-metric-port {metrics_port}"),
202 ]
203 .join(" ");
204 let command = ["source $HOME/.cargo/env", &run].join(" && ");
205
206 (instance, command)
207 })
208 .collect()
209 }
210}
211
212impl SuiProtocol {
213 const CLIENT_METRICS_PORT: u16 = GenesisConfig::BENCHMARKS_PORT_OFFSET + 2000;
214
215 pub fn new(settings: &Settings) -> Self {
217 Self {
218 working_dir: [&settings.working_dir, &sui_config::SUI_CONFIG_DIR.into()]
219 .iter()
220 .collect(),
221 }
222 }
223
224 pub fn resolve_network_addresses(
227 instances: impl IntoIterator<Item = Instance>,
228 ) -> Vec<(Instance, Multiaddr)> {
229 let instances: Vec<Instance> = instances.into_iter().collect();
230 let ips: Vec<_> = instances.iter().map(|x| x.main_ip.to_string()).collect();
231 let genesis_config = GenesisConfig::new_for_benchmarks(&ips);
232 let mut addresses = Vec::new();
233 if let Some(validator_configs) = genesis_config.validator_config_info.as_ref() {
234 for (i, validator_info) in validator_configs.iter().enumerate() {
235 let address = &validator_info.network_address;
236 addresses.push((instances[i].clone(), address.clone()));
237 }
238 }
239 addresses
240 }
241}
242
243impl ProtocolMetrics for SuiProtocol {
244 const BENCHMARK_DURATION: &'static str = "benchmark_duration";
245 const TOTAL_TRANSACTIONS: &'static str = "latency_s_count";
246 const LATENCY_BUCKETS: &'static str = "latency_s";
247 const LATENCY_SUM: &'static str = "latency_s_sum";
248 const LATENCY_SQUARED_SUM: &'static str = "latency_squared_s";
249
250 fn nodes_metrics_path<I>(&self, instances: I) -> Vec<(Instance, String)>
251 where
252 I: IntoIterator<Item = Instance>,
253 {
254 let (ips, instances): (Vec<_>, Vec<_>) = instances
255 .into_iter()
256 .map(|x| (x.main_ip.to_string(), x))
257 .unzip();
258
259 GenesisConfig::new_for_benchmarks(&ips)
260 .validator_config_info
261 .expect("No validator in genesis")
262 .iter()
263 .zip(instances)
264 .map(|(config, instance)| {
265 let path = format!(
266 "{}:{}{}",
267 instance.main_ip,
268 config.metrics_address.port(),
269 mysten_metrics::METRICS_ROUTE
270 );
271 (instance, path)
272 })
273 .collect()
274 }
275
276 fn clients_metrics_path<I>(&self, instances: I) -> Vec<(Instance, String)>
277 where
278 I: IntoIterator<Item = Instance>,
279 {
280 instances
281 .into_iter()
282 .map(|instance| {
283 let path = format!(
284 "{}:{}{}",
285 instance.main_ip,
286 Self::CLIENT_METRICS_PORT,
287 mysten_metrics::METRICS_ROUTE
288 );
289 (instance, path)
290 })
291 .collect()
292 }
293}