2

[Q] When I push() a new struct into an array vs. when change all the values inside the same struct that is stored in the array, they both consume different usedGas. Regarding this difference, which path should I take, in order to use gas efficiently:

node[] array_1;
function foo(){
    array_1.push(<some_value>);
}

or

uint32 index=0;
node[<array_size>] array_2;
function foo() {
   array_2[index++].value = <some_value>;
}

[Observation] When I push() a new struct into my array, it uses much less gas than when I change all the values inside the same struct that is stored in the array.

Why do they differ on gas usage since both do the same operations? I assume, I am doing something wrong.

https://github.com/ethereum/wiki/wiki/Solidity-Features:

.push() for Dynamic Storage Arrays PT Dynamically-sized storage arrays have a member function push, such that var l = arr.push(el); is equivalent to arr[arr.length++] = el; var l = arr.length;.

In this following example: you could see the different gas usage.

my_contract.transact().push_me( 30, 40, 16 ); consumes 63146 gas
my_contract.transact().change( 30, 40, 16 );  consumes 79468 gas

-

contract Example {
  struct node { 
    uint32 blk_start;
    uint32 blk_end;
    uint16 core;
    uint32 next; 
   }
   node[]    array_1;
   node[10]  array_2;
   uint32 index = 0;

   function push_me( uint32 blk_start_, uint32 blk_end_, uint16 core_ ) {
     array_1.push(node( { blk_start: blk_start_, blk_end: blk_end_, core: core_, next: 10 }));
   }

   function change( uint32 blk_start_, uint32 blk_end_, uint16 core_ ) {
     array_2[index].core       = core_;
     array_2[index].blk_start = blk_start_;
     array_2[index].blk_end   = blk_end_;
     array_2[index].next      = 10;
     index++;
   }
}

Thank you for your valuable time and help.

1
+50

I'm not certain, but I'm suspecting it's because in change(), you actually access that one node several times in a row. Each time, it's going to have to look it up again, and it's probably not helping the optimizer, either.

I tried the following code with the above contract:

function change2(uint32 blk_start_, uint32 blk_end_, uint16 core_) {
   array_2[index] = node(blk_start_, blk_end_, core_, 10);
   index++;       
}

Here are the results from browser-solidity:

change: 56541 gas.

change2: 41285 gas.

pushme: 56316 gas.

So I'd say that was the issue.

EDIT: The above numbers are incorrect!

It appears that the first transaction to either pushme or change costs extra gas, because it increments the index (and therefore adds to storage.) Here are more accurate numbers:

change: 41563 gas.

change2: 41285 gas.

pushme: 41316 gas.

As you can see, there's almost no difference in the end, even if change2 is slightly better. This is possibly due to the optimizer working behind the scenes. I suggest pushme, if for no other reason than you can have unlimited nodes if needed, and it's less code.

  • As I understand accessing to memory is expensive. So in your solution you assign the node into the memory in one call instead of multiple calls as I did. But why now change2 consume less gas than pushme, shouldn't they be equal? – alper Feb 18 '17 at 1:13
  • I discovered there was a flaw in my answer, which explains this. The reason it consumes slightly less gas in the end is probably due to whatever assembly-level optimization differences exist between .push() and lookups. – Matthew Schmidt Feb 18 '17 at 1:44
  • Did not get the second part (accurate numbers), are those the ones without incrementing the index? No matter what shouldn't incrementation take place? @Matthew Schmidt – alper Feb 18 '17 at 11:24
  • 1
    The first time index is incremented, it turns a zero into a one, which is considered increasing the amount of storage a contract uses. This is, IIRC, 4x the gas price of writing to storage that is already non-zero. – Matthew Schmidt Feb 18 '17 at 16:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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