Skip to content

Commit c6094bb

Browse files
committed
externalTests: Benchmark reports
1 parent a7852cb commit c6094bb

17 files changed

+232
-27
lines changed

.circleci/config.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,15 @@ jobs:
12051205
name: External <<parameters.project>> tests (native)
12061206
command: |
12071207
test/externalTests/<<parameters.project>>.sh native /tmp/workspace/solc/solc
1208+
- store_artifacts:
1209+
path: reports/externalTests/
1210+
# persist_to_workspace fails if the directory does not exist and the test script will create
1211+
# it only if it actually has benchmark results.
1212+
- run: mkdir -p reports/externalTests/
1213+
- persist_to_workspace:
1214+
root: .
1215+
paths:
1216+
- reports/externalTests/
12081217
- gitter_notify_failure_unless_pr
12091218

12101219
b_win: &b_win

test/externalTests.sh

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,26 @@
2828

2929
set -e
3030

31-
REPO_ROOT="$(dirname "$0")"
32-
3331
source scripts/common.sh
3432
source test/externalTests/common.sh
3533

34+
REPO_ROOT=$(realpath "$(dirname "$0")/..")
35+
3636
verify_input "$@"
3737

3838
printTask "Running external tests..."
3939

40-
"$REPO_ROOT/externalTests/zeppelin.sh" "$@"
41-
"$REPO_ROOT/externalTests/gnosis.sh" "$@"
42-
"$REPO_ROOT/externalTests/gnosis-v2.sh" "$@"
43-
"$REPO_ROOT/externalTests/colony.sh" "$@"
44-
"$REPO_ROOT/externalTests/ens.sh" "$@"
45-
"$REPO_ROOT/externalTests/trident.sh" "$@"
46-
"$REPO_ROOT/externalTests/euler.sh" "$@"
47-
"$REPO_ROOT/externalTests/yield-liquidator.sh" "$@"
48-
"$REPO_ROOT/externalTests/bleeps.sh" "$@"
49-
"$REPO_ROOT/externalTests/pool-together.sh" "$@"
50-
"$REPO_ROOT/externalTests/perpetual-pools.sh" "$@"
51-
"$REPO_ROOT/externalTests/uniswap.sh" "$@"
52-
"$REPO_ROOT/externalTests/prb-math.sh" "$@"
53-
"$REPO_ROOT/externalTests/elementfi.sh" "$@"
40+
"{$REPO_ROOT}/test/externalTests/zeppelin.sh" "$@"
41+
"{$REPO_ROOT}/test/externalTests/gnosis.sh" "$@"
42+
"{$REPO_ROOT}/test/externalTests/gnosis-v2.sh" "$@"
43+
"{$REPO_ROOT}/test/externalTests/colony.sh" "$@"
44+
"{$REPO_ROOT}/test/externalTests/ens.sh" "$@"
45+
"{$REPO_ROOT}/test/externalTests/trident.sh" "$@"
46+
"{$REPO_ROOT}/test/externalTests/euler.sh" "$@"
47+
"{$REPO_ROOT}/test/externalTests/yield-liquidator.sh" "$@"
48+
"{$REPO_ROOT}/test/externalTests/bleeps.sh" "$@"
49+
"{$REPO_ROOT}/test/externalTests/pool-together.sh" "$@"
50+
"{$REPO_ROOT}/test/externalTests/perpetual-pools.sh" "$@"
51+
"{$REPO_ROOT}/test/externalTests/uniswap.sh" "$@"
52+
"{$REPO_ROOT}/test/externalTests/prb-math.sh" "$@"
53+
"{$REPO_ROOT}/test/externalTests/elementfi.sh" "$@"

test/externalTests/bleeps.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,16 @@ set -e
2424
source scripts/common.sh
2525
source test/externalTests/common.sh
2626

27+
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
28+
2729
verify_input "$@"
2830
BINARY_TYPE="$1"
2931
BINARY_PATH="$2"
3032
SELECTED_PRESETS="$3"
3133

3234
function compile_fn { npm run compile; }
33-
function test_fn { npm run test; }
35+
# NOTE: `npm run test` runs `mocha` which seems to disable the gas reporter.
36+
function test_fn { HARDHAT_DEPLOY_FIXTURE=true npx --no hardhat --no-compile test; }
3437

