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

Improve EVM execution performance #434

Open
crystalin opened this issue Aug 1, 2021 · 4 comments
Open

Improve EVM execution performance #434

crystalin opened this issue Aug 1, 2021 · 4 comments
Labels
enhancement New feature or request

Comments

@crystalin
Copy link
Collaborator

crystalin commented Aug 1, 2021

I created this ticket to open the discussion on possible improvements over the EVM execution.

I've been digging a bit to improve the performances of the EVM.
There isn't much space left for optimization but here are my reports.

Running a basic contract looping (32000 times) over an addition:

contract Loop {
  function big_loop(uint256 target) pure public returns (uint256) {
    uint256 number = 0;
    for (uint i = 0; i < target; i++) {
      number += 1;
    }
    return number;
  }
}

I used callgrind (valgrind) to retrieve as much info I could (the recording starts right before the contract call):
callgrind.out.txt (to read with qcachegrind)
perf.data.txt (to rename perf.data and run with perf report --no-inline)

Here are the screenshot of the interesting parts:
image
(This is the map of the execution cycles for the execution of this contract)

This is the same data as a list (filtered to evm functions only):
image

Some important parts:

  • tracing (including memory(), position(), return_value(), gasometer tracing): ~50% (This build was used using the "tracing" feature)
  • run loop: 25% (without including children calls), generating I think the 3.7M calls to memory, position, inspect, return_value,...
  • return_value: 19% (being called 3.7M times), this is mostly due to 256bits number conversation.
  • gasometer: ~5% (snapshot called 3M times)

I've dug into the return_value to see if there was anything special. 1/3rd of it is used by U256::partial_cmp and U256::From, the rest is inherent to the function:
image
(There is nothing really surprising to me when looking at it, but I suspect that being called 3.7M times makes any ops heavy)

@crystalin crystalin added the enhancement New feature or request label Aug 1, 2021
@crystalin crystalin changed the title Improve runtime execution Improve EVM execution performance Aug 1, 2021
@crystalin
Copy link
Collaborator Author

Moving U256::from(usize::max_value()) out of the return_value (and put it into a instance variable for exemple) should already save 5-10%

@sorpaas
Copy link
Member

sorpaas commented Aug 1, 2021

Moving U256::from(usize::max_value()) out of the return_value (and put it into a instance variable for exemple) should already save 5-10%

That's really weird cause U256::from for usize is extremely trivial.

@sorpaas
Copy link
Member

sorpaas commented Aug 1, 2021

You can test out this branch: rust-ethereum/evm#47
Please report the cycle diff of that vs master, see if it actually improves things.

@crystalin
Copy link
Collaborator Author

crystalin commented Aug 2, 2021

@sorpaas I confirm it removed the U256::from cost from the execution, it looks like 10% overall (roughly, not too precise) saved:
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants