7

Mind the following code:

// This is expensive obj.a = uint32(obja); obj.b = uint32(objb); obj.c = uint32(objc); objs[objName] = obj; // This is much cheaper objs[objName].a = uint32(obja); objs[objName].b = uint32(objb); objs[objName].c = uint32(objc); 

Where obj is a memory struct of type

struct Obj { uint32 a; uint32 b; uint32 c; } 

And obja, objb and objc are uint32s. Why the first version is more expensive if, in theory, it could be done in a single SSTORE call, whereas the latter would require 3?

7
  • Just to be sure, you are declaring Obj memory obj, correct? i.e. your're actually using a memory struct, not a storage one as a temporary variable. Commented Dec 1, 2016 at 15:02
  • @TjadenHess yep that is correct, I had Obj memory obj = objs[objName] earlier on. Commented Dec 1, 2016 at 15:03
  • So, it looks like if you use a single global Obj variable, then it is actually cheaper to use the memory route, but when you use an array of them, then it becomes more expensive. Similarly with mappings. Commented Dec 1, 2016 at 15:07
  • Also, note that setting a storage variable from a zero value to nonzero is more expensive than updating a nonzero variable. So the order in which you do this test matters. I'd recommend initializing the struct of interest to have all nonzero values before looking at gas costs Commented Dec 1, 2016 at 15:11
  • Looking at the debugger, the memory one seems to use 14 SSTOREs, for some reason. As does the straight storage one. Commented Dec 1, 2016 at 15:16

2 Answers 2

1

I think you've run into the trap that initializing a storage slot (changing from 0 to something else) for the first time costs 20000 gas and rewriting an already initialized storage slot later costs only 5000 gas. If you repeat your test a second time for the same objName, you'll notice the difference.

Setting via memory obj will be slightly (~100-200 gas) cheaper.

The most efficient way would be:

function set(bytes32 objName, uint obja, uint objb, uint objc) public { Obj storage obj = objs[objName]; obj.a = uint32(obja); obj.b = uint32(objb); obj.c = uint32(objc); } 

in theory, it could be done in a single SSTORE call, whereas the latter would require 3?

A SSTORE can only set one 32-byte storage slot at once. If you have 3 x uint32, you'll have 3 SSTORE calls.

0

You haven't provided anything to back up your measurements, so here is a setup which proves the opposite:

MyContract.sol:

pragma solidity 0.4.24; contract MyContract { struct Obj { uint32 a; uint32 b; uint32 c; } mapping(string => Obj) internal objs; function set1(string objName, uint256 obja, uint256 objb, uint256 objc) external { Obj memory obj; obj.a = uint32(obja); obj.b = uint32(objb); obj.c = uint32(objc); objs[objName] = obj; } function set2(string objName, uint256 obja, uint256 objb, uint256 objc) external { objs[objName].a = uint32(obja); objs[objName].b = uint32(objb); objs[objName].c = uint32(objc); } } 

MyContractTest.js:

contract("MyContractTest", function(accounts) { it("performance measurement:", async function() { let myContract = await artifacts.require("MyContract.sol").new(); for (let a = 0; a < 10; a++) { for (let b = 0; b < 10; b++) { for (let c = 0; c < 10; c++) { let set1gas = await myContract.set1.estimateGas("test", a, b, c); let set2gas = await myContract.set2.estimateGas("test", a, b, c); console.log(`set1gas = ${set1gas}, set2gas = ${set2gas}`); } } } }); }); 

You can run this via truffle test MyContractTest.js, and observe that the first method is in fact around 10K gas units cheaper than the second method.

As mentioned in the first answer, you may have experienced the same issue as when conducting performance (speed) measurement without taking into consideration the impact of the current state of the cache memory (which affects the caching heuristics applied by the underlying platform during runtime).

In a sense, measuring gas consumption on the block-chain is similar to measuring time performance on "standard" machines.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.