-
Notifications
You must be signed in to change notification settings - Fork 19
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
Gas report #104
Gas report #104
Changes from all commits
da402b3
3ae4c64
d01a9c2
a0f3704
d5aadc1
8f202f7
ac69fb3
bc98fff
904af82
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.17; | ||
|
||
import "./Vulcan.sol"; | ||
import "./Accounts.sol"; | ||
|
||
library gas { | ||
bytes32 constant GAS_MEASUREMENTS_MAGIC = keccak256("vulcan.gas.measurements.magic"); | ||
|
||
function record(string memory name) internal { | ||
bytes32 startSlot = keccak256(abi.encode(GAS_MEASUREMENTS_MAGIC, name, "start")); | ||
accounts.setStorage(address(vulcan.hevm), startSlot, bytes32(gasleft())); | ||
} | ||
|
||
function stopRecord(string memory name) internal returns (uint256) { | ||
uint256 endGas = gasleft(); | ||
|
||
bytes32 startSlot = keccak256(abi.encode(GAS_MEASUREMENTS_MAGIC, name, "start")); | ||
uint256 startGas = uint256(accounts.readStorage(address(vulcan.hevm), startSlot)); | ||
|
||
if (endGas > startGas) { | ||
revert("gas.stopRecord: Gas used can't have a negative value"); | ||
} | ||
|
||
bytes32 endSlot = keccak256(abi.encode(GAS_MEASUREMENTS_MAGIC, name, "end")); | ||
accounts.setStorage(address(vulcan.hevm), endSlot, bytes32(endGas)); | ||
|
||
return startGas - endGas; | ||
} | ||
|
||
function getRecord(string memory name) internal view returns (uint256, uint256) { | ||
bytes32 startSlot = keccak256(abi.encode(GAS_MEASUREMENTS_MAGIC, name, "start")); | ||
uint256 startGas = uint256(accounts.readStorage(address(vulcan.hevm), startSlot)); | ||
|
||
bytes32 endSlot = keccak256(abi.encode(GAS_MEASUREMENTS_MAGIC, name, "end")); | ||
uint256 endGas = uint256(accounts.readStorage(address(vulcan.hevm), endSlot)); | ||
|
||
return (startGas, endGas); | ||
} | ||
|
||
function used(string memory name) internal view returns (uint256) { | ||
(uint256 startGas, uint256 endGas) = getRecord(name); | ||
|
||
return startGas - endGas; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -94,6 +94,14 @@ contract ContextTest is Test { | |
|
||
target.value{value: uint256(1337)}(); | ||
} | ||
|
||
function testItCanReportGas() external { | ||
ctx.startGasReport("test"); | ||
for (uint256 i = 0; i < 5; i++) { | ||
new MockTarget(); | ||
} | ||
ctx.endGasReport(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. re: above, I'd be curious to see a similar measurement done without the context methods to see how they compare gas-wise (to determine if and how much gas is added by the gas reporting calls themselves), e.g. uint256 startGas = gasleft();
for (uint256 i = 0; i < 5; i++) {
new MockTarget();
}
println("gas used:", startGas - gasleft()); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sorry for the delay, we are in the middle of an audit right now, but will definitely look into this next week There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hey @holic . This is the gas comparison between the vulcan method vs using
And these are the measurements:
This is the contract we used to compare contract GasReport {
function vulcanReport() public {
ctx.startGasReport("test");
for (uint256 i = 0; i < 5; i++) {
new MockTarget();
}
ctx.endGasReport();
}
function nativeReport() public {
uint256 start = gasleft();
for (uint256 i = 0; i < 5; i++) {
new MockTarget();
}
println(string.concat("gas(test)", strings.toString(start - gasleft())));
}
} |
||
} | ||
} | ||
|
||
contract MockTarget { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.17; | ||
|
||
import {Test, expect, gas} from "../../src/test.sol"; | ||
|
||
contract GasTest is Test { | ||
function testItMeasures() public { | ||
string memory name = "test"; | ||
|
||
gas.record(name); | ||
keccak256(bytes(name)); | ||
uint256 measurementValue = gas.stopRecord(name); | ||
|
||
expect(measurementValue).toBeGreaterThan(0); | ||
expect(measurementValue).toEqual(gas.used(name)); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ooc do these operations affect
gasleft
calculation? I assumegasleft()
is computed first on this line, then put in storage, so I'm wondering if this storage operation would be the first gas consumed in this report?(I am totally fine with this for the purposes of #103 but just curious!)