From 8f23ffe401173c637894a65b05ac8aca1db83ffe Mon Sep 17 00:00:00 2001 From: "remy.baranx@gmail.com" Date: Mon, 13 Jan 2025 15:26:14 +0100 Subject: [PATCH 1/6] optimisations + benchmark setup --- Cargo.lock | 4 +- crates/katana/core/Cargo.toml | 10 +- crates/katana/core/benches/commit.rs | 130 ++++++++++++++++++++++++++ crates/katana/core/src/backend/mod.rs | 75 ++++++++++++++- 4 files changed, 216 insertions(+), 3 deletions(-) create mode 100644 crates/katana/core/benches/commit.rs diff --git a/Cargo.lock b/Cargo.lock index 5df4b41905..c32395b261 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8129,6 +8129,7 @@ dependencies = [ "arbitrary", "assert_matches", "async-trait", + "criterion", "derive_more 0.99.18", "dojo-metrics", "futures", @@ -8145,7 +8146,8 @@ dependencies = [ "metrics", "num-traits 0.2.19", "parking_lot 0.12.3", - "rand", + "rand 0.8.5", + "rayon", "reqwest 0.11.27", "rstest 0.18.2", "serde", diff --git a/crates/katana/core/Cargo.toml b/crates/katana/core/Cargo.toml index add0dcf9e5..1cce58b0d0 100644 --- a/crates/katana/core/Cargo.toml +++ b/crates/katana/core/Cargo.toml @@ -11,7 +11,7 @@ katana-chain-spec.workspace = true katana-db.workspace = true katana-executor = { workspace = true, features = [ "blockifier" ] } katana-pool.workspace = true -katana-primitives.workspace = true +katana-primitives = { workspace = true, features = [ "arbitrary" ]} katana-provider.workspace = true katana-tasks.workspace = true katana-trie.workspace = true @@ -26,6 +26,7 @@ metrics.workspace = true num-traits.workspace = true parking_lot.workspace = true reqwest.workspace = true +rayon.workspace = true serde.workspace = true serde_json.workspace = true starknet.workspace = true @@ -48,10 +49,17 @@ alloy-transport = { workspace = true, default-features = false } [dev-dependencies] arbitrary.workspace = true assert_matches.workspace = true +criterion.workspace = true hex.workspace = true rand.workspace = true rstest.workspace = true tempfile.workspace = true +arbitrary.workspace = true +rand.workspace = true [features] starknet-messaging = [ "dep:starknet-crypto" ] + +[[bench]] +name = "commit" +harness = false diff --git a/crates/katana/core/benches/commit.rs b/crates/katana/core/benches/commit.rs new file mode 100644 index 0000000000..4102d07dfd --- /dev/null +++ b/crates/katana/core/benches/commit.rs @@ -0,0 +1,130 @@ +use std::collections::BTreeMap; + +use arbitrary::{Arbitrary, Unstructured}; +use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion}; +use katana_core::backend::UncommittedBlock; +use katana_primitives::block::{GasPrices, PartialHeader}; +use katana_primitives::da::L1DataAvailabilityMode; +use katana_primitives::receipt::{Receipt, ReceiptWithTxHash}; +use katana_primitives::state::StateUpdates; +use katana_primitives::transaction::{Tx, TxWithHash}; +use katana_primitives::version::CURRENT_STARKNET_VERSION; +use katana_primitives::{ContractAddress, Felt}; +use katana_provider::providers::db::DbProvider; + +const NB_OF_TXS: usize = 20; +const NB_OF_RECEIPTS: usize = 20; +const NB_OF_NONCES: usize = 100; +const NB_OF_STORAGE_KEYS: usize = 100; +const NB_OF_STORAGE_VALUES: usize = 100; +const NB_OF_CLASSES: usize = 100; +const NB_OF_CONTRACTS: usize = 100; + +pub fn commit(block: UncommittedBlock<'_, DbProvider>) { + let _ = block.commit(); +} + +pub fn commit_parallel(block: UncommittedBlock<'_, DbProvider>) { + let _ = block.commit_parallel(); +} + +#[inline(always)] +pub fn random_array(size: usize) -> Vec { + (0..size).map(|_| rand::random::()).collect() +} + +#[inline(always)] +pub fn random_felt() -> Felt { + Felt::arbitrary(&mut Unstructured::new(&random_array(Felt::size_hint(0).0))).unwrap() +} + +#[inline(always)] +pub fn random_tx() -> Tx { + Tx::arbitrary(&mut Unstructured::new(&random_array(Tx::size_hint(0).0))).unwrap() +} + +#[inline(always)] +pub fn random_tx_with_hash() -> TxWithHash { + TxWithHash { hash: random_felt(), transaction: random_tx() } +} + +#[inline(always)] +pub fn random_receipt() -> Receipt { + Receipt::arbitrary(&mut Unstructured::new(&random_array(Receipt::size_hint(0).0))).unwrap() +} + +#[inline(always)] +pub fn random_receipt_with_hash() -> ReceiptWithTxHash { + ReceiptWithTxHash { tx_hash: random_felt(), receipt: random_receipt() } +} + +#[inline(always)] +pub fn random_felt_to_felt_map(size: usize) -> BTreeMap { + (0..size).map(|_| (random_felt(), random_felt())).collect() +} + +#[inline(always)] +pub fn random_address_to_felt_map(size: usize) -> BTreeMap { + (0..size).map(|_| (ContractAddress::new(random_felt()), random_felt())).collect() +} + +pub fn commit_benchmark(c: &mut Criterion) { + let provider = DbProvider::new_ephemeral(); + + let gas_prices = GasPrices { eth: 100 * u128::pow(10, 9), strk: 100 * u128::pow(10, 9) }; + let sequencer_address = ContractAddress(1u64.into()); + + let header = PartialHeader { + protocol_version: CURRENT_STARKNET_VERSION, + number: 1, + timestamp: 100, + sequencer_address, + parent_hash: 123u64.into(), + l1_gas_prices: gas_prices.clone(), + l1_data_gas_prices: gas_prices.clone(), + l1_da_mode: L1DataAvailabilityMode::Calldata, + }; + + let transactions: Vec = (0..NB_OF_TXS).map(|_| random_tx_with_hash()).collect(); + let receipts: Vec = + (0..NB_OF_RECEIPTS).map(|_| random_receipt_with_hash()).collect(); + + let nonce_updates: BTreeMap = + (0..NB_OF_NONCES).map(|_| (ContractAddress::new(random_felt()), random_felt())).collect(); + + let storage_updates: BTreeMap> = (0..NB_OF_STORAGE_KEYS) + .map(|_| { + (ContractAddress::new(random_felt()), random_felt_to_felt_map(NB_OF_STORAGE_VALUES)) + }) + .collect(); + + let declared_classes: BTreeMap = random_felt_to_felt_map(NB_OF_CLASSES); + let deployed_contracts: BTreeMap = + random_address_to_felt_map(NB_OF_CONTRACTS); + + let state_updates = StateUpdates { + nonce_updates, + storage_updates, + declared_classes, + deployed_contracts, + ..Default::default() + }; + + let block = + UncommittedBlock::new(header, transactions, receipts.as_slice(), &state_updates, provider); + + c.bench_function("commit", |b| { + b.iter_batched(|| block.clone(), |input| commit(black_box(input)), BatchSize::SmallInput); + }); + + c.bench_function("commit_parallel", |b| { + b.iter_batched( + || block.clone(), + |input| commit_parallel(black_box(input)), + BatchSize::SmallInput, + ); + }); +} + +criterion_group!(benches, commit_benchmark); +criterion_main!(benches); diff --git a/crates/katana/core/src/backend/mod.rs b/crates/katana/core/src/backend/mod.rs index a0823209a4..82e3682637 100644 --- a/crates/katana/core/src/backend/mod.rs +++ b/crates/katana/core/src/backend/mod.rs @@ -21,6 +21,7 @@ use katana_provider::traits::block::{BlockHashProvider, BlockWriter}; use katana_provider::traits::trie::TrieWriter; use katana_trie::compute_merkle_root; use parking_lot::RwLock; +use rayon::prelude::*; use starknet::macros::short_string; use starknet_types_core::hash::{self, StarkHash}; use tracing::info; @@ -363,6 +364,7 @@ impl<'a, P: TrieWriter> UncommittedBlock<'a, P> { let transaction_count = self.transactions.len() as u32; let state_diff_length = self.state_updates.len() as u32; + // optimisation 1 let state_root = self.compute_new_state_root(); let transactions_commitment = self.compute_transaction_commitment(); let events_commitment = self.compute_event_commitment(); @@ -393,6 +395,51 @@ impl<'a, P: TrieWriter> UncommittedBlock<'a, P> { SealedBlock { hash, header, body: self.transactions } } + pub fn commit_parallel(self) -> SealedBlock { + // get the hash of the latest committed block + let parent_hash = self.header.parent_hash; + let events_count = self.receipts.iter().map(|r| r.events().len() as u32).sum::(); + let transaction_count = self.transactions.len() as u32; + let state_diff_length = self.state_updates.len() as u32; + + let mut state_root = Felt::default(); + let mut transactions_commitment = Felt::default(); + let mut events_commitment = Felt::default(); + let mut receipts_commitment = Felt::default(); + let mut state_diff_commitment = Felt::default(); + + rayon::scope(|s| { + s.spawn(|_| state_root = self.compute_new_state_root()); + s.spawn(|_| transactions_commitment = self.compute_transaction_commitment()); + s.spawn(|_| events_commitment = self.compute_event_commitment_parallel()); + s.spawn(|_| receipts_commitment = self.compute_receipt_commitment_parallel()); + s.spawn(|_| state_diff_commitment = self.compute_state_diff_commitment()); + }); + + let header = Header { + state_root, + parent_hash, + events_count, + state_diff_length, + transaction_count, + events_commitment, + receipts_commitment, + state_diff_commitment, + transactions_commitment, + number: self.header.number, + timestamp: self.header.timestamp, + l1_da_mode: self.header.l1_da_mode, + l1_gas_prices: self.header.l1_gas_prices, + l1_data_gas_prices: self.header.l1_data_gas_prices, + sequencer_address: self.header.sequencer_address, + protocol_version: self.header.protocol_version, + }; + + let hash = header.compute_hash(); + + SealedBlock { hash, header, body: self.transactions } + } + fn compute_transaction_commitment(&self) -> Felt { let tx_hashes = self.transactions.iter().map(|t| t.hash).collect::>(); compute_merkle_root::(&tx_hashes).unwrap() @@ -403,6 +450,12 @@ impl<'a, P: TrieWriter> UncommittedBlock<'a, P> { compute_merkle_root::(&receipt_hashes).unwrap() } + fn compute_receipt_commitment_parallel(&self) -> Felt { + let receipt_hashes = + self.receipts.par_iter().map(|r| r.compute_hash()).collect::>(); + compute_merkle_root::(&receipt_hashes).unwrap() + } + fn compute_state_diff_commitment(&self) -> Felt { compute_state_diff_hash(self.state_updates.clone()) } @@ -418,7 +471,6 @@ impl<'a, P: TrieWriter> UncommittedBlock<'a, P> { // the iterator will yield all events from all the receipts, each one paired with the // transaction hash that emitted it: (tx hash, event). let events = self.receipts.iter().flat_map(|r| r.events().iter().map(|e| (r.tx_hash, e))); - let mut hashes = Vec::new(); for (tx, event) in events { let event_hash = event_hash(tx, event); @@ -429,6 +481,27 @@ impl<'a, P: TrieWriter> UncommittedBlock<'a, P> { compute_merkle_root::(&hashes).unwrap() } + fn compute_event_commitment_parallel(&self) -> Felt { + // h(emitter_address, tx_hash, h(keys), h(data)) + fn event_hash(tx: TxHash, event: &Event) -> Felt { + let keys_hash = hash::Poseidon::hash_array(&event.keys); + let data_hash = hash::Poseidon::hash_array(&event.data); + hash::Poseidon::hash_array(&[tx, event.from_address.into(), keys_hash, data_hash]) + } + + // the iterator will yield all events from all the receipts, each one paired with the + // transaction hash that emitted it: (tx hash, event). + let events = self.receipts.iter().flat_map(|r| r.events().iter().map(|e| (r.tx_hash, e))); + let hashes = events + .par_bridge() + .into_par_iter() + .map(|(tx, event)| event_hash(tx, event)) + .collect::>(); + + // compute events commitment + compute_merkle_root::(&hashes).unwrap() + } + // state_commitment = hPos("STARKNET_STATE_V0", contract_trie_root, class_trie_root) fn compute_new_state_root(&self) -> Felt { let class_trie_root = self From 253288d0b55e33bf8e8314edd80cccd29621525a Mon Sep 17 00:00:00 2001 From: "remy.baranx@gmail.com" Date: Fri, 7 Feb 2025 11:35:35 +0100 Subject: [PATCH 2/6] after review --- Cargo.lock | 1 + Cargo.toml | 1 + crates/katana/core/Cargo.toml | 1 + crates/katana/core/benches/commit.rs | 171 +++++++++++++++++++-------- crates/katana/executor/Cargo.toml | 2 +- 5 files changed, 126 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c32395b261..e33ab0ab4b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8146,6 +8146,7 @@ dependencies = [ "metrics", "num-traits 0.2.19", "parking_lot 0.12.3", + "pprof", "rand 0.8.5", "rayon", "reqwest 0.11.27", diff --git a/Cargo.toml b/Cargo.toml index 297f22755e..3f3c72b5cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -259,6 +259,7 @@ alloy-primitives = { version = "0.8.3", default-features = false } alloy-sol-types = { version = "0.8.3", default-features = false } criterion = "0.5.1" +pprof = { version = "0.13.0", features = [ "criterion", "flamegraph" ] } # Slot integration. Dojo don't need to manually include `account_sdk` as dependency as `slot` already re-exports it. slot = { git = "https://github.com/cartridge-gg/slot", rev = "1298a30" } diff --git a/crates/katana/core/Cargo.toml b/crates/katana/core/Cargo.toml index 1cce58b0d0..03d842de90 100644 --- a/crates/katana/core/Cargo.toml +++ b/crates/katana/core/Cargo.toml @@ -56,6 +56,7 @@ rstest.workspace = true tempfile.workspace = true arbitrary.workspace = true rand.workspace = true +pprof.workspace = true [features] starknet-messaging = [ "dep:starknet-crypto" ] diff --git a/crates/katana/core/benches/commit.rs b/crates/katana/core/benches/commit.rs index 4102d07dfd..0efcec2447 100644 --- a/crates/katana/core/benches/commit.rs +++ b/crates/katana/core/benches/commit.rs @@ -12,95 +12,110 @@ use katana_primitives::version::CURRENT_STARKNET_VERSION; use katana_primitives::{ContractAddress, Felt}; use katana_provider::providers::db::DbProvider; -const NB_OF_TXS: usize = 20; -const NB_OF_RECEIPTS: usize = 20; -const NB_OF_NONCES: usize = 100; -const NB_OF_STORAGE_KEYS: usize = 100; -const NB_OF_STORAGE_VALUES: usize = 100; -const NB_OF_CLASSES: usize = 100; -const NB_OF_CONTRACTS: usize = 100; - -pub fn commit(block: UncommittedBlock<'_, DbProvider>) { +use pprof::criterion::{Output, PProfProfiler}; + +struct BlockConfig { + nb_of_txs: usize, + nb_of_receipts: usize, + nb_of_nonces: usize, + nb_of_storage_keys: usize, + nb_of_storage_values: usize, + nb_of_classes: usize, + nb_of_contracts: usize, +} + +const SMALL_BLOCK_CONFIG: BlockConfig = BlockConfig { + nb_of_txs: 1, + nb_of_receipts: 1, + nb_of_nonces: 1, + nb_of_storage_keys: 1, + nb_of_storage_values: 1, + nb_of_classes: 1, + nb_of_contracts: 1, +}; + +const BIG_BLOCK_CONFIG: BlockConfig = BlockConfig { + nb_of_txs: 20, + nb_of_receipts: 20, + nb_of_nonces: 100, + nb_of_storage_keys: 100, + nb_of_storage_values: 100, + nb_of_classes: 100, + nb_of_contracts: 100, +}; + +fn commit(block: UncommittedBlock<'_, DbProvider>) { let _ = block.commit(); } -pub fn commit_parallel(block: UncommittedBlock<'_, DbProvider>) { +fn commit_parallel(block: UncommittedBlock<'_, DbProvider>) { let _ = block.commit_parallel(); } #[inline(always)] -pub fn random_array(size: usize) -> Vec { +fn random_array(size: usize) -> Vec { (0..size).map(|_| rand::random::()).collect() } #[inline(always)] -pub fn random_felt() -> Felt { +fn random_felt() -> Felt { Felt::arbitrary(&mut Unstructured::new(&random_array(Felt::size_hint(0).0))).unwrap() } #[inline(always)] -pub fn random_tx() -> Tx { +fn random_tx() -> Tx { Tx::arbitrary(&mut Unstructured::new(&random_array(Tx::size_hint(0).0))).unwrap() } #[inline(always)] -pub fn random_tx_with_hash() -> TxWithHash { +fn random_tx_with_hash() -> TxWithHash { TxWithHash { hash: random_felt(), transaction: random_tx() } } #[inline(always)] -pub fn random_receipt() -> Receipt { +fn random_receipt() -> Receipt { Receipt::arbitrary(&mut Unstructured::new(&random_array(Receipt::size_hint(0).0))).unwrap() } #[inline(always)] -pub fn random_receipt_with_hash() -> ReceiptWithTxHash { +fn random_receipt_with_hash() -> ReceiptWithTxHash { ReceiptWithTxHash { tx_hash: random_felt(), receipt: random_receipt() } } #[inline(always)] -pub fn random_felt_to_felt_map(size: usize) -> BTreeMap { +fn random_felt_to_felt_map(size: usize) -> BTreeMap { (0..size).map(|_| (random_felt(), random_felt())).collect() } #[inline(always)] -pub fn random_address_to_felt_map(size: usize) -> BTreeMap { +fn random_address_to_felt_map(size: usize) -> BTreeMap { (0..size).map(|_| (ContractAddress::new(random_felt()), random_felt())).collect() } -pub fn commit_benchmark(c: &mut Criterion) { - let provider = DbProvider::new_ephemeral(); - - let gas_prices = GasPrices { eth: 100 * u128::pow(10, 9), strk: 100 * u128::pow(10, 9) }; - let sequencer_address = ContractAddress(1u64.into()); - - let header = PartialHeader { - protocol_version: CURRENT_STARKNET_VERSION, - number: 1, - timestamp: 100, - sequencer_address, - parent_hash: 123u64.into(), - l1_gas_prices: gas_prices.clone(), - l1_data_gas_prices: gas_prices.clone(), - l1_da_mode: L1DataAvailabilityMode::Calldata, - }; +fn build_block(config: BlockConfig) -> (Vec, Vec, StateUpdates) { + let transactions: Vec = + (0..config.nb_of_txs).map(|_| random_tx_with_hash()).collect(); - let transactions: Vec = (0..NB_OF_TXS).map(|_| random_tx_with_hash()).collect(); let receipts: Vec = - (0..NB_OF_RECEIPTS).map(|_| random_receipt_with_hash()).collect(); + (0..config.nb_of_receipts).map(|_| random_receipt_with_hash()).collect(); - let nonce_updates: BTreeMap = - (0..NB_OF_NONCES).map(|_| (ContractAddress::new(random_felt()), random_felt())).collect(); + let nonce_updates: BTreeMap = (0..config.nb_of_nonces) + .map(|_| (ContractAddress::new(random_felt()), random_felt())) + .collect(); - let storage_updates: BTreeMap> = (0..NB_OF_STORAGE_KEYS) + let storage_updates: BTreeMap> = (0..config + .nb_of_storage_keys) .map(|_| { - (ContractAddress::new(random_felt()), random_felt_to_felt_map(NB_OF_STORAGE_VALUES)) + ( + ContractAddress::new(random_felt()), + random_felt_to_felt_map(config.nb_of_storage_values), + ) }) .collect(); - let declared_classes: BTreeMap = random_felt_to_felt_map(NB_OF_CLASSES); + let declared_classes: BTreeMap = random_felt_to_felt_map(config.nb_of_classes); let deployed_contracts: BTreeMap = - random_address_to_felt_map(NB_OF_CONTRACTS); + random_address_to_felt_map(config.nb_of_contracts); let state_updates = StateUpdates { nonce_updates, @@ -110,21 +125,79 @@ pub fn commit_benchmark(c: &mut Criterion) { ..Default::default() }; - let block = - UncommittedBlock::new(header, transactions, receipts.as_slice(), &state_updates, provider); + (transactions, receipts, state_updates) +} + +fn commit_benchmark(c: &mut Criterion) { + let gas_prices = GasPrices { eth: 100 * u128::pow(10, 9), strk: 100 * u128::pow(10, 9) }; + let sequencer_address = ContractAddress(1u64.into()); - c.bench_function("commit", |b| { - b.iter_batched(|| block.clone(), |input| commit(black_box(input)), BatchSize::SmallInput); + let header = PartialHeader { + protocol_version: CURRENT_STARKNET_VERSION, + number: 1, + timestamp: 100, + sequencer_address, + parent_hash: 123u64.into(), + l1_gas_prices: gas_prices.clone(), + l1_data_gas_prices: gas_prices.clone(), + l1_da_mode: L1DataAvailabilityMode::Calldata, + }; + + let (small_transactions, small_receipts, small_state_updates) = build_block(SMALL_BLOCK_CONFIG); + + let small_block = UncommittedBlock::new( + header.clone(), + small_transactions, + small_receipts.as_slice(), + &small_state_updates, + DbProvider::new_ephemeral(), + ); + + let (big_transactions, big_receipts, big_state_updates) = build_block(BIG_BLOCK_CONFIG); + let big_block = UncommittedBlock::new( + header, + big_transactions, + big_receipts.as_slice(), + &big_state_updates, + DbProvider::new_ephemeral(), + ); + + c.bench_function("Commit.Small.Serial", |b| { + b.iter_batched( + || small_block.clone(), + |input| commit(black_box(input)), + BatchSize::SmallInput, + ); }); - c.bench_function("commit_parallel", |b| { + c.bench_function("Commit.Small.Parallel", |b| { b.iter_batched( - || block.clone(), + || small_block.clone(), + |input| commit_parallel(black_box(input)), + BatchSize::SmallInput, + ); + }); + + c.bench_function("Commit.Big.Serial", |b| { + b.iter_batched( + || big_block.clone(), + |input| commit(black_box(input)), + BatchSize::SmallInput, + ); + }); + + c.bench_function("Commit.Big.Parallel", |b| { + b.iter_batched( + || big_block.clone(), |input| commit_parallel(black_box(input)), BatchSize::SmallInput, ); }); } -criterion_group!(benches, commit_benchmark); +criterion_group! { + name = benches; + config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); + targets = commit_benchmark +} criterion_main!(benches); diff --git a/crates/katana/executor/Cargo.toml b/crates/katana/executor/Cargo.toml index 4cb044d5c9..67cb8d7075 100644 --- a/crates/katana/executor/Cargo.toml +++ b/crates/katana/executor/Cargo.toml @@ -36,7 +36,7 @@ tokio.workspace = true criterion.workspace = true oneshot = { version = "0.1.8", default-features = false, features = [ "std" ] } -pprof = { version = "0.13.0", features = [ "criterion", "flamegraph" ] } +pprof.workspace = true rayon.workspace = true [features] From 82a0abbfe8d829ef7580531ee4d7b68407b67af9 Mon Sep 17 00:00:00 2001 From: "remy.baranx@gmail.com" Date: Fri, 7 Feb 2025 11:42:10 +0100 Subject: [PATCH 3/6] fix duplicates in Cargo.toml --- Cargo.lock | 2 +- crates/katana/core/Cargo.toml | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e33ab0ab4b..6998935217 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8147,7 +8147,7 @@ dependencies = [ "num-traits 0.2.19", "parking_lot 0.12.3", "pprof", - "rand 0.8.5", + "rand", "rayon", "reqwest 0.11.27", "rstest 0.18.2", diff --git a/crates/katana/core/Cargo.toml b/crates/katana/core/Cargo.toml index 03d842de90..90be5f59f2 100644 --- a/crates/katana/core/Cargo.toml +++ b/crates/katana/core/Cargo.toml @@ -54,8 +54,6 @@ hex.workspace = true rand.workspace = true rstest.workspace = true tempfile.workspace = true -arbitrary.workspace = true -rand.workspace = true pprof.workspace = true [features] From 046ecc6131c98bad9aaa3e1339a7f5f7f46e9e0c Mon Sep 17 00:00:00 2001 From: "remy.baranx@gmail.com" Date: Fri, 7 Feb 2025 11:50:19 +0100 Subject: [PATCH 4/6] fix fmt --- crates/katana/core/benches/commit.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/katana/core/benches/commit.rs b/crates/katana/core/benches/commit.rs index 0efcec2447..c9d10c1588 100644 --- a/crates/katana/core/benches/commit.rs +++ b/crates/katana/core/benches/commit.rs @@ -11,7 +11,6 @@ use katana_primitives::transaction::{Tx, TxWithHash}; use katana_primitives::version::CURRENT_STARKNET_VERSION; use katana_primitives::{ContractAddress, Felt}; use katana_provider::providers::db::DbProvider; - use pprof::criterion::{Output, PProfProfiler}; struct BlockConfig { From 32ba95180d3f35dd9d179b9e9a34e61fec3ab3ec Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Fri, 7 Feb 2025 12:25:44 -0500 Subject: [PATCH 5/6] group by block size --- crates/katana/core/benches/commit.rs | 115 ++++++++++---------- crates/katana/primitives/src/block.rs | 1 + crates/katana/primitives/src/receipt.rs | 1 + crates/katana/primitives/src/transaction.rs | 1 + 4 files changed, 58 insertions(+), 60 deletions(-) diff --git a/crates/katana/core/benches/commit.rs b/crates/katana/core/benches/commit.rs index c9d10c1588..cc0d8080ba 100644 --- a/crates/katana/core/benches/commit.rs +++ b/crates/katana/core/benches/commit.rs @@ -1,14 +1,13 @@ use std::collections::BTreeMap; +use std::time::Duration; use arbitrary::{Arbitrary, Unstructured}; use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion}; use katana_core::backend::UncommittedBlock; -use katana_primitives::block::{GasPrices, PartialHeader}; -use katana_primitives::da::L1DataAvailabilityMode; -use katana_primitives::receipt::{Receipt, ReceiptWithTxHash}; +use katana_primitives::block::PartialHeader; +use katana_primitives::receipt::ReceiptWithTxHash; use katana_primitives::state::StateUpdates; -use katana_primitives::transaction::{Tx, TxWithHash}; -use katana_primitives::version::CURRENT_STARKNET_VERSION; +use katana_primitives::transaction::TxWithHash; use katana_primitives::{ContractAddress, Felt}; use katana_provider::providers::db::DbProvider; use pprof::criterion::{Output, PProfProfiler}; @@ -61,24 +60,18 @@ fn random_felt() -> Felt { Felt::arbitrary(&mut Unstructured::new(&random_array(Felt::size_hint(0).0))).unwrap() } -#[inline(always)] -fn random_tx() -> Tx { - Tx::arbitrary(&mut Unstructured::new(&random_array(Tx::size_hint(0).0))).unwrap() -} - #[inline(always)] fn random_tx_with_hash() -> TxWithHash { - TxWithHash { hash: random_felt(), transaction: random_tx() } -} - -#[inline(always)] -fn random_receipt() -> Receipt { - Receipt::arbitrary(&mut Unstructured::new(&random_array(Receipt::size_hint(0).0))).unwrap() + TxWithHash::arbitrary(&mut Unstructured::new(&random_array(TxWithHash::size_hint(0).0))) + .unwrap() } #[inline(always)] fn random_receipt_with_hash() -> ReceiptWithTxHash { - ReceiptWithTxHash { tx_hash: random_felt(), receipt: random_receipt() } + ReceiptWithTxHash::arbitrary(&mut Unstructured::new(&random_array( + ReceiptWithTxHash::size_hint(0).0, + ))) + .unwrap() } #[inline(always)] @@ -91,7 +84,15 @@ fn random_address_to_felt_map(size: usize) -> BTreeMap { (0..size).map(|_| (ContractAddress::new(random_felt()), random_felt())).collect() } -fn build_block(config: BlockConfig) -> (Vec, Vec, StateUpdates) { +#[inline(always)] +fn random_header() -> PartialHeader { + PartialHeader::arbitrary(&mut Unstructured::new(&random_array(PartialHeader::size_hint(0).0))) + .unwrap() +} + +fn build_block( + config: BlockConfig, +) -> (PartialHeader, Vec, Vec, StateUpdates) { let transactions: Vec = (0..config.nb_of_txs).map(|_| random_tx_with_hash()).collect(); @@ -124,76 +125,70 @@ fn build_block(config: BlockConfig) -> (Vec, Vec, ..Default::default() }; - (transactions, receipts, state_updates) + let header = random_header(); + + (header, transactions, receipts, state_updates) } -fn commit_benchmark(c: &mut Criterion) { - let gas_prices = GasPrices { eth: 100 * u128::pow(10, 9), strk: 100 * u128::pow(10, 9) }; - let sequencer_address = ContractAddress(1u64.into()); - - let header = PartialHeader { - protocol_version: CURRENT_STARKNET_VERSION, - number: 1, - timestamp: 100, - sequencer_address, - parent_hash: 123u64.into(), - l1_gas_prices: gas_prices.clone(), - l1_data_gas_prices: gas_prices.clone(), - l1_da_mode: L1DataAvailabilityMode::Calldata, - }; +fn commit_small(c: &mut Criterion) { + let mut c = c.benchmark_group("Commit.Small"); + c.warm_up_time(Duration::from_secs(1)); - let (small_transactions, small_receipts, small_state_updates) = build_block(SMALL_BLOCK_CONFIG); + let (header, small_transactions, small_receipts, small_state_updates) = + build_block(SMALL_BLOCK_CONFIG); - let small_block = UncommittedBlock::new( - header.clone(), + let block = UncommittedBlock::new( + header, small_transactions, small_receipts.as_slice(), &small_state_updates, DbProvider::new_ephemeral(), ); - let (big_transactions, big_receipts, big_state_updates) = build_block(BIG_BLOCK_CONFIG); - let big_block = UncommittedBlock::new( - header, - big_transactions, - big_receipts.as_slice(), - &big_state_updates, - DbProvider::new_ephemeral(), - ); - - c.bench_function("Commit.Small.Serial", |b| { - b.iter_batched( - || small_block.clone(), - |input| commit(black_box(input)), - BatchSize::SmallInput, - ); + c.bench_function("Serial", |b| { + b.iter_batched(|| block.clone(), |input| commit(black_box(input)), BatchSize::SmallInput); }); - c.bench_function("Commit.Small.Parallel", |b| { + c.bench_function("Parallel", |b| { b.iter_batched( - || small_block.clone(), + || block.clone(), |input| commit_parallel(black_box(input)), BatchSize::SmallInput, ); }); +} - c.bench_function("Commit.Big.Serial", |b| { - b.iter_batched( - || big_block.clone(), - |input| commit(black_box(input)), - BatchSize::SmallInput, - ); +fn commit_big(c: &mut Criterion) { + let mut c = c.benchmark_group("Commit.Big"); + c.warm_up_time(Duration::from_secs(1)); + + let (header, big_transactions, big_receipts, big_state_updates) = build_block(BIG_BLOCK_CONFIG); + let block = UncommittedBlock::new( + header, + big_transactions, + big_receipts.as_slice(), + &big_state_updates, + DbProvider::new_ephemeral(), + ); + + c.bench_function("Commit.Small.Parallel", |b| { + b.iter_batched(|| block.clone(), |input| commit(black_box(input)), BatchSize::SmallInput); }); c.bench_function("Commit.Big.Parallel", |b| { b.iter_batched( - || big_block.clone(), + || block.clone(), |input| commit_parallel(black_box(input)), BatchSize::SmallInput, ); }); } +fn commit_benchmark(c: &mut Criterion) { + commit_small(c); + commit_big(c); +} + criterion_group! { name = benches; config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); diff --git a/crates/katana/primitives/src/block.rs b/crates/katana/primitives/src/block.rs index 106499d437..6c40e0b13d 100644 --- a/crates/katana/primitives/src/block.rs +++ b/crates/katana/primitives/src/block.rs @@ -42,6 +42,7 @@ pub enum FinalityStatus { /// Represents a partial block header. #[derive(Debug, Clone)] +#[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct PartialHeader { pub parent_hash: BlockHash, diff --git a/crates/katana/primitives/src/receipt.rs b/crates/katana/primitives/src/receipt.rs index abe0dbec3c..77f5caaf98 100644 --- a/crates/katana/primitives/src/receipt.rs +++ b/crates/katana/primitives/src/receipt.rs @@ -178,6 +178,7 @@ impl Receipt { } #[derive(Debug, Clone, AsRef, Deref, PartialEq, Eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ReceiptWithTxHash { /// The hash of the transaction. diff --git a/crates/katana/primitives/src/transaction.rs b/crates/katana/primitives/src/transaction.rs index f34f9133f5..c17205c33e 100644 --- a/crates/katana/primitives/src/transaction.rs +++ b/crates/katana/primitives/src/transaction.rs @@ -652,6 +652,7 @@ pub struct DeployTx { } #[derive(Debug, Clone, AsRef, Deref, PartialEq, Eq)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TxWithHash { /// The hash of the transaction. From ad0f6a644157f39fc9d1b88e07931b2d5397096b Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Fri, 7 Feb 2025 12:31:25 -0500 Subject: [PATCH 6/6] fix name --- crates/katana/core/benches/commit.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/katana/core/benches/commit.rs b/crates/katana/core/benches/commit.rs index cc0d8080ba..8c1b582365 100644 --- a/crates/katana/core/benches/commit.rs +++ b/crates/katana/core/benches/commit.rs @@ -171,11 +171,11 @@ fn commit_big(c: &mut Criterion) { DbProvider::new_ephemeral(), ); - c.bench_function("Commit.Small.Parallel", |b| { + c.bench_function("Serial", |b| { b.iter_batched(|| block.clone(), |input| commit(black_box(input)), BatchSize::SmallInput); }); - c.bench_function("Commit.Big.Parallel", |b| { + c.bench_function("Parallel", |b| { b.iter_batched( || block.clone(), |input| commit_parallel(black_box(input)),