Skip to content

Commit 9588b72

Browse files
committed
tests: Load benchmarks as proper state test. Support file path. Remove support for raw bytecode testting.
1 parent 3c90f27 commit 9588b72

2 files changed

Lines changed: 127 additions & 178 deletions

File tree

test/bench/bench.cpp

Lines changed: 99 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
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
{
2727
struct 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.
7151
std::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

Comments
 (0)