Skip to content

Commit 7b275a2

Browse files
authored
Merge pull request #486 from ewasm/benchmarking
Benchmarking instrumentation
2 parents 727d3cb + 03f1c31 commit 7b275a2

File tree

8 files changed

+79
-6
lines changed

8 files changed

+79
-6
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ These are to be used via EVMC `set_option`:
6666

6767
- `engine=<engine>` will select the underlying WebAssembly engine, where the only accepted values currently are `binaryen`, `wabt`, and `wavm`
6868
- `metering=true` will enable metering of bytecode at deployment using the [Sentinel system contract] (set to `false` by default)
69+
- `benchmark=true` will produce execution timings and output it to both standard error output and `hera_benchmarks.log` file.
6970
- `evm1mode=<evm1mode>` will select how EVM1 bytecode is handled
7071
- `sys:<alias/address>=file.wasm` will override the code executing at the specified address with code loaded from a filepath at runtime. This option supports aliases for system contracts as well, such that `sys:sentinel=file.wasm` and `sys:evm2wasm=file.wasm` are both valid. **This option is intended for debugging purposes.**
7172

circle.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ defaults:
139139
SO=$([ $(uname) = Darwin ] && echo dylib || echo so)
140140
if [[ $PRELOAD_ASAN ]]; then export LD_PRELOAD=/usr/lib/clang/8/lib/linux/libclang_rt.asan-x86_64.so; fi
141141
testeth --version
142-
testeth -t GeneralStateTests/stEWASMTests -- --testpath tests --vm ~/build/src/libhera.$SO --singlenet Byzantium --evmc engine=binaryen
142+
testeth -t GeneralStateTests/stEWASMTests -- --testpath tests --vm ~/build/src/libhera.$SO --singlenet Byzantium --evmc engine=binaryen $TESTETH_OPTIONS
143143
144144
test-wabt: &test-wabt
145145
run:
@@ -148,7 +148,7 @@ defaults:
148148
SO=$([ $(uname) = Darwin ] && echo dylib || echo so)
149149
if [[ $PRELOAD_ASAN ]]; then export LD_PRELOAD=/usr/lib/clang/8/lib/linux/libclang_rt.asan-x86_64.so; fi
150150
testeth --version
151-
testeth -t GeneralStateTests/stEWASMTests -- --testpath tests --vm ~/build/src/libhera.$SO --singlenet Byzantium --evmc engine=wabt
151+
testeth -t GeneralStateTests/stEWASMTests -- --testpath tests --vm ~/build/src/libhera.$SO --singlenet Byzantium --evmc engine=wabt $TESTETH_OPTIONS
152152
153153
test-wavm: &test-wavm
154154
run:
@@ -158,7 +158,7 @@ defaults:
158158
SO=$([ $(uname) = Darwin ] && echo dylib || echo so)
159159
if [[ $PRELOAD_ASAN ]]; then export LD_PRELOAD=/usr/lib/clang/8/lib/linux/libclang_rt.asan-x86_64.so; fi
160160
testeth --version
161-
testeth -t GeneralStateTests/stEWASMTests -- --testpath tests --vm ~/build/src/libhera.$SO --singlenet Byzantium --evmc engine=wavm
161+
testeth -t GeneralStateTests/stEWASMTests -- --testpath tests --vm ~/build/src/libhera.$SO --singlenet Byzantium --evmc engine=wavm $TESTETH_OPTIONS
162162
163163
evmc-test: &evmc-test
164164
run:
@@ -249,6 +249,7 @@ jobs:
249249
- GENERATOR: Ninja
250250
- BUILD_PARALLEL_JOBS: 4
251251
- CMAKE_OPTIONS: -DCOVERAGE=ON -DBUILD_SHARED_LIBS=ON -DHERA_DEBUGGING=ON -DHERA_BINARYEN=ON
252+
- TESTETH_OPTIONS: --evmc benchmark=true
252253
docker:
253254
- image: ethereum/cpp-build-env:9
254255
steps:

src/binaryen.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,7 @@ ExecutionResult BinaryenEngine::execute(
479479
evmc_message const& msg,
480480
bool meterInterfaceGas
481481
) {
482+
instantiationStarted();
482483
wasm::Module module;
483484

484485
// Load module
@@ -497,6 +498,8 @@ ExecutionResult BinaryenEngine::execute(
497498
BinaryenEthereumInterface interface(context, state_code, msg, result, meterInterfaceGas);
498499
wasm::ModuleInstance instance(module, &interface);
499500

501+
executionStarted();
502+
500503
try {
501504
wasm::Name main = wasm::Name("main");
502505
wasm::LiteralList args;
@@ -506,6 +509,7 @@ ExecutionResult BinaryenEngine::execute(
506509
// It is only a clutch for POSIX style exit()
507510
}
508511

512+
executionFinished();
509513
return result;
510514
}
511515

src/eei.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
*/
1616

1717
#include <array>
18-
#include <vector>
19-
#include <sstream>
20-
#include <iostream>
18+
#include <fstream>
2119
#include <iomanip>
20+
#include <iostream>
21+
#include <sstream>
22+
#include <vector>
2223

2324
#include "debugging.h"
2425
#include "eei.h"
@@ -45,6 +46,26 @@ bool exceedsUint128(evmc_uint256be const& value) noexcept
4546
}
4647
} // namespace
4748

