111 lines
3.4 KiB
Rust
111 lines
3.4 KiB
Rust
use crate::{cli::Args, rpc_client::CustomRpcClient};
|
|
use itertools::Itertools;
|
|
use rand::{rngs::StdRng, Rng, SeedableRng};
|
|
use serde::Serialize;
|
|
use solana_program::hash::Hash;
|
|
use std::{
|
|
sync::Arc,
|
|
time::{Duration, Instant},
|
|
};
|
|
use tokio::sync::RwLock;
|
|
|
|
pub type BlockHashGetter = Arc<RwLock<Hash>>;
|
|
|
|
#[async_trait::async_trait]
|
|
pub trait Benchmark: Clone + Send + 'static {
|
|
async fn run(
|
|
self,
|
|
rpc_client: &mut CustomRpcClient,
|
|
duration: Duration,
|
|
random_number: u64,
|
|
) -> anyhow::Result<()>;
|
|
}
|
|
|
|
#[derive(Default, Serialize)]
|
|
pub struct Run {
|
|
pub requests_completed: u64,
|
|
pub requests_failed: u64,
|
|
pub bytes_sent: u64,
|
|
pub bytes_received: u64,
|
|
pub errors: Vec<String>,
|
|
}
|
|
|
|
#[derive(Default, Serialize, Clone)]
|
|
pub struct Stats {
|
|
pub total_requests: u64,
|
|
pub requests_per_second: f64,
|
|
pub time_per_request: f64,
|
|
pub total_transferred: u64,
|
|
pub top_5_errors: Vec<(String, usize)>,
|
|
pub average_number_of_requests_by_a_task: f64,
|
|
pub total_requests_succeded: u64,
|
|
pub total_requests_failed: u64,
|
|
pub average_succeds_per_task: f64,
|
|
pub average_failed_per_task: f64,
|
|
}
|
|
|
|
pub struct Bencher;
|
|
|
|
impl Bencher {
|
|
pub async fn bench<B: Benchmark + Send + Clone>(
|
|
instant: B,
|
|
args: Args,
|
|
) -> anyhow::Result<Stats> {
|
|
let start = Instant::now();
|
|
let mut random = StdRng::seed_from_u64(0);
|
|
let futs = (0..args.threads).map(|_| {
|
|
let mut rpc_client = args.get_rpc_client();
|
|
let duration = args.get_duration_to_run_test();
|
|
let random_number = random.gen();
|
|
let instance = instant.clone();
|
|
|
|
tokio::spawn(async move {
|
|
instance
|
|
.run(&mut rpc_client, duration, random_number)
|
|
.await
|
|
.unwrap();
|
|
|
|
rpc_client.into()
|
|
})
|
|
});
|
|
|
|
let all_results: Vec<Run> = futures::future::try_join_all(futs).await?;
|
|
|
|
let time = start.elapsed();
|
|
|
|
let total_requests = all_results
|
|
.iter()
|
|
.fold(0, |acc, r| acc + r.requests_completed + r.requests_failed);
|
|
|
|
let total_requests_succeded = all_results
|
|
.iter()
|
|
.fold(0, |acc, r| acc + r.requests_completed);
|
|
let total_requests_failed = all_results.iter().fold(0, |acc, r| acc + r.requests_failed);
|
|
|
|
let total_transferred = all_results
|
|
.iter()
|
|
.fold(0, |acc, r| acc + r.bytes_sent + r.bytes_received);
|
|
let all_errors = all_results.iter().flat_map(|r| &r.errors).counts();
|
|
let top_5_errors = all_errors
|
|
.iter()
|
|
.sorted_by_key(|(_e, c)| *c)
|
|
.rev()
|
|
.take(5)
|
|
.map(|(e, c)| ((*e).clone(), *c))
|
|
.collect_vec();
|
|
|
|
Ok(Stats {
|
|
total_requests,
|
|
requests_per_second: total_requests as f64 / time.as_secs_f64(),
|
|
time_per_request: time.as_secs_f64() / (total_requests as f64 / args.threads as f64),
|
|
total_transferred,
|
|
top_5_errors,
|
|
average_number_of_requests_by_a_task: (total_requests as f64) / (args.threads as f64),
|
|
total_requests_succeded,
|
|
total_requests_failed,
|
|
average_succeds_per_task: total_requests_succeded as f64 / args.threads as f64,
|
|
average_failed_per_task: total_requests_failed as f64 / args.threads as f64,
|
|
})
|
|
}
|
|
}
|