Skip to content

Commit

Permalink
added rough benchmarks for isolated tps measurement
Browse files Browse the repository at this point in the history
  • Loading branch information
Voxelot committed Oct 20, 2023
1 parent 43054d4 commit cd79b25
Show file tree
Hide file tree
Showing 2 changed files with 212 additions and 51 deletions.
262 changes: 211 additions & 51 deletions benches/benches/transaction_throughput.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,49 @@ use criterion::{
measurement::WallTime,
BenchmarkGroup,
Criterion,
SamplingMode,
};
use fuel_core::service::config::Trigger;
use fuel_core_benches::*;
use fuel_core_types::{
fuel_asm::{
op,
GMArgs,
GTFArgs,
RegId,
},
fuel_crypto::*,
fuel_tx::{
Finalizable,
Input,
Output,
Script,
Transaction,
TransactionBuilder,
},
fuel_types::AssetId,
fuel_types::{
AssetId,
Immediate12,
Immediate18,
},
fuel_vm::checked_transaction::{
CheckPredicateParams,
EstimatePredicates,
},
};
use futures::{
stream::FuturesUnordered,
FutureExt,
StreamExt,
};
use rand::SeedableRng;
use std::sync::Arc;
use rand::{
rngs::StdRng,
SeedableRng,
};
use std::{
sync::Arc,
time::Duration,
};
use test_helpers::builder::{
TestContext,
TestSetupBuilder,
Expand All @@ -35,11 +58,13 @@ use test_helpers::builder::{
#[global_allocator]
static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;

fn basic_transfers(c: &mut Criterion) {
let transfer_bench = |c: &mut BenchmarkGroup<WallTime>, n: u32| {
fn bench_txs<F>(group_id: &str, c: &mut Criterion, f: F)
where
F: Fn(&mut StdRng) -> Script,
{
let inner_bench = |c: &mut BenchmarkGroup<WallTime>, n: u64| {
let id = format!("{}", n);
c.bench_function(id.as_str(), |b| {
eprintln!("setting up test");
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
Expand All @@ -50,29 +75,7 @@ fn basic_transfers(c: &mut Criterion) {

let mut transactions = vec![];
for _ in 0..n {
let tx = TransactionBuilder::script(vec![], vec![])
.gas_limit(10000)
.gas_price(1)
.add_unsigned_coin_input(
SecretKey::random(&mut rng),
rng.gen(),
1000,
Default::default(),
Default::default(),
Default::default(),
)
.add_unsigned_coin_input(
SecretKey::random(&mut rng),
rng.gen(),
1000,
Default::default(),
Default::default(),
Default::default(),
)
.add_output(Output::coin(rng.gen(), 50, AssetId::default()))
.add_output(Output::change(rng.gen(), 0, AssetId::default()))
.finalize();
transactions.push(tx);
transactions.push(f(&mut rng));
}

let mut test_builder = TestSetupBuilder::new(2322);
Expand All @@ -85,42 +88,199 @@ fn basic_transfers(c: &mut Criterion) {
test_builder.utxo_validation = true;

// spin up node
let TestContext {
srv: _dont_drop,
client,
..
} = rt.block_on(async move { test_builder.finalize().await });
let transactions: Vec<Transaction> =
transactions.into_iter().map(|tx| tx.into()).collect();
let transactions = Arc::new(transactions);
eprintln!("test setup");
b.to_async(&rt).iter(|| {
let client = client.clone();

b.to_async(&rt).iter_custom(|iters| {
let mut elapsed_time = Duration::default();
let test_builder = test_builder.clone();
let transactions = transactions.clone();

async move {
eprintln!("running test");
// insert all transactions
let submits = FuturesUnordered::new();
for tx in transactions.iter() {
submits.push(client.submit(&tx).boxed());
}
let _: Vec<_> = submits.collect().await;
for _ in 0..iters {
let mut test_builder = test_builder.clone();
let transactions = transactions.clone();
// start the node
let TestContext {
srv: _dont_drop,
client,
..
} = test_builder.finalize().await;

// insert all transactions
let submits = FuturesUnordered::new();
for tx in transactions.iter() {
submits.push(client.submit(&tx).boxed());
}
let _: Vec<_> = submits.collect().await;
let start = std::time::Instant::now();
let _ = client.produce_blocks(1, None).await;
elapsed_time += start.elapsed();

let _ = client.produce_blocks(1, None).await;
eprintln!("finished test");
// sanity check block to ensure the transactions were actually processed
let block = client.block_by_height(1).await.unwrap().unwrap();
assert_eq!(block.transactions.len(), (n + 1) as usize);
}
elapsed_time
}
});
});
};

let mut group = c.benchmark_group("basic transfer throughput");
let mut group = c.benchmark_group(group_id);

for i in [100, 500, 1000, 1500] {
group.throughput(criterion::Throughput::Elements(i));
group.sampling_mode(SamplingMode::Flat);
group.sample_size(10);
inner_bench(&mut group, i);
}

group.finish();
}

fn signed_transfers(c: &mut Criterion) {
let generator = |rng: &mut StdRng| {
TransactionBuilder::script(vec![], vec![])
.gas_limit(10000)
.gas_price(1)
.add_unsigned_coin_input(
SecretKey::random(rng),
rng.gen(),
1000,
Default::default(),
Default::default(),
Default::default(),
)
.add_unsigned_coin_input(
SecretKey::random(rng),
rng.gen(),
1000,
Default::default(),
Default::default(),
Default::default(),
)
.add_output(Output::coin(rng.gen(), 50, AssetId::default()))
.add_output(Output::change(rng.gen(), 0, AssetId::default()))
.finalize()
};
bench_txs("signed transfers", c, generator);
}

fn predicate_transfers(c: &mut Criterion) {
let generator = |rng: &mut StdRng| {
let predicate = op::ret(RegId::ONE).to_bytes().to_vec();
let owner = Input::predicate_owner(&predicate);

let mut tx = TransactionBuilder::script(vec![], vec![])
.gas_limit(10000)
.gas_price(1)
.add_input(Input::coin_predicate(
rng.gen(),
owner,
1000,
Default::default(),
Default::default(),
Default::default(),
Default::default(),
predicate.clone(),
vec![],
))
.add_input(Input::coin_predicate(
rng.gen(),
owner,
1000,
Default::default(),
Default::default(),
Default::default(),
Default::default(),
predicate,
vec![],
))
.add_output(Output::coin(rng.gen(), 50, AssetId::default()))
.add_output(Output::change(rng.gen(), 0, AssetId::default()))
.finalize();
tx.estimate_predicates(&CheckPredicateParams::default())
.expect("Predicate check failed");
tx
};
bench_txs("predicate transfers", c, generator);
}

fn predicate_transfers_eck1(c: &mut Criterion) {
let generator = |rng: &mut StdRng| {
let secret = SecretKey::random(rng);
let public = secret.public_key();

transfer_bench(&mut group, 10);
let message = b"The gift of words is the gift of deception and illusion.";
let message = Message::new(message);

transfer_bench(&mut group, 100);
let signature = Signature::sign(&secret, &message);

transfer_bench(&mut group, 1000);
let predicate = vec![
op::gm_args(0x20, GMArgs::GetVerifyingPredicate),
op::gtf_args(0x20, 0x20, GTFArgs::InputCoinPredicateData),
op::addi(0x21, 0x20, signature.as_ref().len() as Immediate12),
op::addi(0x22, 0x21, message.as_ref().len() as Immediate12),
op::movi(0x10, PublicKey::LEN as Immediate18),
op::aloc(0x10),
op::move_(0x11, RegId::HP),
op::eck1(0x11, 0x20, 0x21),
op::meq(0x12, 0x22, 0x11, 0x10),
op::ret(0x12),
]
.into_iter()
.collect::<Vec<u8>>();
let owner = Input::predicate_owner(&predicate);

let predicate_data: Vec<u8> = signature
.as_ref()
.iter()
.copied()
.chain(message.as_ref().iter().copied())
.chain(public.as_ref().iter().copied())
.collect();

let mut tx = TransactionBuilder::script(vec![], vec![])
.gas_limit(10000)
.gas_price(1)
.add_input(Input::coin_predicate(
rng.gen(),
owner,
1000,
Default::default(),
Default::default(),
Default::default(),
Default::default(),
predicate.clone(),
predicate_data.clone(),
))
.add_input(Input::coin_predicate(
rng.gen(),
owner,
1000,
Default::default(),
Default::default(),
Default::default(),
Default::default(),
predicate,
predicate_data,
))
.add_output(Output::coin(rng.gen(), 50, AssetId::default()))
.add_output(Output::change(rng.gen(), 0, AssetId::default()))
.finalize();
tx.estimate_predicates(&CheckPredicateParams::default())
.expect("Predicate check failed");
tx
};
bench_txs("predicate transfers eck1", c, generator);
}

criterion_group!(benches, basic_transfers);
criterion_group!(
benches,
signed_transfers,
predicate_transfers,
predicate_transfers_eck1
);
criterion_main!(benches);
1 change: 1 addition & 0 deletions tests/test-helpers/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ impl TestContext {
}

/// Helper for configuring the genesis block in tests
#[derive(Clone)]
pub struct TestSetupBuilder {
pub rng: StdRng,
pub contracts: HashMap<ContractId, ContractConfig>,
Expand Down

0 comments on commit cd79b25

Please sign in to comment.