49+
bool WasmEngine::benchmarkingEnabled = false;
50+
51+
void WasmEngine::collectBenchmarkingData()
52+
{
53+
// Convert duration to string with microsecond units.
54+
constexpr auto to_us_str = [](clock::duration d) {
55+
return std::to_string(std::chrono::duration_cast<std::chrono::microseconds>(d).count());
56+
};
57+
58+
const auto now = clock::now();
59+
const auto instantiationDuration = executionStartTime - instantiationStartTime;
60+
const auto executionDuration = now - executionStartTime;
61+
62+
const auto log = "Time [us]: " + to_us_str(instantiationDuration + executionDuration) +
63+
" (instantiation: " + to_us_str(instantiationDuration) +
64+
", execution: " + to_us_str(executionDuration) + ")\n";
65+
std::cerr << log;
66+
std::ofstream{"hera_benchmarks.log", std::ios::out | std::ios::app} << log;
67+
}
68+
4869
#if HERA_DEBUGGING
4970
void EthereumInterface::debugPrintMem(bool useHex, uint32_t offset, uint32_t length)
5071
{

src/eei.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#pragma once
1818

19+
#include <chrono>
1920
#include <vector>
2021

2122
#include <evmc/evmc.h>
@@ -47,6 +48,35 @@ class WasmEngine {
4748
) = 0;
4849

4950
virtual void verifyContract(std::vector<uint8_t> const& code) = 0;
51+
52+
static void enableBenchmarking() noexcept { benchmarkingEnabled = true; }
53+
54+
protected:
55+
void instantiationStarted() noexcept
56+
{
57+
if (benchmarkingEnabled)
58+
instantiationStartTime = clock::now();
59+
}
60+
61+
void executionStarted() noexcept
62+
{
63+
if (benchmarkingEnabled)
64+
executionStartTime = clock::now();
65+
}
66+
67+
void executionFinished()
68+
{
69+
if (benchmarkingEnabled)
70+
collectBenchmarkingData();
71+
}
72+
73+
private:
74+
void collectBenchmarkingData();
75+
76+
using clock = std::chrono::high_resolution_clock;
77+
static bool benchmarkingEnabled;
78+
clock::time_point instantiationStartTime;
79+
clock::time_point executionStartTime;
5080
};
5181

5282
class EthereumInterface {

src/hera.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,14 @@ evmc_set_option_result hera_set_option(
413413
return EVMC_SET_OPTION_SUCCESS;
414414
}
415415

416+
if (strcmp(name, "benchmark") == 0) {
417+
if (strcmp(value, "true") == 0) {
418+
WasmEngine::enableBenchmarking();
419+
return EVMC_SET_OPTION_SUCCESS;
420+
}
421+
return EVMC_SET_OPTION_INVALID_VALUE;
422+
}
423+
416424
if (strcmp(name, "engine") == 0) {
417425
auto it = wasm_engine_map.find(value);
418426
if (it != wasm_engine_map.end()) {

src/wabt.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ ExecutionResult WabtEngine::execute(
7878
evmc_message const& msg,
7979
bool meterInterfaceGas
8080
) {
81+
instantiationStarted();
8182
HERA_DEBUG << "Executing with wabt...\n";
8283

8384
// Set up the wabt Environment, which includes the Wasm store
@@ -650,6 +651,8 @@ ExecutionResult WabtEngine::execute(
650651
// FIXME: really bad design
651652
interface.setWasmMemory(env.GetMemory(0));
652653

654+
executionStarted();
655+
653656
// Execute main
654657
try {
655658
interp::ExecResult wabtResult = executor.RunExport(mainFunction, interp::TypedValues{}); // second arg is empty since no args
@@ -660,6 +663,7 @@ ExecutionResult WabtEngine::execute(
660663
// It is only a clutch for POSIX style exit()
661664
}
662665

666+
executionFinished();
663667
return result;
664668
}
665669

src/wavm.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,11 @@ ExecutionResult WavmEngine::execute(
285285
bool meterInterfaceGas
286286
) {
287287
try {
288+
instantiationStarted();
288289
ExecutionResult result = internalExecute(context, code, state_code, msg, meterInterfaceGas);
289290
// And clean up mess left by this run.
290291
Runtime::collectGarbage();
292+
executionFinished();
291293
return result;
292294
} catch (exception const&) {
293295
// And clean up mess left by this run.
@@ -373,6 +375,8 @@ ExecutionResult WavmEngine::internalExecute(
373375
Runtime::GCPointer<Runtime::FunctionInstance> mainFunction = asFunctionNullable(Runtime::getInstanceExport(moduleInstance, "main"));
374376
ensureCondition(mainFunction, ContractValidationFailure, "\"main\" not found");
375377

378+
executionStarted();
379+
376380
// this is how WAVM's try/catch for exceptions
377381
Runtime::catchRuntimeExceptions(
378382
[&] {

0 commit comments

Comments
 (0)