Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce per tx execution allocations #7990

Merged
merged 12 commits into from
Jan 2, 2025
Merged

Conversation

benaadams
Copy link
Member

@benaadams benaadams commented Jan 2, 2025

Changes

Saves 8.6MB of allocations per min; reduces worse case from smart contracts that do huge amounts of calls

  • Reduce allocations by pooling StackAccessTracker collections
  • Reduce allocations by pooling EvmState
  • EvmState, pass large struct via in
  • Change StackAccessTracker and EvmState to file level namespaces
  • Rearranged parameters and assignment order to match layout order

EvmState is a super chonky class and currently allocated for every tx and every internal call (and this is after shrinking StackAccessTracker)

Type layout for 'EvmState'
Size: 368 bytes. Paddings: 10 bytes (%2 of empty space)
|==================================================================================|
| Object Header (8 bytes)                                                          |
|----------------------------------------------------------------------------------|
| Method Table Ptr (8 bytes)                                                       |
|==================================================================================|
|   0-7: Byte[] DataStack (8 bytes)                                                |
|----------------------------------------------------------------------------------|
|  8-15: Int32[] ReturnStack (8 bytes)                                             |
|----------------------------------------------------------------------------------|
| 16-23: Int64 <GasAvailable>k__BackingField (8 bytes)                             |
|----------------------------------------------------------------------------------|
| 24-31: Int64 <OutputDestination>k__BackingField (8 bytes)                        |
|----------------------------------------------------------------------------------|
| 32-39: Int64 <OutputLength>k__BackingField (8 bytes)                             |
|----------------------------------------------------------------------------------|
| 40-47: Int64 <Refund>k__BackingField (8 bytes)                                   |
|----------------------------------------------------------------------------------|
| 48-51: Int32 DataStackHead (4 bytes)                                             |
|----------------------------------------------------------------------------------|
| 52-55: Int32 ReturnStackHead (4 bytes)                                           |
|----------------------------------------------------------------------------------|
| 56-59: ExecutionType <ExecutionType>k__BackingField (4 bytes)                    |
| |================================|                                               |
| |   0-3: Int32 value__ (4 bytes) |                                               |
| |================================|                                               |
|----------------------------------------------------------------------------------|
| 60-63: Int32 <ProgramCounter>k__BackingField (4 bytes)                           |
|----------------------------------------------------------------------------------|
|    64: Boolean <IsTopLevel>k__BackingField (1 byte)                              |
|----------------------------------------------------------------------------------|
|    65: Boolean _canRestore (1 byte)                                              |
|----------------------------------------------------------------------------------|
|    66: Boolean <IsStatic>k__BackingField (1 byte)                                |
|----------------------------------------------------------------------------------|
|    67: Boolean <IsContinuation>k__BackingField (1 byte)                          |
|----------------------------------------------------------------------------------|
|    68: Boolean <IsCreateOnPreExistingAccount>k__BackingField (1 byte)            |
|----------------------------------------------------------------------------------|
|    69: Boolean _isDisposed (1 byte)                                              |
|----------------------------------------------------------------------------------|
| 70-71: padding (2 bytes)                                                         |
|----------------------------------------------------------------------------------|
| 72-103: EvmPooledMemory _memory (32 bytes)                                       |
| |=================================================|                              |
| |   0-7: Byte[] _memory (8 bytes)                 |                              |
| |-------------------------------------------------|                              |
| |  8-15: UInt64 _lastZeroedSize (8 bytes)         |                              |
| |-------------------------------------------------|                              |
| | 16-23: UInt64 <Length>k__BackingField (8 bytes) |                              |
| |-------------------------------------------------|                              |
| | 24-31: UInt64 <Size>k__BackingField (8 bytes)   |                              |
| |=================================================|                              |
|----------------------------------------------------------------------------------|
| 104-115: Snapshot <Snapshot>k__BackingField (12 bytes)                           |
| |=======================================================================|        |
| |   0-3: Int32 <StateSnapshot>k__BackingField (4 bytes)                 |        |
| |-----------------------------------------------------------------------|        |
| |  4-11: Storage <StorageSnapshot>k__BackingField (8 bytes)             |        |
| | |===================================================================| |        |
| | |   0-3: Int32 <PersistentStorageSnapshot>k__BackingField (4 bytes) | |        |
| | |-------------------------------------------------------------------| |        |
| | |   4-7: Int32 <TransientStorageSnapshot>k__BackingField (4 bytes)  | |        |
| | |===================================================================| |        |
| |=======================================================================|        |
|----------------------------------------------------------------------------------|
| 116-119: padding (4 bytes)                                                       |
|----------------------------------------------------------------------------------|
| 120-343: ExecutionEnvironment _env (224 bytes)                                   |
| |==============================================================================| |
| |   0-7: CodeInfo CodeInfo (8 bytes)                                           | |
| |------------------------------------------------------------------------------| |
| |  8-15: Address ExecutingAccount (8 bytes)                                    | |
| |------------------------------------------------------------------------------| |
| | 16-23: Address Caller (8 bytes)                                              | |
| |------------------------------------------------------------------------------| |
| | 24-31: Address CodeSource (8 bytes)                                          | |
| |------------------------------------------------------------------------------| |
| | 32-35: Int32 CallDepth (4 bytes)                                             | |
| |------------------------------------------------------------------------------| |
| | 36-39: padding (4 bytes)                                                     | |
| |------------------------------------------------------------------------------| |
| | 40-55: ReadOnlyMemory`1 InputData (16 bytes)                                 | |
| | |=================================|                                          | |
| | |   0-7: Object _object (8 bytes) |                                          | |
| | |---------------------------------|                                          | |
| | |  8-11: Int32 _index (4 bytes)   |                                          | |
| | |---------------------------------|                                          | |
| | | 12-15: Int32 _length (4 bytes)  |                                          | |
| | |=================================|                                          | |
| |------------------------------------------------------------------------------| |
| | 56-159: TxExecutionContext TxExecutionContext (104 bytes)                    | |
| | |==========================================================================| | |
| | |   0-7: Address <Origin>k__BackingField (8 bytes)                         | | |
| | |--------------------------------------------------------------------------| | |
| | |  8-15: Byte[][] <BlobVersionedHashes>k__BackingField (8 bytes)           | | |
| | |--------------------------------------------------------------------------| | |
| | | 16-23: ICodeInfoRepository <CodeInfoRepository>k__BackingField (8 bytes) | | |
| | |--------------------------------------------------------------------------| | |
| | | 24-71: BlockExecutionContext BlockExecutionContext (48 bytes)            | | |
| | | |===========================================================|            | | |
| | | |   0-7: BlockHeader <Header>k__BackingField (8 bytes)      |            | | |
| | | |-----------------------------------------------------------|            | | |
| | | |  8-47: Nullable`1 <BlobBaseFee>k__BackingField (40 bytes) |            | | |
| | | |===========================================================|            | | |
| | |--------------------------------------------------------------------------| | |
| | | 72-103: UInt256 <GasPrice>k__BackingField (32 bytes)                     | | |
| | | |============================|                                           | | |
| | | |   0-7: UInt64 u0 (8 bytes) |                                           | | |
| | | |----------------------------|                                           | | |
| | | |  8-15: UInt64 u1 (8 bytes) |                                           | | |
| | | |----------------------------|                                           | | |
| | | | 16-23: UInt64 u2 (8 bytes) |                                           | | |
| | | |----------------------------|                                           | | |
| | | | 24-31: UInt64 u3 (8 bytes) |                                           | | |
| | | |============================|                                           | | |
| | |==========================================================================| | |
| |------------------------------------------------------------------------------| |
| | 160-191: UInt256 TransferValue (32 bytes)                                    | |
| | |============================|                                               | |
| | |   0-7: UInt64 u0 (8 bytes) |                                               | |
| | |----------------------------|                                               | |
| | |  8-15: UInt64 u1 (8 bytes) |                                               | |
| | |----------------------------|                                               | |
| | | 16-23: UInt64 u2 (8 bytes) |                                               | |
| | |----------------------------|                                               | |
| | | 24-31: UInt64 u3 (8 bytes) |                                               | |
| | |============================|                                               | |
| |------------------------------------------------------------------------------| |
| | 192-223: UInt256 Value (32 bytes)                                            | |
| | |============================|                                               | |
| | |   0-7: UInt64 u0 (8 bytes) |                                               | |
| | |----------------------------|                                               | |
| | |  8-15: UInt64 u1 (8 bytes) |                                               | |
| | |----------------------------|                                               | |
| | | 16-23: UInt64 u2 (8 bytes) |                                               | |
| | |----------------------------|                                               | |
| | | 24-31: UInt64 u3 (8 bytes) |                                               | |
| | |============================|                                               | |
| |==============================================================================| |
|----------------------------------------------------------------------------------|
| 344-367: StackAccessTracker _accessTracker (24 bytes)                            |
| |===============================================|                                |
| |   0-7: TrackingState _trackingState (8 bytes) |                                |
| |-----------------------------------------------|                                |
| |  8-11: Int32 _addressesSnapshots (4 bytes)    |                                |
| |-----------------------------------------------|                                |
| | 12-15: Int32 _storageKeysSnapshots (4 bytes)  |                                |
| |-----------------------------------------------|                                |
| | 16-19: Int32 _destroyListSnapshots (4 bytes)  |                                |
| |-----------------------------------------------|                                |
| | 20-23: Int32 _logsSnapshots (4 bytes)         |                                |
| |===============================================|                                |
|==================================================================================|

