22// Copyright 2019 The evmone Authors.
33// SPDX-License-Identifier: Apache-2.0
44
5- #include " ../statetest/statetest.hpp"
65#include " helpers.hpp"
76#include " synthetic_benchmarks.hpp"
87#include < benchmark/benchmark.h>
98#include < evmc/evmc.hpp>
10- #include < evmc/loader.h>
119#include < evmone/evmone.h>
10+ #include < gtest/gtest.h>
11+ #include < test/statetest/statetest.hpp>
1212#include < filesystem>
1313#include < fstream>
1414#include < iostream>
@@ -26,70 +26,66 @@ namespace
2626{
2727struct BenchmarkCase
2828{
29- struct Input
30- {
31- std::string name;
32- bytes input;
33- bytes expected_output;
34-
35- Input (std::string _name, bytes _input, bytes _expected_output = {}) noexcept
36- : name{std::move (_name)},
37- input{std::move (_input)},
38- expected_output{std::move (_expected_output)}
39- {}
40- };
41-
29+ StateTransitionTest state_test;
4230 std::string name;
43- bytes code;
44- std::vector<Input> inputs;
4531};
4632
47- // / Loads the benchmark case's inputs from the inputs file at the given path.
48- std::vector<BenchmarkCase::Input> load_inputs (const StateTransitionTest& state_test)
49- {
50- std::vector<BenchmarkCase::Input> inputs;
51- inputs.reserve (state_test.multi_tx .inputs .size ());
52- for (size_t i = 0 ; i < state_test.multi_tx .inputs .size (); ++i)
53- inputs.emplace_back (state_test.input_labels .at (i), state_test.multi_tx .inputs [i]);
54- return inputs;
55- }
56-
5733// / Loads a benchmark case from a file at `path` and all its inputs from the matching inputs file.
58- BenchmarkCase load_benchmark (const fs::path& path, const std::string& name_prefix)
34+ std::vector< BenchmarkCase> load_benchmark (const fs::path& path, const std::string& name_prefix)
5935{
6036 std::ifstream f{path};
61- auto state_test = std::move ( load_state_tests (f). at ( 0 )) ;
37+ std::vector<BenchmarkCase> result ;
6238
63- const auto name = name_prefix + path.stem ().string ();
64- const auto code = state_test.pre_state .get (state_test.multi_tx .to .value ()).code ;
65- const auto inputs = load_inputs (state_test);
39+ auto state_tests = load_state_tests (f);
40+ result.reserve (state_tests.size ());
41+ for (const auto & state_test : state_tests)
42+ {
43+ result.emplace_back (
44+ BenchmarkCase{state_test, name_prefix + path.stem ().string () + " /" + state_test.name });
45+ }
6646
67- return BenchmarkCase{name, code, inputs} ;
47+ return result ;
6848}
6949
7050// / Loads all benchmark cases from the given directory and all its subdirectories.
7151std::vector<BenchmarkCase> load_benchmarks_from_dir ( // NOLINT(misc-no-recursion)
7252 const fs::path& path, const std::string& name_prefix = {})
7353{
7454 std::vector<fs::path> subdirs;
75- std::vector<fs::path> code_files ;
55+ std::vector<fs::path> files ;
7656
77- for (auto & e : fs::directory_iterator{path})
57+ if (fs::is_directory (path))
58+ {
59+ for (auto & e : fs::directory_iterator{path})
60+ {
61+ if (e.is_directory ())
62+ subdirs.emplace_back (e);
63+ else if (e.path ().extension () == " .json" )
64+ files.emplace_back (e);
65+ }
66+ }
67+ else
7868 {
79- if (e.is_directory ())
80- subdirs.emplace_back (e);
81- else if (e.path ().extension () == " .json" )
82- code_files.emplace_back (e);
69+ if (path.extension () == " .json" )
70+ {
71+ if (fs::exists (path))
72+ files.emplace_back (path);
73+ else
74+ throw std::invalid_argument{" Path '" + path.string () + " ' does not exist." };
75+ }
8376 }
8477
8578 std::ranges::sort (subdirs);
86- std::ranges::sort (code_files );
79+ std::ranges::sort (files );
8780
8881 std::vector<BenchmarkCase> benchmark_cases;
8982
90- benchmark_cases.reserve (std::size (code_files));
91- for (const auto & f : code_files)
92- benchmark_cases.emplace_back (load_benchmark (f, name_prefix));
83+ for (const auto & f : files)
84+ {
85+ auto t = load_benchmark (f, name_prefix);
86+ benchmark_cases.insert (benchmark_cases.end (), std::make_move_iterator (t.begin ()),
87+ std::make_move_iterator (t.end ()));
88+ }
9389
9490 for (const auto & d : subdirs)
9591 {
@@ -105,66 +101,54 @@ void register_benchmarks(std::span<const BenchmarkCase> benchmark_cases)
105101{
106102 evmc::VM* advanced_vm = nullptr ;
107103 evmc::VM* baseline_vm = nullptr ;
108- evmc::VM* basel_cg_vm = nullptr ;
109104 if (const auto it = registered_vms.find (" advanced" ); it != registered_vms.end ())
110105 advanced_vm = &it->second ;
111106 if (const auto it = registered_vms.find (" baseline" ); it != registered_vms.end ())
112107 baseline_vm = &it->second ;
113- if ( const auto it = registered_vms. find ( " bnocgoto " ); it != registered_vms. end ())
114- basel_cg_vm = &it-> second ;
108+
109+ evmc::VM check_test_vm = evmc::VM{ evmc_create_evmone ()} ;
115110
116111 for (const auto & b : benchmark_cases)
117112 {
118- if (advanced_vm != nullptr )
119- {
120- RegisterBenchmark (" advanced/analyse/" + b.name , [&b](State& state) {
121- bench_analyse<advanced::AdvancedCodeAnalysis, advanced_analyse>(
122- state, default_revision, b.code );
123- })->Unit (kMicrosecond );
124- }
113+ run_state_test (b.state_test , check_test_vm, false );
125114
126- if (baseline_vm != nullptr )
127- {
128- RegisterBenchmark (" baseline/analyse/" + b.name , [&b](State& state) {
129- bench_analyse<baseline::CodeAnalysis, baseline_analyse>(
130- state, default_revision, b.code );
131- })->Unit (kMicrosecond );
132- }
115+ if (::testing::Test::HasFailure ())
116+ throw std::invalid_argument{" State test you want to bench failed." };
133117
134- for (const auto & input : b.inputs )
118+ const auto code = b.state_test .pre_state .get_account_code (b.state_test .multi_tx .to .value ());
119+ for (const auto & [rev, cases, block_info] : b.state_test .cases )
135120 {
136- const auto case_name = b.name + (!input.name .empty () ? ' /' + input.name : " " );
137-
138121 if (advanced_vm != nullptr )
139122 {
140- const auto name = " advanced/execute /" + case_name;
141- RegisterBenchmark (name, [&vm = *advanced_vm, &b, &input](State& state) {
142- bench_advanced_execute (state, vm, b. code , input. input , input. expected_output );
123+ RegisterBenchmark ( " advanced/analyse /" + b. name , [code, &rev](State& state) {
124+ bench_analyse<advanced::AdvancedCodeAnalysis, advanced_analyse>(
125+ state, rev, code );
143126 })->Unit (kMicrosecond );
144127 }
145128
146129 if (baseline_vm != nullptr )
147130 {
148- const auto name = " baseline/execute/" + case_name;
149- RegisterBenchmark (name, [&vm = *baseline_vm, &b, &input](State& state) {
150- bench_baseline_execute (state, vm, b.code , input.input , input.expected_output );
151- })->Unit (kMicrosecond );
152- }
153-
154- if (basel_cg_vm != nullptr )
155- {
156- const auto name = " bnocgoto/execute/" + case_name;
157- RegisterBenchmark (name, [&vm = *basel_cg_vm, &b, &input](State& state) {
158- bench_baseline_execute (state, vm, b.code , input.input , input.expected_output );
131+ RegisterBenchmark (" baseline/analyse/" + b.name , [code, &rev](State& state) {
132+ bench_analyse<baseline::CodeAnalysis, baseline_analyse>(state, rev, code);
159133 })->Unit (kMicrosecond );
160134 }
161135
162- for (auto & [vm_name, vm] : registered_vms )
136+ for (size_t case_index = 0 ; case_index != cases. size (); ++case_index )
163137 {
164- const auto name = std::string{vm_name} + " /total/" + case_name;
165- RegisterBenchmark (name, [&vm, &b, &input](State& state) {
166- bench_evmc_execute (state, vm, b.code , input.input , input.expected_output );
167- })->Unit (kMicrosecond );
138+ const auto & expected = cases[case_index];
139+ const auto tx = b.state_test .multi_tx .get (expected.indexes );
140+
141+ for (auto & [vm_name, vm] : registered_vms)
142+ {
143+ const auto name = std::string{vm_name} + " /execute/" + b.name + ' /' +
144+ std::to_string (case_index);
145+
146+ // `tx` is temporary.
147+ RegisterBenchmark (name, [tx, &vm, &b, &block_info, &rev](State& state) {
148+ bench_transition (state, vm, tx, b.state_test .pre_state , block_info,
149+ b.state_test .block_hashes , rev);
150+ })->Unit (kMicrosecond );
151+ }
168152 }
169153 }
170154 }
@@ -181,79 +165,32 @@ constexpr auto cli_parsing_error = -3;
181165// /
182166// / 1: evmone-bench
183167// / Uses evmone VMs, only synthetic benchmarks are available.
184- // / 2: evmone-bench benchmarks_dir
185- // / Uses evmone VMs, loads all benchmarks from benchmarks_dir.
186- // / 3: evmone-bench evmc_config benchmarks_dir
187- // / The same as (2) but loads additional custom EVMC VM.
188- // / 4: evmone-bench code_hex_file input_hex expected_output_hex.
189- // / Uses evmone VMs, registers custom benchmark with the code from the given file,
190- // / and the given input. The benchmark will compare the output with the provided
191- // / expected one.
192- std::tuple<int , std::vector<BenchmarkCase>> parseargs (int argc, char ** argv)
168+ // / 2: evmone-bench benchmarks_path
169+ // / Uses evmone VMs, loads all benchmarks from benchmarks_path. If benchmarks_path is a `json`
170+ // / file, single test is run.
171+ std::variant<int , std::vector<BenchmarkCase>> parseargs (int argc, char ** argv)
193172{
194- // Arguments' placeholders:
195- std::string evmc_config;
196- std::string benchmarks_dir;
197- std::string code_hex_file;
198- std::string input_hex;
199- std::string expected_output_hex;
173+ // Argument's placeholder:
174+ std::string benchmarks_path;
200175
201176 switch (argc)
202177 {
203178 case 1 :
204179 // Run with built-in synthetic benchmarks only.
205180 break ;
206181 case 2 :
207- benchmarks_dir = argv[1 ];
208- break ;
209- case 3 :
210- evmc_config = argv[1 ];
211- benchmarks_dir = argv[2 ];
212- break ;
213- case 4 :
214- code_hex_file = argv[1 ];
215- input_hex = argv[2 ];
216- expected_output_hex = argv[3 ];
182+ benchmarks_path = argv[1 ];
217183 break ;
218184 default :
219- std::cerr << " Too many arguments\n " ;
220- return {cli_parsing_error, {}};
221- }
222-
223- if (!evmc_config.empty ())
224- {
225- auto ec = evmc_loader_error_code{};
226- registered_vms[" external" ] = evmc::VM{evmc_load_and_configure (evmc_config.c_str (), &ec)};
227-
228- if (ec != EVMC_LOADER_SUCCESS)
229- {
230- if (const auto error = evmc_last_error_msg ())
231- std::cerr << " EVMC loading error: " << error << " \n " ;
232- else
233- std::cerr << " EVMC loading error " << ec << " \n " ;
234- return {static_cast <int >(ec), {}};
235- }
236-
237- std::cout << " External VM: " << evmc_config << " \n " ;
238- }
239-
240- if (!benchmarks_dir.empty ())
241- {
242- return {0 , load_benchmarks_from_dir (benchmarks_dir)};
185+ return cli_parsing_error;
243186 }
244187
245- if (!code_hex_file .empty ())
188+ if (!benchmarks_path .empty ())
246189 {
247- std::ifstream file{code_hex_file};
248- return {0 , {BenchmarkCase{code_hex_file,
249- from_spaced_hex (
250- std::istreambuf_iterator<char >{file}, std::istreambuf_iterator<char >{})
251- .value (),
252- {BenchmarkCase::Input{" " , from_hex (input_hex).value (),
253- from_hex (expected_output_hex).value ()}}}}};
190+ return load_benchmarks_from_dir (benchmarks_path);
254191 }
255192
256- return { 0 , {} };
193+ return std::vector<BenchmarkCase>{ };
257194}
258195} // namespace
259196} // namespace evmone::test
@@ -264,20 +201,28 @@ int main(int argc, char** argv)
264201 try
265202 {
266203 Initialize (&argc, argv); // Consumes --benchmark_ options.
267- const auto [ec, benchmark_cases] = parseargs (argc, argv);
268- if (ec == cli_parsing_error && ReportUnrecognizedArguments (argc, argv))
269- return ec;
270-
271- if (ec != 0 )
272- return ec;
273-
274- registered_vms[" advanced" ] = evmc::VM{evmc_create_evmone (), {{" advanced" , " " }}};
275- registered_vms[" baseline" ] = evmc::VM{evmc_create_evmone ()};
276- registered_vms[" bnocgoto" ] = evmc::VM{evmc_create_evmone (), {{" cgoto" , " no" }}};
277- register_benchmarks (benchmark_cases);
278- register_synthetic_benchmarks ();
279- RunSpecifiedBenchmarks ();
280- return 0 ;
204+ const auto ec_or_benchmark_cases = parseargs (argc, argv);
205+ if (std::holds_alternative<int >(ec_or_benchmark_cases))
206+ {
207+ const auto ec = std::get<int >(ec_or_benchmark_cases);
208+ if (ec == cli_parsing_error && ReportUnrecognizedArguments (argc, argv))
209+ return ec;
210+
211+ if (ec != 0 )
212+ return ec;
213+ }
214+ else
215+ {
216+ const auto benchmark_cases =
217+ std::get<std::vector<BenchmarkCase>>(ec_or_benchmark_cases);
218+ registered_vms[" advanced" ] = evmc::VM{evmc_create_evmone (), {{" advanced" , " " }}};
219+ registered_vms[" baseline" ] = evmc::VM{evmc_create_evmone ()};
220+ registered_vms[" bnocgoto" ] = evmc::VM{evmc_create_evmone (), {{" cgoto" , " no" }}};
221+ register_benchmarks (benchmark_cases);
222+ register_synthetic_benchmarks ();
223+ RunSpecifiedBenchmarks ();
224+ return 0 ;
225+ }
281226 }
282227 catch (const std::exception& ex)
283228 {
0 commit comments