diff --git a/Cargo.lock b/Cargo.lock index b9fa7bdbbf..c082a928a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2995,6 +2995,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "cpp_demangle" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119" +dependencies = [ + "cfg-if", +] + [[package]] name = "cpufeatures" version = "0.2.12" @@ -3351,6 +3360,15 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "uuid 1.7.0", +] + [[package]] name = "deno_task_shell" version = "0.14.4" @@ -4202,6 +4220,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "findshlibs" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64" +dependencies = [ + "cc", + "lazy_static", + "libc", + "winapi", +] + [[package]] name = "finl_unicode" version = "1.2.0" @@ -6181,6 +6211,24 @@ version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" +[[package]] +name = "inferno" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "321f0f839cd44a4686e9504b0a62b4d69a50b62072144c71c68f5873c167b8d9" +dependencies = [ + "ahash 0.8.8", + "indexmap 2.2.5", + "is-terminal", + "itoa", + "log", + "num-format", + "once_cell", + "quick-xml", + "rgb", + "str_stack", +] + [[package]] name = "inotify" version = "0.9.6" @@ -6872,11 +6920,13 @@ dependencies = [ "blockifier", "cairo-vm", "convert_case 0.6.0", + "criterion", "futures", "katana-primitives", "katana-provider", "katana-rpc-types", "parking_lot 0.12.1", + "pprof", "rstest 0.18.2", "rstest_reuse", "serde_json", @@ -8509,6 +8559,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "num-format" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" +dependencies = [ + "arrayvec", + "itoa", +] + [[package]] name = "num-integer" version = "0.1.46" @@ -9205,6 +9265,28 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "pprof" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5c97c51bd34c7e742402e216abdeb44d415fbe6ae41d56b114723e953711cb" +dependencies = [ + "backtrace", + "cfg-if", + "criterion", + "findshlibs", + "inferno", + "libc", + "log", + "nix 0.26.4", + "once_cell", + "parking_lot 0.12.1", + "smallvec", + "symbolic-demangle", + "tempfile", + "thiserror", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -9593,6 +9675,15 @@ dependencies = [ "unsigned-varint 0.8.0", ] +[[package]] +name = "quick-xml" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd" +dependencies = [ + "memchr", +] + [[package]] name = "quinn" version = "0.10.2" @@ -10000,6 +10091,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "rgb" +version = "0.8.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8" +dependencies = [ + "bytemuck", +] + [[package]] name = "ring" version = "0.16.20" @@ -11701,6 +11801,12 @@ dependencies = [ "uuid 1.7.0", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "starknet" version = "0.10.0" @@ -11935,6 +12041,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "str_stack" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9091b6114800a5f2141aee1d1b9d6ca3592ac062dc5decb3764ec5895a47b4eb" + [[package]] name = "string_cache" version = "0.8.7" @@ -12061,6 +12173,29 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" +[[package]] +name = "symbolic-common" +version = "12.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cccfffbc6bb3bb2d3a26cd2077f4d055f6808d266f9d4d158797a4c60510dfe" +dependencies = [ + "debugid", + "memmap2", + "stable_deref_trait", + "uuid 1.7.0", +] + +[[package]] +name = "symbolic-demangle" +version = "12.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a99812da4020a67e76c4eb41f08c87364c14170495ff780f30dd519c221a68" +dependencies = [ + "cpp_demangle", + "rustc-demangle", + "symbolic-common", +] + [[package]] name = "syn" version = "1.0.109" diff --git a/Cargo.toml b/Cargo.toml index 5a465a47fd..6ce0761f97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -209,6 +209,8 @@ wasm-tonic-build = { version = "0.9.2", default-features = false, features = [ " alloy-primitives = { version = "0.7.2", default-features = false } alloy-sol-types = { version = "0.7.2", default-features = false } +criterion = "0.5.1" + [patch.crates-io] cairo-felt = { git = "https://github.com/dojoengine/cairo-rs.git", rev = "1031381" } cairo-vm = { git = "https://github.com/dojoengine/cairo-rs.git", rev = "1031381" } diff --git a/crates/katana/executor/Cargo.toml b/crates/katana/executor/Cargo.toml index 013739321c..3f3cd15ded 100644 --- a/crates/katana/executor/Cargo.toml +++ b/crates/katana/executor/Cargo.toml @@ -34,7 +34,7 @@ cairo-vm = { workspace = true, optional = true } [dev-dependencies] anyhow.workspace = true cairo-vm.workspace = true -katana-provider.workspace = true +katana-provider = { workspace = true, features = [ "test-utils" ] } katana-rpc-types.workspace = true rstest.workspace = true rstest_reuse.workspace = true @@ -42,8 +42,16 @@ serde_json.workspace = true similar-asserts.workspace = true tokio.workspace = true +criterion.workspace = true +pprof = { version = "0.13.0", features = [ "criterion", "flamegraph" ] } + [features] blockifier = [ "dep:blockifier", "dep:cairo-vm" ] default = [ "blockifier" ] # native = [ "sir", "sir/cairo-native" ] # sir = [ "dep:sir", "dep:starknet-types-core" ] + +[[bench]] +harness = false +name = "execution" +required-features = [ "blockifier" ] diff --git a/crates/katana/executor/benches/execution.rs b/crates/katana/executor/benches/execution.rs new file mode 100644 index 0000000000..a1f546569c --- /dev/null +++ b/crates/katana/executor/benches/execution.rs @@ -0,0 +1,67 @@ +use std::time::Duration; + +use blockifier::state::cached_state::{CachedState, GlobalContractCache}; +use criterion::measurement::WallTime; +use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkGroup, Criterion}; +use katana_executor::{SimulationFlag, StateProviderDb}; +use katana_primitives::env::{BlockEnv, CfgEnv}; +use katana_primitives::transaction::ExecutableTxWithHash; +use katana_provider::test_utils; +use katana_provider::traits::state::StateFactoryProvider; +use pprof::criterion::{Output, PProfProfiler}; + +use crate::utils::{envs, tx}; + +mod utils; + +fn executor_transact(c: &mut Criterion) { + let mut group = c.benchmark_group("Invoke.ERC20.transfer"); + group.warm_up_time(Duration::from_millis(200)); + + let provider = test_utils::test_in_memory_provider(); + let flags = SimulationFlag::new(); + + let tx = tx(); + let envs = envs(); + + blockifier(&mut group, &provider, &flags, &envs, tx); +} + +fn blockifier( + group: &mut BenchmarkGroup<'_, WallTime>, + provider: impl StateFactoryProvider, + execution_flags: &SimulationFlag, + block_envs: &(BlockEnv, CfgEnv), + tx: ExecutableTxWithHash, +) { + use katana_executor::implementation::blockifier::utils::{block_context_from_envs, transact}; + + // convert to blockifier block context + let block_context = block_context_from_envs(&block_envs.0, &block_envs.1); + + group.bench_function("Blockifier", |b| { + // we need to set up the cached state for each iteration as it's not cloneable + b.iter_batched( + || { + // setup state + let state = provider.latest().expect("failed to get latest state"); + + // setup blockifier cached state + let contract_cache = GlobalContractCache::new(100); + let state = CachedState::new(StateProviderDb::from(state), contract_cache); + + (state, &block_context, execution_flags, tx.clone()) + }, + |(mut state, block_context, flags, tx)| transact(&mut state, block_context, flags, tx), + BatchSize::SmallInput, + ) + }); +} + +criterion_group! { + name = benches; + config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); + targets = executor_transact +} + +criterion_main!(benches); diff --git a/crates/katana/executor/benches/utils.rs b/crates/katana/executor/benches/utils.rs new file mode 100644 index 0000000000..fb05d0bbae --- /dev/null +++ b/crates/katana/executor/benches/utils.rs @@ -0,0 +1,67 @@ +use std::collections::HashMap; + +use cairo_vm::vm::runners::builtin_runner::{ + BITWISE_BUILTIN_NAME, EC_OP_BUILTIN_NAME, HASH_BUILTIN_NAME, KECCAK_BUILTIN_NAME, + OUTPUT_BUILTIN_NAME, POSEIDON_BUILTIN_NAME, RANGE_CHECK_BUILTIN_NAME, + SEGMENT_ARENA_BUILTIN_NAME, SIGNATURE_BUILTIN_NAME, +}; +use katana_primitives::block::GasPrices; +use katana_primitives::env::{BlockEnv, CfgEnv, FeeTokenAddressses}; +use katana_primitives::genesis::constant::DEFAULT_FEE_TOKEN_ADDRESS; +use katana_primitives::transaction::{ExecutableTxWithHash, InvokeTx, InvokeTxV1}; +use katana_primitives::FieldElement; +use starknet::macros::{felt, selector}; + +pub fn tx() -> ExecutableTxWithHash { + let invoke = InvokeTx::V1(InvokeTxV1 { + sender_address: felt!("0x1").into(), + calldata: vec![ + DEFAULT_FEE_TOKEN_ADDRESS.into(), + selector!("transfer"), + FieldElement::THREE, + felt!("0x100"), + FieldElement::ONE, + FieldElement::ZERO, + ], + max_fee: 10_000, + ..Default::default() + }); + + ExecutableTxWithHash::new(invoke.into()) +} + +pub fn envs() -> (BlockEnv, CfgEnv) { + let block = BlockEnv { + l1_gas_prices: GasPrices { eth: 1, strk: 1 }, + sequencer_address: felt!("0x1337").into(), + ..Default::default() + }; + let cfg = CfgEnv { + max_recursion_depth: 100, + validate_max_n_steps: 4_000_000, + invoke_tx_max_n_steps: 4_000_000, + vm_resource_fee_cost: vm_resource_fee_cost(), + fee_token_addresses: FeeTokenAddressses { + eth: DEFAULT_FEE_TOKEN_ADDRESS, + strk: DEFAULT_FEE_TOKEN_ADDRESS, + }, + ..Default::default() + }; + + (block, cfg) +} + +fn vm_resource_fee_cost() -> HashMap { + HashMap::from([ + (String::from("n_steps"), 1_f64), + (HASH_BUILTIN_NAME.to_string(), 1_f64), + (RANGE_CHECK_BUILTIN_NAME.to_string(), 1_f64), + (SIGNATURE_BUILTIN_NAME.to_string(), 1_f64), + (BITWISE_BUILTIN_NAME.to_string(), 1_f64), + (POSEIDON_BUILTIN_NAME.to_string(), 1_f64), + (OUTPUT_BUILTIN_NAME.to_string(), 1_f64), + (EC_OP_BUILTIN_NAME.to_string(), 1_f64), + (KECCAK_BUILTIN_NAME.to_string(), 1_f64), + (SEGMENT_ARENA_BUILTIN_NAME.to_string(), 1_f64), + ]) +} diff --git a/crates/katana/executor/src/abstraction/mod.rs b/crates/katana/executor/src/abstraction/mod.rs index 196f91c6a2..ae57d8ceb6 100644 --- a/crates/katana/executor/src/abstraction/mod.rs +++ b/crates/katana/executor/src/abstraction/mod.rs @@ -148,7 +148,13 @@ pub struct ResultAndStates { /// A wrapper around a boxed [StateProvider] for implementing the executor's own state reader /// traits. -pub(crate) struct StateProviderDb<'a>(pub(crate) Box); +pub struct StateProviderDb<'a>(pub(crate) Box); + +impl From> for StateProviderDb<'_> { + fn from(provider: Box) -> Self { + Self(provider) + } +} impl<'a> ContractClassProvider for StateProviderDb<'a> { fn class(&self, hash: ClassHash) -> ProviderResult> { diff --git a/crates/katana/executor/src/implementation/blockifier/mod.rs b/crates/katana/executor/src/implementation/blockifier/mod.rs index ed15ffe030..617624bf0b 100644 --- a/crates/katana/executor/src/implementation/blockifier/mod.rs +++ b/crates/katana/executor/src/implementation/blockifier/mod.rs @@ -1,6 +1,6 @@ mod error; mod state; -mod utils; +pub mod utils; use std::num::NonZeroU128; diff --git a/crates/katana/executor/src/implementation/blockifier/utils.rs b/crates/katana/executor/src/implementation/blockifier/utils.rs index e46af78da0..06e32d3866 100644 --- a/crates/katana/executor/src/implementation/blockifier/utils.rs +++ b/crates/katana/executor/src/implementation/blockifier/utils.rs @@ -62,7 +62,7 @@ use crate::abstraction::{EntryPointCall, SimulationFlag}; use crate::utils::build_receipt; use crate::{ExecutionError, ExecutionResult}; -pub(super) fn transact( +pub fn transact( state: &mut cached_state::CachedState, block_context: &BlockContext, simulation_flags: &SimulationFlag, @@ -357,7 +357,7 @@ fn to_executor_tx(tx: ExecutableTxWithHash) -> Transaction { } /// Create a block context from the chain environment values. -pub(crate) fn block_context_from_envs(block_env: &BlockEnv, cfg_env: &CfgEnv) -> BlockContext { +pub fn block_context_from_envs(block_env: &BlockEnv, cfg_env: &CfgEnv) -> BlockContext { let fee_token_addresses = FeeTokenAddresses { eth_fee_token_address: to_blk_address(cfg_env.fee_token_addresses.eth), strk_fee_token_address: to_blk_address(cfg_env.fee_token_addresses.strk), diff --git a/crates/katana/storage/db/Cargo.toml b/crates/katana/storage/db/Cargo.toml index 49e30dfb3b..d0ed3c1e2a 100644 --- a/crates/katana/storage/db/Cargo.toml +++ b/crates/katana/storage/db/Cargo.toml @@ -35,7 +35,7 @@ rev = "b34b0d3" [dev-dependencies] cairo-lang-starknet.workspace = true -criterion = "0.5.1" +criterion.workspace = true starknet.workspace = true tempfile.workspace = true