Types of changes

What types of changes does your code introduce?

  • Optimization

Testing

Requires testing

  • No

@benaadams benaadams marked this pull request as ready for review January 2, 2025 07:31
@benaadams benaadams changed the title Reduce tx execution allocations Reduce per tx execution allocations Jan 2, 2025
Copy link
Member

@LukaszRozmej LukaszRozmej left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should return RentFrame too

src/Nethermind/Nethermind.Evm/EvmState.cs Outdated Show resolved Hide resolved
src/Nethermind/Nethermind.Evm/StackAccessTracker.cs Outdated Show resolved Hide resolved
src/Nethermind/Nethermind.Evm/StackAccessTracker.cs Outdated Show resolved Hide resolved
@benaadams
Copy link
Member Author

We should return RentFrame too

Are returned when the Frames are unwound:

For exception

currentState.Dispose();
currentState = _stateStack.Pop();
currentState.IsContinuation = true;

For success:

using (EvmState previousState = currentState)
{
currentState = _stateStack.Pop();
currentState.IsContinuation = true;
currentState.GasAvailable += previousState.GasAvailable;

@benaadams benaadams requested a review from LukaszRozmej January 2, 2025 10:43
@benaadams benaadams merged commit 14d832c into master Jan 2, 2025
79 checks passed
@benaadams benaadams deleted the reduce-execution-memory-use branch January 2, 2025 11:35
rjnrohit pushed a commit that referenced this pull request Jan 11, 2025
Co-authored-by: lukasz.rozmej <lukasz.rozmej@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants