cli.rs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. use clap::{crate_description, crate_name, crate_version, App, Arg, ArgMatches};
  2. use solana_drone::drone::DRONE_PORT;
  3. use solana_sdk::fee_calculator::FeeCalculator;
  4. use solana_sdk::signature::{read_keypair_file, Keypair, KeypairUtil};
  5. use std::{net::SocketAddr, process::exit, time::Duration};
  6. const NUM_LAMPORTS_PER_ACCOUNT_DEFAULT: u64 = solana_sdk::native_token::SOL_LAMPORTS;
  7. /// Holds the configuration for a single run of the benchmark
  8. pub struct Config {
  9. pub entrypoint_addr: SocketAddr,
  10. pub drone_addr: SocketAddr,
  11. pub id: Keypair,
  12. pub threads: usize,
  13. pub num_nodes: usize,
  14. pub duration: Duration,
  15. pub tx_count: usize,
  16. pub thread_batch_sleep_ms: usize,
  17. pub sustained: bool,
  18. pub client_ids_and_stake_file: String,
  19. pub write_to_client_file: bool,
  20. pub read_from_client_file: bool,
  21. pub target_lamports_per_signature: u64,
  22. pub multi_client: bool,
  23. pub use_move: bool,
  24. pub num_lamports_per_account: u64,
  25. }
  26. impl Default for Config {
  27. fn default() -> Config {
  28. Config {
  29. entrypoint_addr: SocketAddr::from(([127, 0, 0, 1], 8001)),
  30. drone_addr: SocketAddr::from(([127, 0, 0, 1], DRONE_PORT)),
  31. id: Keypair::new(),
  32. threads: 4,
  33. num_nodes: 1,
  34. duration: Duration::new(std::u64::MAX, 0),
  35. tx_count: 50_000,
  36. thread_batch_sleep_ms: 1000,
  37. sustained: false,
  38. client_ids_and_stake_file: String::new(),
  39. write_to_client_file: false,
  40. read_from_client_file: false,
  41. target_lamports_per_signature: FeeCalculator::default().target_lamports_per_signature,
  42. multi_client: true,
  43. use_move: false,
  44. num_lamports_per_account: NUM_LAMPORTS_PER_ACCOUNT_DEFAULT,
  45. }
  46. }
  47. }
  48. /// Defines and builds the CLI args for a run of the benchmark
  49. pub fn build_args<'a, 'b>() -> App<'a, 'b> {
  50. App::new(crate_name!()).about(crate_description!())
  51. .version(crate_version!())
  52. .arg(
  53. Arg::with_name("entrypoint")
  54. .short("n")
  55. .long("entrypoint")
  56. .value_name("HOST:PORT")
  57. .takes_value(true)
  58. .help("Rendezvous with the cluster at this entry point; defaults to 127.0.0.1:8001"),
  59. )
  60. .arg(
  61. Arg::with_name("drone")
  62. .short("d")
  63. .long("drone")
  64. .value_name("HOST:PORT")
  65. .takes_value(true)
  66. .help("Location of the drone; defaults to entrypoint:DRONE_PORT"),
  67. )
  68. .arg(
  69. Arg::with_name("identity")
  70. .short("i")
  71. .long("identity")
  72. .value_name("PATH")
  73. .takes_value(true)
  74. .help("File containing a client identity (keypair)"),
  75. )
  76. .arg(
  77. Arg::with_name("num-nodes")
  78. .short("N")
  79. .long("num-nodes")
  80. .value_name("NUM")
  81. .takes_value(true)
  82. .help("Wait for NUM nodes to converge"),
  83. )
  84. .arg(
  85. Arg::with_name("threads")
  86. .short("t")
  87. .long("threads")
  88. .value_name("NUM")
  89. .takes_value(true)
  90. .help("Number of threads"),
  91. )
  92. .arg(
  93. Arg::with_name("duration")
  94. .long("duration")
  95. .value_name("SECS")
  96. .takes_value(true)
  97. .help("Seconds to run benchmark, then exit; default is forever"),
  98. )
  99. .arg(
  100. Arg::with_name("sustained")
  101. .long("sustained")
  102. .help("Use sustained performance mode vs. peak mode. This overlaps the tx generation with transfers."),
  103. )
  104. .arg(
  105. Arg::with_name("use-move")
  106. .long("use-move")
  107. .help("Use Move language transactions to perform transfers."),
  108. )
  109. .arg(
  110. Arg::with_name("no-multi-client")
  111. .long("no-multi-client")
  112. .help("Disable multi-client support, only transact with the entrypoint."),
  113. )
  114. .arg(
  115. Arg::with_name("tx_count")
  116. .long("tx_count")
  117. .value_name("NUM")
  118. .takes_value(true)
  119. .help("Number of transactions to send per batch")
  120. )
  121. .arg(
  122. Arg::with_name("thread-batch-sleep-ms")
  123. .short("z")
  124. .long("thread-batch-sleep-ms")
  125. .value_name("NUM")
  126. .takes_value(true)
  127. .help("Per-thread-per-iteration sleep in ms"),
  128. )
  129. .arg(
  130. Arg::with_name("write-client-keys")
  131. .long("write-client-keys")
  132. .value_name("FILENAME")
  133. .takes_value(true)
  134. .help("Generate client keys and stakes and write the list to YAML file"),
  135. )
  136. .arg(
  137. Arg::with_name("read-client-keys")
  138. .long("read-client-keys")
  139. .value_name("FILENAME")
  140. .takes_value(true)
  141. .help("Read client keys and stakes from the YAML file"),
  142. )
  143. .arg(
  144. Arg::with_name("target_lamports_per_signature")
  145. .long("target-lamports-per-signature")
  146. .value_name("LAMPORTS")
  147. .takes_value(true)
  148. .help(
  149. "The cost in lamports that the cluster will charge for signature \
  150. verification when the cluster is operating at target-signatures-per-slot",
  151. ),
  152. )
  153. .arg(
  154. Arg::with_name("num_lamports_per_account")
  155. .long("num-lamports-per-account")
  156. .value_name("LAMPORTS")
  157. .takes_value(true)
  158. .help(
  159. "Number of lamports per account.",
  160. ),
  161. )
  162. }
  163. /// Parses a clap `ArgMatches` structure into a `Config`
  164. /// # Arguments
  165. /// * `matches` - command line arguments parsed by clap
  166. /// # Panics
  167. /// Panics if there is trouble parsing any of the arguments
  168. pub fn extract_args<'a>(matches: &ArgMatches<'a>) -> Config {
  169. let mut args = Config::default();
  170. if let Some(addr) = matches.value_of("entrypoint") {
  171. args.entrypoint_addr = solana_net_utils::parse_host_port(addr).unwrap_or_else(|e| {
  172. eprintln!("failed to parse entrypoint address: {}", e);
  173. exit(1)
  174. });
  175. }
  176. if let Some(addr) = matches.value_of("drone") {
  177. args.drone_addr = solana_net_utils::parse_host_port(addr).unwrap_or_else(|e| {
  178. eprintln!("failed to parse drone address: {}", e);
  179. exit(1)
  180. });
  181. }
  182. if matches.is_present("identity") {
  183. args.id = read_keypair_file(matches.value_of("identity").unwrap())
  184. .expect("can't read client identity");
  185. }
  186. if let Some(t) = matches.value_of("threads") {
  187. args.threads = t.to_string().parse().expect("can't parse threads");
  188. }
  189. if let Some(n) = matches.value_of("num-nodes") {
  190. args.num_nodes = n.to_string().parse().expect("can't parse num-nodes");
  191. }
  192. if let Some(duration) = matches.value_of("duration") {
  193. args.duration = Duration::new(
  194. duration.to_string().parse().expect("can't parse duration"),
  195. 0,
  196. );
  197. }
  198. if let Some(s) = matches.value_of("tx_count") {
  199. args.tx_count = s.to_string().parse().expect("can't parse tx_account");
  200. }
  201. if let Some(t) = matches.value_of("thread-batch-sleep-ms") {
  202. args.thread_batch_sleep_ms = t
  203. .to_string()
  204. .parse()
  205. .expect("can't parse thread-batch-sleep-ms");
  206. }
  207. args.sustained = matches.is_present("sustained");
  208. if let Some(s) = matches.value_of("write-client-keys") {
  209. args.write_to_client_file = true;
  210. args.client_ids_and_stake_file = s.to_string();
  211. }
  212. if let Some(s) = matches.value_of("read-client-keys") {
  213. assert!(!args.write_to_client_file);
  214. args.read_from_client_file = true;
  215. args.client_ids_and_stake_file = s.to_string();
  216. }
  217. if let Some(v) = matches.value_of("target_lamports_per_signature") {
  218. args.target_lamports_per_signature = v.to_string().parse().expect("can't parse lamports");
  219. }
  220. args.use_move = matches.is_present("use-move");
  221. args.multi_client = !matches.is_present("no-multi-client");
  222. if let Some(v) = matches.value_of("num_lamports_per_account") {
  223. args.num_lamports_per_account = v.to_string().parse().expect("can't parse lamports");
  224. }
  225. args
  226. }