Last active
June 7, 2021 20:34
-
-
Save hrkrshnn/39ef4a42c661c17b2908400d914784c8 to your computer and use it in GitHub Desktop.
Needs parsec and tabulate. Inside `scripts`, run `python3 gas_stats.py`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""A script to collect gas statistics and print it. | |
Dependencies: Parsec (https://pypi.org/project/parsec/) and Tabulate | |
https://pypi.org/project/tabulate/ | |
pip install parsec tabulate | |
Run from root project dir. | |
python3 scripts/gas_stats.py | |
The output table may look messy, but it can be directly posted as a github | |
comment, and will look fine. | |
Note that the changes to semantic tests have to be committed. | |
Assumes that there is a remote named ``origin`` pointing to the Solidity github | |
repository. The changes are compared against origin/develop. | |
""" | |
from parsec import * | |
from enum import Enum | |
from pathlib import Path | |
from tabulate import tabulate | |
import subprocess | |
class Kind(Enum): | |
IrOptimized = 1 | |
Legacy = 2 | |
LegacyOptimized = 3 | |
class Diff(Enum): | |
Minus = 1 | |
Plus = 2 | |
minus = string("-").result(Diff.Minus) | |
plus = string("+").result(Diff.Plus) | |
space = string(" ") | |
comment = string("//") | |
colon = string(":") | |
gas_ir_optimized = string("gas irOptimized").result(Kind.IrOptimized) | |
gas_legacy_optimized = string("gas legacyOptimized").result(Kind.LegacyOptimized) | |
gas_legacy = string("gas legacy").result(Kind.Legacy) | |
def number() -> int: | |
"""Parse number.""" | |
return regex(r"([0-9]*)").parsecmap(int) | |
@generate | |
def diff_string() -> (Kind, Diff, int): | |
"""Usage: diff_string.parse(string)""" | |
diff_kind = yield (minus | plus) | |
yield comment | |
yield space | |
codegen_kind = yield (gas_ir_optimized ^ gas_legacy_optimized ^ gas_legacy) | |
yield colon | |
yield space | |
val = yield number() | |
return (diff_kind, codegen_kind, val) | |
def collect_statistics(lines) -> (int, int, int, int, int, int): | |
"""Returns | |
(old_ir_optimized, old_legacy_optimized, old_legacy, new_ir_optimized, | |
new_legacy_optimized, new_legacy) | |
""" | |
if not lines: | |
raise Exception("Empty list") | |
def try_parse(line): | |
try: | |
return diff_string.parse(line) | |
except ParseError: | |
pass | |
out = [parsed for line in lines if (parsed := try_parse(line)) is not None] | |
diff_kinds = [Diff.Minus, Diff.Plus] | |
codegen_kinds = [Kind.IrOptimized, Kind.LegacyOptimized, Kind.Legacy] | |
return tuple([ | |
sum([ | |
val | |
for (diff_kind, codegen_kind, val) in out | |
if diff_kind == _diff_kind and codegen_kind == _codegen_kind | |
]) | |
for _diff_kind in diff_kinds | |
for _codegen_kind in codegen_kinds | |
]) | |
def semantictest_statistics(): | |
def try_parse_git_diff(fname): | |
try: | |
diff_output = subprocess.check_output( | |
"git diff --unified=0 origin/develop HEAD " + fname, | |
shell=True, | |
universal_newlines=True | |
).splitlines() | |
if diff_output: | |
return collect_statistics(diff_output) | |
except: | |
pass | |
def stat(a, b): | |
return ((b - a) / a) * 100 if a else 0 | |
table = [] | |
for path in Path("test/libsolidity/semanticTests").rglob("*.sol"): | |
fname = path.as_posix() | |
parsed = try_parse_git_diff(fname) | |
if parsed is None: | |
continue | |
print(parsed) | |
ir_optimized = stat(parsed[0], parsed[3]) | |
legacy_optimized = stat(parsed[1], parsed[4]) | |
legacy = stat(parsed[2], parsed[5]) | |
fname = fname.split('/', 4)[-1] | |
table += [map(str, [fname, ir_optimized, legacy_optimized, legacy])] | |
if table: | |
print("<details><summary>Click for a table of gas differences</summary>\n") | |
table_header = ["File name", "IR-optimized (%)", "Legacy-Optimized (%)", "Legacy (%)"] | |
print(tabulate(table, headers=table_header, tablefmt="github")) | |
print("</details>") | |
else: | |
print("No differences found.") | |
if __name__ == "__main__": | |
semantictest_statistics() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment