diff --git a/Cargo.lock b/Cargo.lock index f58a1a4230..b6a4682238 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3243,12 +3243,12 @@ version = "0.10.1" dependencies = [ "alloy-rlp", "clap", + "criterion", "hash-db", "hashbrown", "hex", "indicatif", "k256", - "microbench", "plain_hasher", "revm", "serde", diff --git a/bins/revme/Cargo.toml b/bins/revme/Cargo.toml index b8f02f90d2..f672cda0bd 100644 --- a/bins/revme/Cargo.toml +++ b/bins/revme/Cargo.toml @@ -9,11 +9,11 @@ description = "Rust Ethereum Virtual Machine Executable" version = "0.10.1" [dependencies] +criterion = "0.5" hash-db = "0.15" hex = "0.4" hashbrown = "0.14" indicatif = "0.17" -microbench = "0.5" plain_hasher = "0.2" revm = { path = "../../crates/revm", version = "14.0.1", default-features = false, features = [ "ethersdb", diff --git a/bins/revme/README.md b/bins/revme/README.md index 61390f233e..fb005126df 100644 --- a/bins/revme/README.md +++ b/bins/revme/README.md @@ -2,7 +2,17 @@ `revme` is a binary crate to execute the evm in multiple ways. -Currently it is mainly used to run ethereum tests with the `statetest` subcommand. + +## Usage +You can run it directly from the command line with the following command: +```shell +cargo run -p revme +``` + +or build an optimized bin and re-use with: +```shell +cargo build -p revme --profile release +``` ## State Tests @@ -24,3 +34,22 @@ cargo run -p revme statetest tests/GeneralStateTests is ignored so it won't be checked into git.* [et]: https://github.com/ethereum/tests + +## Evm + +`evm` executes any given bytecode and returns the result, for example: + +```shell +cargo run -p revme evm 60FF60005261000F600020 +``` + +### Benchmarks + +Adding the `--bench` flag will run the benchmarks. It is important to run all the benchmarks in the release mode, as the results can be misleading in the debug mode. + +Example of running the benchmarks: +```shell +cargo run -p revme --profile release evm 60FF60005261000F600020 --bench +``` + +The detailed reports and comparisons can be found in the `target/criterion` directory. \ No newline at end of file diff --git a/bins/revme/src/cmd/evmrunner.rs b/bins/revme/src/cmd/evmrunner.rs index 381b153de4..24fbd26d3b 100644 --- a/bins/revme/src/cmd/evmrunner.rs +++ b/bins/revme/src/cmd/evmrunner.rs @@ -1,14 +1,19 @@ use clap::Parser; use revm::{ - db::BenchmarkDB, + db::{BenchmarkDB, EthereumBenchmarkWiring}, inspector_handle_register, inspectors::TracerEip3155, - primitives::{address, Address, Bytecode, BytecodeDecodeError, EthereumWiring, TxKind}, + interpreter::{ + analysis::to_analysed, opcode::make_instruction_table, Contract, DummyHost, Interpreter, + SharedMemory, + }, + primitives::{ + address, Address, Bytecode, BytecodeDecodeError, Bytes, EthereumWiring, LatestSpec, TxKind, + }, Database, Evm, }; use std::io::Error as IoError; use std::path::PathBuf; -use std::time::Duration; use std::{borrow::Cow, fs}; #[derive(Debug, thiserror::Error)] @@ -74,6 +79,11 @@ impl Cmd { .map_err(|_| Errors::InvalidInput)? .into(); + if self.bench { + run_benchmark(bytecode_str); + return Ok(()); + } + let mut db = BenchmarkDB::new_bytecode(Bytecode::new_raw_checked(bytecode.into())?); let nonce = db.basic(CALLER).unwrap().map_or(0, |account| account.nonce); @@ -89,23 +99,12 @@ impl Cmd { tx.data = input; tx.nonce = nonce; }) + .with_external_context(TracerEip3155::new(Box::new(std::io::stdout()))) .build(); - if self.bench { - // Microbenchmark - let bench_options = microbench::Options::default().time(Duration::from_secs(3)); - - microbench::bench(&bench_options, "Run bytecode", || { - let _ = evm.transact().unwrap(); - }); - - return Ok(()); - } - let out = if self.trace { let mut evm = evm .modify() - .with_external_context(TracerEip3155::new(Box::new(std::io::stdout()))) .append_handler_register(inspector_handle_register) .build(); @@ -123,3 +122,42 @@ impl Cmd { Ok(()) } } + +fn run_benchmark(bytecode_str: Cow) { + let evm = Evm::::builder() + .with_db(BenchmarkDB::new_bytecode(Bytecode::new())) + .modify_tx_env(|tx| { + tx.caller = "1000000000000000000000000000000000000000".parse().unwrap(); + tx.transact_to = + TxKind::Call("0000000000000000000000000000000000000000".parse().unwrap()); + }) + .with_external_context(()) + .build(); + + let host = DummyHost::new(*evm.context.evm.env.clone()); + let instruction_table = + make_instruction_table::>, LatestSpec>(); + let contract = Contract { + input: Bytes::from(hex::decode("").unwrap()), + bytecode: to_analysed(Bytecode::new_raw( + hex::decode(bytecode_str.to_string()).unwrap().into(), + )), + ..Default::default() + }; + + let mut criterion = criterion::Criterion::default() + .warm_up_time(std::time::Duration::from_millis(100)) + .measurement_time(std::time::Duration::from_secs(1)) + .without_plots(); + let mut criterion_group = criterion.benchmark_group("revme"); + criterion_group.bench_function("bytecode", |b| { + b.iter(|| { + Interpreter::new(contract.clone(), u64::MAX, false).run( + SharedMemory::new(), + &instruction_table, + &mut host.clone(), + ); + }) + }); + criterion_group.finish(); +}