diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 262b3a57c2..b6888b7fbb 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -195,7 +195,7 @@ pub mod test { bytecode_table: [Column; 5], block_table: [Column; 3], copy_table: CopyCircuit, - evm_circuit: EvmCircuit, + pub evm_circuit: EvmCircuit, } impl TestCircuitConfig { @@ -515,3 +515,82 @@ pub mod test { run_test_circuit(block, FixedTableTag::iter().collect()) } } + +#[cfg(test)] +mod evm_circuit_stats { + use super::test::*; + use super::*; + use crate::evm_circuit::step::ExecutionState; + use eth_types::{bytecode, evm_types::OpcodeId, geth_types::GethData}; + use halo2_proofs::pairing::bn256::Fr; + use halo2_proofs::plonk::ConstraintSystem; + use mock::test_ctx::{helpers::*, TestContext}; + use strum::IntoEnumIterator; + + /// This function prints to stdout a table with all the implemented states + /// and their responsible opcodes with the following stats: + /// - height: number of rows used by the execution state + /// - gas: gas value used for the opcode execution + /// - height/gas: ratio between circuit cost and gas cost + /// + /// Run with: + /// `cargo test -p zkevm-circuits --release get_evm_states_stats -- + /// --nocapture --ignored` + #[ignore] + #[test] + pub fn get_evm_states_stats() { + let mut meta = ConstraintSystem::::default(); + let circuit = TestCircuit::configure(&mut meta); + + let mut implemented_states = Vec::new(); + for state in ExecutionState::iter() { + let height = circuit.evm_circuit.execution.get_step_height_option(state); + if let Some(h) = height { + implemented_states.push((state, h)); + } + } + + let mut stats = Vec::new(); + for (state, h) in implemented_states { + for opcode in state.responsible_opcodes() { + let mut code = bytecode! { + PUSH2(0x8000) + PUSH2(0x00) + PUSH2(0x10) + PUSH2(0x20) + PUSH2(0x30) + PUSH2(0x40) + PUSH2(0x50) + }; + code.write_op(opcode); + code.write_op(OpcodeId::STOP); + let block: GethData = TestContext::<2, 1>::new( + None, + account_0_code_account_1_no_code(code), + tx_from_1_to_0, + |block, _tx| block.number(0xcafeu64), + ) + .unwrap() + .into(); + let gas_cost = block.geth_traces[0].struct_logs[7].gas_cost.0; + stats.push((state, opcode, h, gas_cost)); + } + } + + println!( + "| {: <14} | {: <14} | {: <2} | {: >6} | {: <5} |", + "state", "opcode", "h", "g", "h/g" + ); + println!("| --- | --- | ---| --- | --- |"); + for (state, opcode, height, gas_cost) in stats { + println!( + "| {: <14} | {: <14} | {: >2} | {: >6} | {: >1.3} |", + format!("{:?}", state), + format!("{:?}", opcode), + height, + gas_cost, + height as f64 / gas_cost as f64 + ); + } + } +} diff --git a/zkevm-circuits/src/evm_circuit/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs index 35bf947ad0..9804a145ba 100644 --- a/zkevm-circuits/src/evm_circuit/execution.rs +++ b/zkevm-circuits/src/evm_circuit/execution.rs @@ -452,10 +452,12 @@ impl ExecutionConfig { config } + pub fn get_step_height_option(&self, execution_state: ExecutionState) -> Option { + self.height_map.get(&execution_state).copied() + } + pub fn get_step_height(&self, execution_state: ExecutionState) -> usize { - *self - .height_map - .get(&execution_state) + self.get_step_height_option(execution_state) .unwrap_or_else(|| panic!("Execution state unknown: {:?}", execution_state)) } diff --git a/zkevm-circuits/src/evm_circuit/util.rs b/zkevm-circuits/src/evm_circuit/util.rs index 2ab26bdebb..fc40c1d4c7 100644 --- a/zkevm-circuits/src/evm_circuit/util.rs +++ b/zkevm-circuits/src/evm_circuit/util.rs @@ -278,6 +278,7 @@ impl CellManager { .unwrap() } + /// Returns a map of CellType -> (width, height, num_cells) pub(crate) fn get_stats(&self) -> BTreeMap { let mut data = BTreeMap::new(); for column in self.columns.iter() {