3538
function bleeps_test
3639
{
@@ -87,6 +90,7 @@ function bleeps_test
8790

8891
for preset in $SELECTED_PRESETS; do
8992
hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var"
93+
store_benchmark_report hardhat bleeps "$repo" "$preset"
9094
done
9195

9296
popd

test/externalTests/colony.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ set -e
2424
source scripts/common.sh
2525
source test/externalTests/common.sh
2626

27+
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
28+
2729
verify_input "$@"
2830
BINARY_TYPE="$1"
2931
BINARY_PATH="$2"
@@ -73,6 +75,7 @@ function colony_test
7375

7476
for preset in $SELECTED_PRESETS; do
7577
truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc/dist" "$preset" "${compile_only_presets[*]}" compile_fn test_fn
78+
store_benchmark_report truffle colony "$repo" "$preset"
7679
done
7780
}
7881

test/externalTests/common.sh

Lines changed: 157 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#------------------------------------------------------------------------------
2121
set -e
2222

23-
# Requires "${REPO_ROOT}/scripts/common.sh" to be included before.
23+
# Requires $REPO_ROOT to be defined and "${REPO_ROOT}/scripts/common.sh" to be included before.
2424

2525
CURRENT_EVM_VERSION=london
2626

@@ -207,9 +207,19 @@ function force_truffle_compiler_settings
207207
echo "Compiler version (full): ${SOLCVERSION}"
208208
echo "-------------------------------------"
209209

210-
# Forcing the settings should always work by just overwriting the solc object. Forcing them by using a
211-
# dedicated settings objects should only be the fallback.
212-
echo "module.exports['compilers'] = $(truffle_compiler_settings "$solc_path" "$preset" "$evm_version");" >> "$config_file"
210+
local compiler_settings gas_reporter_settings
211+
compiler_settings=$(truffle_compiler_settings "$solc_path" "$preset" "$evm_version")
212+
gas_reporter_settings=$(eth_gas_reporter_settings "$preset")
213+
214+
{
215+
echo "require('eth-gas-reporter');"
216+
echo "module.exports['mocha'] = {"
217+
echo " reporter: 'eth-gas-reporter',"
218+
echo " reporterOptions: ${gas_reporter_settings}"
219+
echo "};"
220+
221+
echo "module.exports['compilers'] = ${compiler_settings};"
222+
} >> "$config_file"
213223
}
214224

215225
function name_hardhat_default_export
@@ -278,16 +288,21 @@ function force_hardhat_compiler_settings
278288
echo "Compiler version (full): ${SOLCVERSION}"
279289
echo "-------------------------------------"
280290

281-
local settings
282-
settings=$(hardhat_compiler_settings "$SOLCVERSION_SHORT" "$preset" "$evm_version")
291+
local compiler_settings gas_reporter_settings
292+
compiler_settings=$(hardhat_compiler_settings "$SOLCVERSION_SHORT" "$preset" "$evm_version")
293+
gas_reporter_settings=$(eth_gas_reporter_settings "$preset")
283294
if [[ $config_file == *\.js ]]; then
284295
[[ $config_var_name == "" ]] || assertFail
285-
echo "module.exports['solidity'] = ${settings}" >> "$config_file"
296+
echo "require('hardhat-gas-reporter');"
297+
echo "module.exports.gasReporter = ${gas_reporter_settings};"
298+
echo "module.exports.solidity = ${compiler_settings};"
286299
else
287300
[[ $config_file == *\.ts ]] || assertFail
288301
[[ $config_var_name != "" ]] || assertFail
289-
echo "${config_var_name}.solidity = {compilers: [${settings}]}" >> "$config_file"
290-
fi
302+
echo 'import "hardhat-gas-reporter";'
303+
echo "${config_var_name}.gasReporter = ${gas_reporter_settings};"
304+
echo "${config_var_name}.solidity = {compilers: [${compiler_settings}]};"
305+
fi >> "$config_file"
291306
}
292307

293308
function truffle_verify_compiler_version
@@ -368,6 +383,21 @@ function replace_global_solc
368383
export PATH="$PWD:$PATH"
369384
}
370385

