feat: add queued pool truncate benchmarks (#6684)

This commit is contained in:
Dan Cline
2024-02-20 02:25:35 -05:00
committed by GitHub
parent 123b95aecc
commit a5dc8d6679
3 changed files with 62 additions and 22 deletions

View File

@ -9,7 +9,7 @@ use proptest::{
}; };
use reth_primitives::{hex_literal::hex, Address}; use reth_primitives::{hex_literal::hex, Address};
use reth_transaction_pool::{ use reth_transaction_pool::{
pool::{BasefeeOrd, ParkedPool, PendingPool}, pool::{BasefeeOrd, ParkedPool, PendingPool, QueuedOrd},
test_utils::{MockOrdering, MockTransaction, MockTransactionFactory}, test_utils::{MockOrdering, MockTransaction, MockTransactionFactory},
SubPoolLimit, SubPoolLimit,
}; };
@ -84,6 +84,23 @@ fn generate_many_transactions(senders: usize, max_depth: usize) -> Vec<MockTrans
txs txs
} }
/// Benchmarks all pool types for the truncate function.
fn benchmark_pools(group: &mut BenchmarkGroup<'_, WallTime>, senders: usize, max_depth: usize) {
println!("Generating transactions for benchmark with {senders} unique senders and a max depth of {max_depth}...");
let txs = generate_many_transactions(senders, max_depth);
// benchmark parked pool
truncate_basefee(group, "BasefeePool", txs.clone(), senders, max_depth);
// benchmark pending pool
truncate_pending(group, "PendingPool", txs.clone(), senders, max_depth);
// benchmark queued pool
truncate_queued(group, "QueuedPool", txs, senders, max_depth);
// TODO: benchmark blob truncate
}
fn txpool_truncate(c: &mut Criterion) { fn txpool_truncate(c: &mut Criterion) {
let mut group = c.benchmark_group("Transaction Pool Truncate"); let mut group = c.benchmark_group("Transaction Pool Truncate");
@ -95,17 +112,8 @@ fn txpool_truncate(c: &mut Criterion) {
for senders in [5, 10, 20, 100, 1000, 2000] { for senders in [5, 10, 20, 100, 1000, 2000] {
// the max we'll be benching is 20, because MAX_ACCOUNT_SLOTS so far is 16. So 20 should be // the max we'll be benching is 20, because MAX_ACCOUNT_SLOTS so far is 16. So 20 should be
// a reasonable worst-case benchmark // a reasonable worst-case benchmark
for max_depth in [5, 10, 20] { for max_depth in [1, 5, 10, 20] {
println!("Generating transactions for benchmark with {senders} unique senders and a max depth of {max_depth}..."); benchmark_pools(&mut group, senders, max_depth);
let txs = generate_many_transactions(senders, max_depth);
// benchmark parked pool
truncate_parked(&mut group, "ParkedPool", txs.clone(), senders, max_depth);
// benchmark pending pool
truncate_pending(&mut group, "PendingPool", txs, senders, max_depth);
// TODO: benchmark blob truncate
} }
} }
@ -114,14 +122,12 @@ fn txpool_truncate(c: &mut Criterion) {
// let's run a benchmark that includes a large number of senders and max_depth of 16 to ensure // let's run a benchmark that includes a large number of senders and max_depth of 16 to ensure
// we hit the TXPOOL_SUBPOOL_MAX_TXS_DEFAULT limit, which is currently 10k // we hit the TXPOOL_SUBPOOL_MAX_TXS_DEFAULT limit, which is currently 10k
println!("Generating transactions for large benchmark with {large_senders} unique senders and a max depth of {max_depth}..."); benchmark_pools(&mut group, large_senders, max_depth);
let txs = generate_many_transactions(large_senders, max_depth);
// benchmark parked // now we'll run a more realistic benchmark, with max depth of 1 and 15000 senders
truncate_parked(&mut group, "ParkedPool", txs.clone(), large_senders, max_depth); let realistic_senders = 15000;
let realistic_max_depth = 1;
// benchmark pending benchmark_pools(&mut group, realistic_senders, realistic_max_depth);
truncate_pending(&mut group, "PendingPool", txs, large_senders, max_depth);
} }
fn truncate_pending( fn truncate_pending(
@ -159,7 +165,41 @@ fn truncate_pending(
}); });
} }
fn truncate_parked( fn truncate_queued(
group: &mut BenchmarkGroup<'_, WallTime>,
description: &str,
seed: Vec<MockTransaction>,
senders: usize,
max_depth: usize,
) {
let setup = || {
let mut txpool = ParkedPool::<QueuedOrd<_>>::default();
let mut f = MockTransactionFactory::default();
for tx in seed.iter() {
txpool.add_transaction(f.validated_arc(tx.clone()));
}
txpool
};
let group_id = format!(
"txpool | total txs: {} | total senders: {} | max depth: {} | {}",
seed.len(),
senders,
max_depth,
description,
);
// for now we just use the default SubPoolLimit
group.bench_function(group_id, |b| {
b.iter_with_setup(setup, |mut txpool| {
txpool.truncate_pool(SubPoolLimit::default());
std::hint::black_box(());
});
});
}
fn truncate_basefee(
group: &mut BenchmarkGroup<'_, WallTime>, group: &mut BenchmarkGroup<'_, WallTime>,
description: &str, description: &str,
seed: Vec<MockTransaction>, seed: Vec<MockTransaction>,

View File

@ -108,7 +108,7 @@ pub use best::BestTransactionFilter;
pub use blob::{blob_tx_priority, fee_delta}; pub use blob::{blob_tx_priority, fee_delta};
pub use events::{FullTransactionEvent, TransactionEvent}; pub use events::{FullTransactionEvent, TransactionEvent};
pub use listener::{AllTransactionsEvents, TransactionEvents}; pub use listener::{AllTransactionsEvents, TransactionEvents};
pub use parked::{BasefeeOrd, ParkedOrd, ParkedPool}; pub use parked::{BasefeeOrd, ParkedOrd, ParkedPool, QueuedOrd};
pub use pending::PendingPool; pub use pending::PendingPool;
mod best; mod best;

View File

@ -442,7 +442,7 @@ impl<T: PoolTransaction> Ord for BasefeeOrd<T> {
/// The primary order function always compares the transaction costs first. In case these /// The primary order function always compares the transaction costs first. In case these
/// are equal, it compares the timestamps when the transactions were created. /// are equal, it compares the timestamps when the transactions were created.
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct QueuedOrd<T: PoolTransaction>(Arc<ValidPoolTransaction<T>>); pub struct QueuedOrd<T: PoolTransaction>(Arc<ValidPoolTransaction<T>>);
impl_ord_wrapper!(QueuedOrd); impl_ord_wrapper!(QueuedOrd);