3

sload loads a word from storage. https://ethereum.github.io/yellowpaper/paper.pdf

if we have a loop over uint256, both preloading into memory and loading within the loop should use the same number sload calls. I assume when loading into memory, there is a loop over sload calls. so why is preloading a bit faster?

modifying https://moralis.io/gas-optimizations-in-solidity-top-tips/ :

// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;

contract Gas_Test{
    uint[] public arrayFunds;
    uint public totalFunds;

    constructor() {
        arrayFunds = [1,2,3,4,5,6,7,8,9,10,11,12,13,2,3,4,5,6,7,8,9,10,11,12,13];
    }

    function optionB2() external {
        uint _totalFunds;
        uint al = arrayFunds.length;
        for (uint i =0; i < al; i++){
            _totalFunds = _totalFunds + arrayFunds[i];
        }
        totalFunds = _totalFunds;
    }

    function optionC() external {
        uint _totalFunds;
        uint[] memory _arrayFunds = arrayFunds;
        for (uint i =0; i < _arrayFunds.length; i++){
            _totalFunds = _totalFunds + _arrayFunds[i];
        }
        totalFunds = _totalFunds;
    }

}

B2 is 105997 gas C is 104084 gas

if i use an array that is almost half the size arrayFunds = [1,2,3,4,5,6,7,8,9,10,11,12,13], the gas difference almost halves: B2 is 69275 C is 68396

the cost of sload is 2100. the difference is smaller than a sload. However, b2 makes 4 sload calls, and C makes only 2. I'd think memory would have to do a bunch of calls to load the whole array.

1 Answer 1

1

Some potential issues at play:


When accessing an array a bounds check will be included because the contract has to throw if the index is out of bounds. With a variable size array this means first running an SLOAD to load the array length before the second SLOAD to actually load the data.

An array assignment doesn't need to do any bounds checks.


Fixed size storage arrays store their elements 'in-place'. For example:

uint256 private a; // slot 0
uint256 private b; // slot 1
uint256[5] private arr; // slot 2 to 6
uint256 private c; // slot 7

// arr[3] will compile to SLOAD[2+3]

Storage arrays with variable size obviously cannot store their data 'in-place' because the amount can vary. Instead they store their data at the hash of their slot:

uint256 private a; // slot 0
uint256 private b; // slot 1
uint256[] private arr; // length at slot 2, data starts at slot KECCAK256[2]
uint256 private c; // slot 3

// arr.length will compile to SLOAD[2]
// arr[3] will compile to SLOAD[KECCAK256[2]+3]

I don't think the keccak256 of a constant is being optimized away, so every time you access a variable-size storage array a keccak256 opcode is executed. (plus some memory ops to set the input for the hashing function)


Memory and storage access costs vary somewhat because of memory expansion cost (which is non-linear) and storage 'warm-up' cost.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.