386+
function eth_gas_reporter_settings
387+
{
388+
local preset="$1"
389+
390+
echo "{"
391+
echo " enabled: true,"
392+
echo " gasPrice: 1," # Gas price does not matter to us at all. Set to whatever to avoid API call.
393+
echo " noColors: true,"
394+
echo " showTimeSpent: false," # We're not interested in test timing
395+
echo " onlyCalledMethods: true," # Exclude entries with no gas for shorter report
396+
echo " showMethodSig: true," # Should make diffs more stable if there are overloaded functions
397+
echo " outputFile: \"$(gas_report_path "$preset")\""
398+
echo "}"
399+
}
400+
371401
function truffle_compiler_settings
372402
{
373403
local solc_path="$1"
@@ -495,3 +525,121 @@ function external_test
495525
rm -rf "$DIR"
496526
echo "Done."
497527
}
528+
529+
function gas_report_path
530+
{
531+
local preset="$1"
532+
533+
echo "${DIR}/gas-report-${preset}.rst"
534+
}
535+
536+
function gas_report_to_json
537+
{
538+
cat - | "${REPO_ROOT}/scripts/externalTests/parse_eth_gas_report.py" | jq '{gas: .}'
539+
}
540+
541+
function detect_hardhat_artifact_dir
542+
{
543+
if [[ -e build/ && -e artifacts/ ]]; then
544+
fail "Cannot determine Hardhat artifact location. Both build/ and artifacts/ exist"
545+
elif [[ -e build/ ]]; then
546+
echo -n build/artifacts
547+
elif [[ -e artifacts/ ]]; then
548+
echo -n artifacts
549+
else
550+
fail "Hardhat build artifacts not found."
551+
fi
552+
}
553+
554+
function bytecode_size_json_from_truffle_artifacts
555+
{
556+
# NOTE: The output of this function is a series of concatenated JSON dicts rather than a list.
557+
558+
for artifact in build/contracts/*.json; do
559+
if [[ $(jq '. | has("unlinked_binary")' "$artifact") == false ]]; then
560+
# Each artifact represents compilation output for a single contract. Some top-level keys contain
561+
# bits of Standard JSON output while others are generated by Truffle. Process it into a dict
562+
# of the form `{"<file>": {"<contract>": <size>}}`.
563+
# NOTE: The `bytecode` field starts with 0x, which is why we subtract 1 from size.
564+
jq '{
565+
(.ast.absolutePath): {
566+
(.contractName): (.bytecode | length / 2 - 1)
567+
}
568+
}' "$artifact"
569+
fi
570+
done
571+
}
572+
573+
function bytecode_size_json_from_hardhat_artifacts
574+
{
575+
# NOTE: The output of this function is a series of concatenated JSON dicts rather than a list.
576+
577+
for artifact in "$(detect_hardhat_artifact_dir)"/build-info/*.json; do
578+
# Each artifact contains Standard JSON output under the `output` key.
579+
# Process it into a dict of the form `{"<file>": {"<contract>": <size>}}`,
580+
# Note that one Hardhat artifact often represents multiple input files.
581+
jq '.output.contracts | to_entries[] | {
582+
"\(.key)": .value | to_entries[] | {
583+
"\(.key)": (.value.evm.bytecode.object | length / 2)
584+
}
585+
}' "$artifact"
586+
done
587+
}
588+
589+
function combine_artifact_json
590+
{
591+
# Combine all dicts into a list with `jq --slurp` and then use `reduce` to merge them into one
592+
# big dict with keys of the form `"<file>:<contract>"`. Then run jq again to filter out items
593+
# with zero size and put the rest under under a top-level `bytecode_size` key. Also add another
594+
# key with total bytecode size.
595+
# NOTE: The extra inner `bytecode_size` key is there only to make diffs more readable.
596+
cat - |
597+
jq --slurp 'reduce (.[] | to_entries[]) as {$key, $value} ({}; . + {
598+
($key + ":" + ($value | to_entries[].key)): {
599+
bytecode_size: $value | to_entries[].value
600+
}
601+
})' |
602+
jq --indent 4 --sort-keys '{
603+
bytecode_size: [. | to_entries[] | select(.value.bytecode_size > 0)] | from_entries,
604+
total_bytecode_size: (reduce (. | to_entries[]) as {$key, $value} (0; . + $value.bytecode_size))
605+
}'
606+
}
607+
608+
function project_info_json
609+
{
610+
local project_url="$1"
611+
612+
echo "{"
613+
echo " \"project\": {"
614+
# NOTE: Given that we clone with `--depth 1`, we'll only get useful output out of `git describe`
615+
# if we directly check out a tag. Still better than nothing.
616+
echo " \"version\": \"$(git describe --always)\","
617+
echo " \"commit\": \"$(git rev-parse HEAD)\","
618+
echo " \"url\": \"${project_url}\""
619+
echo " }"
620+
echo "}"
621+
}
622+
623+
function store_benchmark_report
624+
{
625+
local framework="$1"
626+
local project_name="$2"
627+
local project_url="$3"
628+
local preset="$4"
629+
630+
[[ $framework == truffle || $framework == hardhat ]] || assertFail
631+
[[ " ${AVAILABLE_PRESETS[*]} " == *" $preset "* ]] || assertFail
632+
633+
local report_dir="${REPO_ROOT}/reports/externalTests"
634+
local output_file="${report_dir}/benchmark-${project_name}-${preset}.json"
635+
mkdir -p "$report_dir"
636+
637+
{
638+
if [[ -e $(gas_report_path "$preset") ]]; then
639+
gas_report_to_json < "$(gas_report_path "$preset")"
640+
fi
641+
642+
"bytecode_size_json_from_${framework}_artifacts" | combine_artifact_json
643+
project_info_json "$project_url"
644+
} | jq --slurp "{\"${project_name}\": {\"${preset}\": add}}" --indent 4 --sort-keys > "$output_file"
645+
}

test/externalTests/elementfi.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ set -e
2424
source scripts/common.sh
2525
source test/externalTests/common.sh
2626

27+
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
28+
2729
verify_input "$@"
2830
BINARY_TYPE="$1"
2931
BINARY_PATH="$2"
@@ -96,6 +98,7 @@ function elementfi_test
9698

9799
for preset in $SELECTED_PRESETS; do
98100
hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var"
101+
store_benchmark_report hardhat elementfi "$repo" "$preset"
99102
done
100103
}
101104

test/externalTests/ens.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ set -e
2424
source scripts/common.sh
2525
source test/externalTests/common.sh
2626

27+
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
28+
2729
verify_input "$@"
2830
BINARY_TYPE="$1"
2931
BINARY_PATH="$2"
@@ -68,6 +70,7 @@ function ens_test
6870

6971
for preset in $SELECTED_PRESETS; do
7072
hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn
73+
store_benchmark_report hardhat ens "$repo" "$preset"
7174
done
7275
}
7376

test/externalTests/euler.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ set -e
2424
source scripts/common.sh
2525
source test/externalTests/common.sh
2626

27+
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
28+
2729
verify_input "$@"
2830
BINARY_TYPE="$1"
2931
BINARY_PATH="$2"
@@ -68,6 +70,7 @@ function euler_test
6870

6971
for preset in $SELECTED_PRESETS; do
7072
hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn
73+
store_benchmark_report hardhat euler "$repo" "$preset"
7174
done
7275
}
7376

test/externalTests/gnosis-v2.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ set -e
2424
source scripts/common.sh
2525
source test/externalTests/common.sh
2626

27+
REPO_ROOT=$(realpath "$(dirname "$0")/../..")
28+
2729
verify_input "$@"
2830
BINARY_TYPE="$1"
2931
BINARY_PATH="$2"
@@ -65,12 +67,14 @@ function gnosis_safe_test
6567
neutralize_package_json_hooks
6668
force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc/dist" "$(first_word "$SELECTED_PRESETS")"
6769
npm install --package-lock
70+
npm install eth-gas-reporter
6871

6972
replace_version_pragmas
7073
[[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc/dist"
7174

7275
for preset in $SELECTED_PRESETS; do
7376
truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc/dist" "$preset" "${compile_only_presets[*]}" compile_fn test_fn
77+
store_benchmark_report truffle gnosis2 "$repo" "$preset"
7478
done
7579
}
7680

0 commit comments

Comments
 (0)