Compare commits
No commits in common. "f828cb7bce5a7a322d4daa67394570be1003756a" and "40fe0f632e5379af9c978fb763a392556e6e858a" have entirely different histories.
f828cb7bce
...
40fe0f632e
|
@ -3,7 +3,10 @@ use itertools::Itertools;
|
||||||
use rand::{rngs::StdRng, Rng, SeedableRng};
|
use rand::{rngs::StdRng, Rng, SeedableRng};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use std::time::{Duration, Instant};
|
use std::{
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
pub trait Benchmark: Clone + Send + 'static {
|
pub trait Benchmark: Clone + Send + 'static {
|
||||||
|
@ -24,7 +27,7 @@ pub struct Run {
|
||||||
pub errors: Vec<String>,
|
pub errors: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Serialize, Clone, Debug)]
|
#[derive(Default, Serialize, Clone)]
|
||||||
pub struct Stats {
|
pub struct Stats {
|
||||||
pub total_requests: u64,
|
pub total_requests: u64,
|
||||||
pub requests_per_second: f64,
|
pub requests_per_second: f64,
|
||||||
|
@ -43,7 +46,7 @@ pub struct Bencher;
|
||||||
impl Bencher {
|
impl Bencher {
|
||||||
pub async fn bench<B: Benchmark + Send + Clone>(
|
pub async fn bench<B: Benchmark + Send + Clone>(
|
||||||
instant: B,
|
instant: B,
|
||||||
args: &Args,
|
args: Args,
|
||||||
) -> anyhow::Result<Stats> {
|
) -> anyhow::Result<Stats> {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let mut random = StdRng::seed_from_u64(0);
|
let mut random = StdRng::seed_from_u64(0);
|
||||||
|
|
18
src/main.rs
18
src/main.rs
|
@ -24,19 +24,17 @@ async fn main() -> anyhow::Result<()> {
|
||||||
|
|
||||||
assert_ne!(args.threads, 0, "Threads can't be 0");
|
assert_ne!(args.threads, 0, "Threads can't be 0");
|
||||||
assert_ne!(args.duration_in_seconds, 0, "Duration can't be 0");
|
assert_ne!(args.duration_in_seconds, 0, "Duration can't be 0");
|
||||||
assert_ne!(args.output_file.len(), 0, "Output file name can't be empty");
|
|
||||||
|
|
||||||
let config = std::fs::read_to_string(&args.config_file)
|
let contents = std::fs::read_to_string(&args.config_file)
|
||||||
.context("Should have been able to read the file")?;
|
.context("Should have been able to read the file")?;
|
||||||
|
let config_json: Config = serde_json::from_str(&contents).context("Config file not valid")?;
|
||||||
|
|
||||||
let config: Config = serde_json::from_str(&config).context("Config file not valid")?;
|
if config_json.users.is_empty() {
|
||||||
|
|
||||||
if config.users.is_empty() {
|
|
||||||
log::error!("Config file is missing payers");
|
log::error!("Config file is missing payers");
|
||||||
bail!("No payers");
|
bail!("No payers");
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.markets.is_empty() {
|
if config_json.markets.is_empty() {
|
||||||
log::error!("Config file is missing markets");
|
log::error!("Config file is missing markets");
|
||||||
bail!("No markets")
|
bail!("No markets")
|
||||||
}
|
}
|
||||||
|
@ -63,13 +61,9 @@ async fn main() -> anyhow::Result<()> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let results = args
|
args.generate_test_registry(block_hash)
|
||||||
.generate_test_registry(block_hash)
|
.start_testing(args, config_json)
|
||||||
.run_tests(&args, &config)
|
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let results = serde_json::to_string(&results)?;
|
|
||||||
std::fs::write(args.output_file, results)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
bencher::{Bencher, Benchmark, Stats},
|
bencher::{Bencher, Benchmark, Stats},
|
||||||
cli::Args,
|
config::{Market, User},
|
||||||
config::{Config, Market, User},
|
|
||||||
rpc_client::CustomRpcClient,
|
rpc_client::CustomRpcClient,
|
||||||
test_registry::TestingTask,
|
test_registry::TestingTask,
|
||||||
utils::noop,
|
utils::noop,
|
||||||
|
@ -52,7 +51,11 @@ impl ToPubkey for String {
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl TestingTask for SimulateOpenbookV2PlaceOrder {
|
impl TestingTask for SimulateOpenbookV2PlaceOrder {
|
||||||
async fn test(&self, args: &Args, config: &Config) -> anyhow::Result<Stats> {
|
async fn test(
|
||||||
|
&self,
|
||||||
|
args: crate::cli::Args,
|
||||||
|
config: crate::config::Config,
|
||||||
|
) -> anyhow::Result<Stats> {
|
||||||
let openbook_data = config
|
let openbook_data = config
|
||||||
.programs
|
.programs
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -77,6 +80,7 @@ impl TestingTask for SimulateOpenbookV2PlaceOrder {
|
||||||
openbook_pid,
|
openbook_pid,
|
||||||
};
|
};
|
||||||
let metric = Bencher::bench::<SimulateOpenbookV2PlaceOrderBench>(instant, args).await?;
|
let metric = Bencher::bench::<SimulateOpenbookV2PlaceOrderBench>(instant, args).await?;
|
||||||
|
log::info!("{} {}", self.get_name(), serde_json::to_string(&metric)?);
|
||||||
Ok(metric)
|
Ok(metric)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,8 +96,9 @@ impl CustomRpcClient {
|
||||||
Ok(res_bytes) => {
|
Ok(res_bytes) => {
|
||||||
self.metric.bytes_received += res_bytes.len() as u64;
|
self.metric.bytes_received += res_bytes.len() as u64;
|
||||||
|
|
||||||
match serde_json::from_slice::<Value>(&res_bytes) {
|
let res: Value =
|
||||||
Ok(res) => {
|
serde_json::from_slice(&res_bytes).expect("Server invalid response json");
|
||||||
|
|
||||||
if res.get("result").is_some() {
|
if res.get("result").is_some() {
|
||||||
self.metric.requests_completed += 1;
|
self.metric.requests_completed += 1;
|
||||||
return;
|
return;
|
||||||
|
@ -106,9 +107,6 @@ impl CustomRpcClient {
|
||||||
res["error"].to_string()
|
res["error"].to_string()
|
||||||
}
|
}
|
||||||
Err(err) => err.to_string(),
|
Err(err) => err.to_string(),
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => err.to_string(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.metric.errors.push(err);
|
self.metric.errors.push(err);
|
||||||
|
@ -116,16 +114,14 @@ impl CustomRpcClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_raw(&self, req_raw_body: Vec<u8>) -> anyhow::Result<Bytes> {
|
pub async fn send_raw(&self, req_raw_body: Vec<u8>) -> anyhow::Result<Bytes> {
|
||||||
let response = self
|
Ok(self
|
||||||
.client
|
.client
|
||||||
.post(&self.url)
|
.post(&self.url)
|
||||||
.header(CONTENT_TYPE, "application/json")
|
.header(CONTENT_TYPE, "application/json")
|
||||||
.body(req_raw_body)
|
.body(req_raw_body)
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?
|
||||||
|
.bytes()
|
||||||
response.error_for_status_ref()?;
|
.await?)
|
||||||
|
|
||||||
Ok(response.bytes().await?)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,11 @@ use async_trait::async_trait;
|
||||||
use const_env::from_env;
|
use const_env::from_env;
|
||||||
use rand::{seq::IteratorRandom, SeedableRng};
|
use rand::{seq::IteratorRandom, SeedableRng};
|
||||||
use solana_sdk::{pubkey::Pubkey, signature::Keypair, signer::Signer};
|
use solana_sdk::{pubkey::Pubkey, signature::Keypair, signer::Signer};
|
||||||
use std::{str::FromStr, sync::Arc};
|
use std::str::FromStr;
|
||||||
use tokio::time::Instant;
|
use tokio::time::Instant;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bencher::{Bencher, Benchmark, Stats},
|
bencher::{Bencher, Benchmark, Stats},
|
||||||
cli::Args,
|
|
||||||
config::Config,
|
config::Config,
|
||||||
rpc_client::CustomRpcClient,
|
rpc_client::CustomRpcClient,
|
||||||
test_registry::TestingTask,
|
test_registry::TestingTask,
|
||||||
|
@ -26,7 +25,7 @@ impl AccountsFetchingTests {
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl TestingTask for AccountsFetchingTests {
|
impl TestingTask for AccountsFetchingTests {
|
||||||
async fn test(&self, args: &Args, config: &Config) -> anyhow::Result<Stats> {
|
async fn test(&self, args: crate::cli::Args, config: Config) -> anyhow::Result<Stats> {
|
||||||
let accounts = config
|
let accounts = config
|
||||||
.known_accounts
|
.known_accounts
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -36,13 +35,13 @@ impl TestingTask for AccountsFetchingTests {
|
||||||
AccountsFetchingTests::create_random_address(accounts.len());
|
AccountsFetchingTests::create_random_address(accounts.len());
|
||||||
|
|
||||||
let instant = GetAccountsBench {
|
let instant = GetAccountsBench {
|
||||||
accounts_list: Arc::new([accounts, unknown_accounts].concat()),
|
accounts_list: [accounts, unknown_accounts].concat(),
|
||||||
};
|
};
|
||||||
let metric = Bencher::bench::<GetAccountsBench>(instant, args).await?;
|
let metric = Bencher::bench::<GetAccountsBench>(instant, args).await?;
|
||||||
|
log::info!("{} {}", self.get_name(), serde_json::to_string(&metric)?);
|
||||||
Ok(metric)
|
Ok(metric)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn get_name(&self) -> String {
|
fn get_name(&self) -> String {
|
||||||
"Accounts Fetching".to_string()
|
"Accounts Fetching".to_string()
|
||||||
}
|
}
|
||||||
|
@ -50,7 +49,7 @@ impl TestingTask for AccountsFetchingTests {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct GetAccountsBench {
|
pub struct GetAccountsBench {
|
||||||
accounts_list: Arc<Vec<Pubkey>>,
|
accounts_list: Vec<Pubkey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
use log::info;
|
||||||
use solana_sdk::slot_history::Slot;
|
use solana_sdk::slot_history::Slot;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -14,10 +15,11 @@ pub struct GetBlockTest;
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl TestingTask for GetBlockTest {
|
impl TestingTask for GetBlockTest {
|
||||||
async fn test(&self, args: &Args, _: &Config) -> anyhow::Result<Stats> {
|
async fn test(&self, args: Args, _: Config) -> anyhow::Result<Stats> {
|
||||||
let slot = args.get_rpc_client().get_slot().await.unwrap();
|
let slot = args.get_rpc_client().get_slot().await.unwrap();
|
||||||
let instant = GetBlockBench { slot };
|
let instant = GetBlockBench { slot };
|
||||||
let metric = Bencher::bench::<GetBlockBench>(instant, args).await?;
|
let metric = Bencher::bench::<GetBlockBench>(instant, args).await?;
|
||||||
|
info!("{} {}", self.get_name(), serde_json::to_string(&metric)?);
|
||||||
Ok(metric)
|
Ok(metric)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub struct GetSlotTest;
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl TestingTask for GetSlotTest {
|
impl TestingTask for GetSlotTest {
|
||||||
async fn test(&self, args: &Args, _: &Config) -> anyhow::Result<Stats> {
|
async fn test(&self, args: Args, _: Config) -> anyhow::Result<Stats> {
|
||||||
let instant = GetSlotTest;
|
let instant = GetSlotTest;
|
||||||
let stats = Bencher::bench::<Self>(instant, args).await?;
|
let stats = Bencher::bench::<Self>(instant, args).await?;
|
||||||
info!("{} {}", self.get_name(), serde_json::to_string(&stats)?);
|
info!("{} {}", self.get_name(), serde_json::to_string(&stats)?);
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
bencher::{Bencher, Benchmark, Stats},
|
bencher::{Bencher, Benchmark, Stats},
|
||||||
cli::Args,
|
|
||||||
config::Config,
|
|
||||||
rpc_client::CustomRpcClient,
|
rpc_client::CustomRpcClient,
|
||||||
test_registry::TestingTask,
|
test_registry::TestingTask,
|
||||||
};
|
};
|
||||||
|
@ -30,12 +28,21 @@ fn create_memo_tx(msg: &[u8], payer: &Keypair, blockhash: Hash) -> Transaction {
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl TestingTask for SendAndConfrimTesting {
|
impl TestingTask for SendAndConfrimTesting {
|
||||||
async fn test(&self, args: &Args, config: &Config) -> anyhow::Result<Stats> {
|
async fn test(
|
||||||
|
&self,
|
||||||
|
args: crate::cli::Args,
|
||||||
|
config: crate::config::Config,
|
||||||
|
) -> anyhow::Result<Stats> {
|
||||||
let instant = SendMemoTransactionsBench {
|
let instant = SendMemoTransactionsBench {
|
||||||
block_hash: self.block_hash.clone(),
|
block_hash: self.block_hash.clone(),
|
||||||
payers: Arc::new(config.users.iter().map(|x| x.get_keypair()).collect()),
|
payers: config
|
||||||
|
.users
|
||||||
|
.iter()
|
||||||
|
.map(|x| Arc::new(x.get_keypair()))
|
||||||
|
.collect(),
|
||||||
};
|
};
|
||||||
let metric = Bencher::bench::<SendMemoTransactionsBench>(instant, args).await?;
|
let metric = Bencher::bench::<SendMemoTransactionsBench>(instant, args).await?;
|
||||||
|
log::info!("{} {}", self.get_name(), serde_json::to_string(&metric)?);
|
||||||
Ok(metric)
|
Ok(metric)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +54,7 @@ impl TestingTask for SendAndConfrimTesting {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct SendMemoTransactionsBench {
|
struct SendMemoTransactionsBench {
|
||||||
block_hash: Arc<RwLock<Hash>>,
|
block_hash: Arc<RwLock<Hash>>,
|
||||||
payers: Arc<Vec<Keypair>>,
|
payers: Vec<Arc<Keypair>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
use crate::{bencher::Stats, cli::Args, config::Config};
|
use crate::{bencher::Stats, cli::Args, config::Config};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait TestingTask: Send + Sync {
|
pub trait TestingTask: Send + Sync {
|
||||||
async fn test(&self, args: &Args, config: &Config) -> anyhow::Result<Stats>;
|
async fn test(&self, args: Args, config: Config) -> anyhow::Result<Stats>;
|
||||||
fn get_name(&self) -> String;
|
fn get_name(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,26 +20,35 @@ impl TestRegistry {
|
||||||
self.tests.push(test);
|
self.tests.push(test);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_tests(&self, args: &Args, config: &Config) -> HashMap<String, Stats> {
|
pub async fn start_testing(self, args: Args, config: Config) {
|
||||||
let mut results = HashMap::new();
|
let results = Arc::new(RwLock::new(HashMap::new()));
|
||||||
|
let tasks = self.tests.into_iter().map(|test| {
|
||||||
for test in &self.tests {
|
let args = args.clone();
|
||||||
|
let config = config.clone();
|
||||||
let name = test.get_name();
|
let name = test.get_name();
|
||||||
|
let results = results.clone();
|
||||||
|
|
||||||
log::info!("Test: {name}");
|
tokio::spawn(async move {
|
||||||
|
log::info!("test {name}");
|
||||||
|
|
||||||
match test.test(args, config).await {
|
match test.test(args, config).await {
|
||||||
Ok(stat) => {
|
Ok(metric) => {
|
||||||
log::info!("Test {name} passed");
|
log::info!("test {name} passed");
|
||||||
log::info!("Metric:\n{stat:#?}");
|
let mut lock = results.write().await;
|
||||||
|
lock.insert(test.get_name(), metric);
|
||||||
|
}
|
||||||
|
Err(e) => log::info!("test {name} failed with error {e}"),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
results.insert(name, stat);
|
futures::future::join_all(tasks).await;
|
||||||
}
|
let res = results.read().await.clone();
|
||||||
Err(e) => log::error!("test {name} failed with error {e}"),
|
if !args.output_file.is_empty() {
|
||||||
}
|
let result_string = serde_json::to_string(&res);
|
||||||
|
if let Ok(result) = result_string {
|
||||||
}
|
std::fs::write(args.output_file, result).expect("Could not write output file");
|
||||||
|
}
|
||||||
results
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue