Skip to content

Commit 9cfd1f1

Browse files
iovoidjrchatruclferrigno
authored andcommitted
perf(levm): reuse stack pool (#5179)
**Motivation** Currently, allocation of a new stack object is taking ~8% of execution. **Description** We make a single allocation of every layer. --------- Co-authored-by: Javier Chatruc <jrchatruc@gmail.com> Co-authored-by: Leandro Ferrigno <leanrafa@gmail.com>
1 parent 0e4a5b3 commit 9cfd1f1

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## Perf
44

5+
### 2025-11-07
6+
- Reuse stack pool in LEVM [#5179](https://github.com/lambdaclass/ethrex/pull/5179)
7+
58
### 2025-11-03
69

710
- Avoid unnecessary hash validations [#5167](https://github.com/lambdaclass/ethrex/pull/5167)

crates/vm/backends/levm/mod.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ use ethrex_common::{
1818
},
1919
};
2020
use ethrex_levm::EVMConfig;
21-
use ethrex_levm::constants::{SYS_CALL_GAS_LIMIT, TX_BASE_COST};
21+
use ethrex_levm::call_frame::Stack;
22+
use ethrex_levm::constants::{STACK_LIMIT, SYS_CALL_GAS_LIMIT, TX_BASE_COST};
2223
use ethrex_levm::db::gen_db::GeneralizedDatabase;
2324
use ethrex_levm::errors::{InternalError, TxValidationError};
2425
use ethrex_levm::tracing::LevmCallTracer;
@@ -99,6 +100,8 @@ impl LEVM {
99100
) -> Result<BlockExecutionResult, EvmError> {
100101
Self::prepare_block(block, db, vm_type)?;
101102

103+
let mut shared_stack_pool = Vec::with_capacity(STACK_LIMIT);
104+
102105
let mut receipts = Vec::new();
103106
let mut cumulative_gas_used = 0;
104107

@@ -113,7 +116,14 @@ impl LEVM {
113116
)));
114117
}
115118

116-
let report = Self::execute_tx(tx, tx_sender, &block.header, db, vm_type)?;
119+
let report = Self::execute_tx_in_block(
120+
tx,
121+
tx_sender,
122+
&block.header,
123+
db,
124+
vm_type,
125+
&mut shared_stack_pool,
126+
)?;
117127
LEVM::send_state_transitions_tx(&merkleizer, db, queue_length)?;
118128

119129
cumulative_gas_used += report.gas_used;
@@ -218,7 +228,7 @@ impl LEVM {
218228
pub fn execute_tx(
219229
// The transaction to execute.
220230
tx: &Transaction,
221-
// The transactions recovered address
231+
// The transaction's recovered address
222232
tx_sender: Address,
223233
// The block header for the current block.
224234
block_header: &BlockHeader,
@@ -231,6 +241,27 @@ impl LEVM {
231241
vm.execute().map_err(VMError::into)
232242
}
233243

244+
// Like execute_tx but allows reusing the stack pool
245+
fn execute_tx_in_block(
246+
// The transaction to execute.
247+
tx: &Transaction,
248+
// The transaction's recovered address
249+
tx_sender: Address,
250+
// The block header for the current block.
251+
block_header: &BlockHeader,
252+
db: &mut GeneralizedDatabase,
253+
vm_type: VMType,
254+
stack_pool: &mut Vec<Stack>,
255+
) -> Result<ExecutionReport, EvmError> {
256+
let env = Self::setup_env(tx, tx_sender, block_header, db, vm_type)?;
257+
let mut vm = VM::new(env, db, tx, LevmCallTracer::disabled(), vm_type)?;
258+
259+
std::mem::swap(&mut vm.stack_pool, stack_pool);
260+
let result = vm.execute().map_err(VMError::into);
261+
std::mem::swap(&mut vm.stack_pool, stack_pool);
262+
result
263+
}
264+
234265
pub fn undo_last_tx(db: &mut GeneralizedDatabase) -> Result<(), EvmError> {
235266
db.undo_last_transaction()?;
236267
Ok(())

0 commit comments

Comments
 (0)