Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Profiler #9541

Merged
merged 5 commits into from
Oct 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ struct controller_impl {
cfg.reversible_cache_size, false, cfg.db_map_mode ),
blog( cfg.blog ),
fork_db( cfg.state_dir ),
wasmif( cfg.wasm_runtime, cfg.eosvmoc_tierup, db, cfg.state_dir, cfg.eosvmoc_config ),
wasmif( cfg.wasm_runtime, cfg.eosvmoc_tierup, db, cfg.state_dir, cfg.eosvmoc_config, !cfg.profile_accounts.empty() ),
resource_limits( db, [&s]() { return s.get_deep_mind_logger(); }),
authorization( s, db ),
protocol_features( std::move(pfs), [&s]() { return s.get_deep_mind_logger(); } ),
Expand Down Expand Up @@ -3190,6 +3190,10 @@ bool controller::contracts_console()const {
return my->conf.contracts_console;
}

bool controller::is_profiling(account_name account) const {
return my->conf.profile_accounts.find(account) != my->conf.profile_accounts.end();
}

chain_id_type controller::get_chain_id()const {
return my->chain_id;
}
Expand Down
4 changes: 4 additions & 0 deletions libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ namespace eosio { namespace chain {
flat_set<account_name> resource_greylist;
flat_set<account_name> trusted_producers;
uint32_t greylist_limit = chain::config::maximum_elastic_resource_multiplier;

flat_set<account_name> profile_accounts;
};

enum class block_status {
Expand Down Expand Up @@ -288,6 +290,8 @@ namespace eosio { namespace chain {

bool contracts_console()const;

bool is_profiling(account_name name) const;

chain_id_type get_chain_id()const;

db_read_mode get_read_mode()const;
Expand Down
2 changes: 1 addition & 1 deletion libraries/chain/include/eosio/chain/wasm_interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ namespace eosio { namespace chain {
}
}

wasm_interface(vm_type vm, bool eosvmoc_tierup, const chainbase::database& d, const boost::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config);
wasm_interface(vm_type vm, bool eosvmoc_tierup, const chainbase::database& d, const boost::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, bool profile);
~wasm_interface();

//call before dtor to skip what can be minutes of dtor overhead with some runtimes; can cause leaks
Expand Down
10 changes: 7 additions & 3 deletions libraries/chain/include/eosio/chain/wasm_interface_private.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,17 @@ namespace eosio { namespace chain {
};
#endif

wasm_interface_impl(wasm_interface::vm_type vm, bool eosvmoc_tierup, const chainbase::database& d, const boost::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config) : db(d), wasm_runtime_time(vm) {
wasm_interface_impl(wasm_interface::vm_type vm, bool eosvmoc_tierup, const chainbase::database& d, const boost::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, bool profile) : db(d), wasm_runtime_time(vm) {
#ifdef EOSIO_EOS_VM_RUNTIME_ENABLED
if(vm == wasm_interface::vm_type::eos_vm)
runtime_interface = std::make_unique<webassembly::eos_vm_runtime::eos_vm_runtime<eosio::vm::interpreter>>();
#endif
#ifdef EOSIO_EOS_VM_JIT_RUNTIME_ENABLED
if(vm == wasm_interface::vm_type::eos_vm_jit)
if(vm == wasm_interface::vm_type::eos_vm_jit && profile) {
eosio::vm::set_profile_interval_us(200);
runtime_interface = std::make_unique<webassembly::eos_vm_runtime::eos_vm_profile_runtime>();
}
if(vm == wasm_interface::vm_type::eos_vm_jit && !profile)
runtime_interface = std::make_unique<webassembly::eos_vm_runtime::eos_vm_runtime<eosio::vm::jit>>();
#endif
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
Expand All @@ -86,7 +90,7 @@ namespace eosio { namespace chain {
if(is_shutting_down)
for(wasm_cache_index::iterator it = wasm_instantiation_cache.begin(); it != wasm_instantiation_cache.end(); ++it)
wasm_instantiation_cache.modify(it, [](wasm_cache_entry& e) {
e.module.release();
e.module.release()->fast_shutdown();
});
}

Expand Down
17 changes: 16 additions & 1 deletion libraries/chain/include/eosio/chain/webassembly/eos-vm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

//eos-vm includes
#include <eosio/vm/backend.hpp>
#include <eosio/vm/profile.hpp>

namespace eosio { namespace chain { namespace webassembly { namespace eos_vm_runtime {

Expand All @@ -18,7 +19,7 @@ struct apply_options;
}}

template <typename Impl>
using eos_vm_backend_t = eosio::vm::backend<eos_vm_host_functions_t, Impl, webassembly::eos_vm_runtime::apply_options>;
using eos_vm_backend_t = eosio::vm::backend<eos_vm_host_functions_t, Impl, webassembly::eos_vm_runtime::apply_options, vm::profile_instr_map>;

template <typename Options>
using eos_vm_null_backend_t = eosio::vm::backend<eos_vm_host_functions_t, eosio::vm::null_backend, Options>;
Expand All @@ -34,6 +35,10 @@ void validate(const bytes& code, const wasm_config& cfg, const whitelisted_intri

struct apply_options;

struct profile_config {
boost::container::flat_set<name> accounts_to_profile;
};

template<typename Backend>
class eos_vm_runtime : public eosio::chain::wasm_runtime_interface {
public:
Expand All @@ -54,4 +59,14 @@ class eos_vm_runtime : public eosio::chain::wasm_runtime_interface {
friend class eos_vm_instantiated_module;
};

class eos_vm_profile_runtime : public eosio::chain::wasm_runtime_interface {
public:
eos_vm_profile_runtime();
bool inject_module(IR::Module&) override;
std::unique_ptr<wasm_instantiated_module_interface> instantiate_module(const char* code_bytes, size_t code_size, std::vector<uint8_t>,
const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version) override;

void immediately_exit_currently_running_module() override;
};

}}}}// eosio::chain::webassembly::eos_vm_runtime
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class apply_context;
class wasm_instantiated_module_interface {
public:
virtual void apply(apply_context& context) = 0;
virtual void fast_shutdown() {}

virtual ~wasm_instantiated_module_interface();
};
Expand Down
4 changes: 2 additions & 2 deletions libraries/chain/wasm_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@

namespace eosio { namespace chain {

wasm_interface::wasm_interface(vm_type vm, bool eosvmoc_tierup, const chainbase::database& d, const boost::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config)
: my( new wasm_interface_impl(vm, eosvmoc_tierup, d, data_dir, eosvmoc_config) ) {}
wasm_interface::wasm_interface(vm_type vm, bool eosvmoc_tierup, const chainbase::database& d, const boost::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, bool profile)
: my( new wasm_interface_impl(vm, eosvmoc_tierup, d, data_dir, eosvmoc_config, profile) ) {}

wasm_interface::~wasm_interface() {}

Expand Down
92 changes: 92 additions & 0 deletions libraries/chain/webassembly/runtimes/eos-vm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,72 @@ class eos_vm_instantiated_module : public wasm_instantiated_module_interface {
std::unique_ptr<backend_t> _instantiated_module;
};

class eos_vm_profiling_module : public wasm_instantiated_module_interface {
using backend_t = eosio::vm::backend<eos_vm_host_functions_t, eosio::vm::jit_profile, webassembly::eos_vm_runtime::apply_options, vm::profile_instr_map>;
public:
eos_vm_profiling_module(std::unique_ptr<backend_t> mod, const char * code, std::size_t code_size) :
_instantiated_module(std::move(mod)),
_original_code(code, code + code_size) {}


void apply(apply_context& context) override {
_instantiated_module->set_wasm_allocator(&context.control.get_wasm_allocator());
apply_options opts;
if(context.control.is_builtin_activated(builtin_protocol_feature_t::configurable_wasm_limits)) {
const wasm_config& config = context.control.get_global_properties().wasm_configuration;
opts = {config.max_pages, config.max_call_depth};
}
auto fn = [&]() {
eosio::chain::webassembly::interface iface(context);
_instantiated_module->initialize(&iface, opts);
_instantiated_module->call(
iface, "env", "apply",
context.get_receiver().to_uint64_t(),
context.get_action().account.to_uint64_t(),
context.get_action().name.to_uint64_t());
};
profile_data* prof = start(context);
try {
scoped_profile profile_runner(prof);
checktime_watchdog wd(context.trx_context.transaction_timer);
_instantiated_module->timed_run(wd, fn);
} catch(eosio::vm::timeout_exception&) {
context.trx_context.checktime();
} catch(eosio::vm::wasm_memory_exception& e) {
FC_THROW_EXCEPTION(wasm_execution_error, "access violation");
} catch(eosio::vm::exception& e) {
FC_THROW_EXCEPTION(wasm_execution_error, "eos-vm system failure");
}
}

void fast_shutdown() override {
_prof.clear();
}

profile_data* start(apply_context& context) {
name account = context.get_receiver();
if(!context.control.is_profiling(account)) return nullptr;
if(auto it = _prof.find(account); it != _prof.end()) {
return it->second.get();
} else {
auto code_sequence = context.control.db().get<account_metadata_object, by_name>(account).code_sequence;
std::string basename = account.to_string() + "." + std::to_string(code_sequence);
auto prof = std::make_unique<profile_data>(basename + ".profile", *_instantiated_module);
auto [pos,_] = _prof.insert(std::pair{ account, std::move(prof)});
std::ofstream outfile(basename + ".wasm");
outfile.write(_original_code.data(), _original_code.size());
return pos->second.get();
}
return nullptr;
}

private:

std::unique_ptr<backend_t> _instantiated_module;
boost::container::flat_map<name, std::unique_ptr<profile_data>> _prof;
std::vector<char> _original_code;
};

template<typename Impl>
eos_vm_runtime<Impl>::eos_vm_runtime() {}

Expand Down Expand Up @@ -189,4 +255,30 @@ std::unique_ptr<wasm_instantiated_module_interface> eos_vm_runtime<Impl>::instan
template class eos_vm_runtime<eosio::vm::interpreter>;
template class eos_vm_runtime<eosio::vm::jit>;

eos_vm_profile_runtime::eos_vm_profile_runtime() {}

void eos_vm_profile_runtime::immediately_exit_currently_running_module() {
throw wasm_exit{};
}

bool eos_vm_profile_runtime::inject_module(IR::Module& module) {
return false;
}

std::unique_ptr<wasm_instantiated_module_interface> eos_vm_profile_runtime::instantiate_module(const char* code_bytes, size_t code_size, std::vector<uint8_t>,
const digest_type&, const uint8_t&, const uint8_t&) {

using backend_t = eosio::vm::backend<eos_vm_host_functions_t, eosio::vm::jit_profile, webassembly::eos_vm_runtime::apply_options, vm::profile_instr_map>;
try {
wasm_code_ptr code((uint8_t*)code_bytes, code_size);
apply_options options = { .max_pages = 65536,
.max_call_depth = 0 };
std::unique_ptr<backend_t> bkend = std::make_unique<backend_t>(code, code_size, nullptr, options);
eos_vm_host_functions_t::resolve(bkend->get_module());
return std::make_unique<eos_vm_profiling_module>(std::move(bkend), code_bytes, code_size);
} catch(eosio::vm::exception& e) {
FC_THROW_EXCEPTION(wasm_execution_error, "Error building eos-vm interp: ${e}", ("e", e.what()));
}
}

}}}}
2 changes: 1 addition & 1 deletion libraries/rodeos/embedded_rodeos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ extern "C" rodeos_bool rodeos_write_deltas(rodeos_error* error, rodeos_db_snapsh

extern "C" rodeos_filter* rodeos_create_filter(rodeos_error* error, uint64_t name, const char* wasm_filename) {
return handle_exceptions(error, nullptr, [&]() -> rodeos_filter* { //
return std::make_unique<rodeos_filter>(eosio::name{ name }, wasm_filename).release();
return std::make_unique<rodeos_filter>(eosio::name{ name }, wasm_filename, false).release();
});
}

Expand Down
2 changes: 1 addition & 1 deletion libraries/rodeos/include/b1/rodeos/filter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace b1::rodeos::filter {

struct callbacks;
using rhf_t = registered_host_functions<callbacks>;
using backend_t = eosio::vm::backend<rhf_t, eosio::vm::jit>;
using backend_t = eosio::vm::backend<rhf_t, eosio::vm::jit_profile, eosio::vm::default_options, eosio::vm::profile_instr_map>;

#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
struct eosvmoc_tier {
Expand Down
4 changes: 3 additions & 1 deletion libraries/rodeos/include/b1/rodeos/rodeos.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <b1/rodeos/filter.hpp>
#include <b1/rodeos/wasm_ql.hpp>
#include <eosio/ship_protocol.hpp>
#include <eosio/vm/profile.hpp>
#include <functional>

namespace b1::rodeos {
Expand Down Expand Up @@ -74,8 +75,9 @@ struct rodeos_filter {
eosio::name name = {};
std::unique_ptr<filter::backend_t> backend = {};
std::unique_ptr<filter::filter_state> filter_state = {};
std::unique_ptr<eosio::vm::profile_data> prof = {};

rodeos_filter(eosio::name name, const std::string& wasm_filename
rodeos_filter(eosio::name name, const std::string& wasm_filename, bool profile
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
,
const boost::filesystem::path& eosvmoc_path = "",
Expand Down
6 changes: 5 additions & 1 deletion libraries/rodeos/rodeos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ void rodeos_db_snapshot::write_deltas(const ship_protocol::get_blocks_result_v1&

std::once_flag registered_filter_callbacks;

rodeos_filter::rodeos_filter(eosio::name name, const std::string& wasm_filename
rodeos_filter::rodeos_filter(eosio::name name, const std::string& wasm_filename, bool profile
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
,
const boost::filesystem::path& eosvmoc_path,
Expand All @@ -286,6 +286,9 @@ rodeos_filter::rodeos_filter(eosio::name name, const std::string& wasm_filename
backend = std::make_unique<filter::backend_t>(code, nullptr);
filter_state = std::make_unique<filter::filter_state>();
filter::rhf_t::resolve(backend->get_module());
if (profile) {
prof = std::make_unique<eosio::vm::profile_data>(wasm_filename + ".profile", *backend);
}
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
if (eosvmoc_enable) {
try {
Expand Down Expand Up @@ -329,6 +332,7 @@ void rodeos_filter::process(rodeos_db_snapshot& snapshot, const ship_protocol::g
backend->set_wasm_allocator(&filter_state->wa);
backend->initialize(&cb);
try {
eosio::vm::scoped_profile profile_runner(prof.get());
(*backend)(cb, "env", "apply", uint64_t(0), uint64_t(0), uint64_t(0));

if (!filter_state->console.empty())
Expand Down
4 changes: 4 additions & 0 deletions plugins/chain_plugin/chain_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip
#endif
})->default_value(eosio::chain::config::default_wasm_runtime, default_wasm_runtime_str), wasm_runtime_opt.c_str()
)
("profile-account", boost::program_options::value<vector<string>>()->composing(),
"The name of an account whose code will be profiled")
("abi-serializer-max-time-ms", bpo::value<uint32_t>()->default_value(config::default_abi_serializer_max_time_us / 1000),
"Override default maximum ABI serialization time allowed in ms")
("chain-state-db-size-mb", bpo::value<uint64_t>()->default_value(config::default_state_size / (1024 * 1024)), "Maximum size (in MiB) of the chain state database")
Expand Down Expand Up @@ -750,6 +752,8 @@ void chain_plugin::plugin_initialize(const variables_map& options) {
if( options.count( "wasm-runtime" ))
my->wasm_runtime = options.at( "wasm-runtime" ).as<vm_type>();

LOAD_VALUE_SET( options, "profile-account", my->chain_config->profile_accounts );

if(options.count("abi-serializer-max-time-ms")) {
my->abi_serializer_max_time_us = fc::microseconds(options.at("abi-serializer-max-time-ms").as<uint32_t>() * 1000);
my->chain_config->abi_serializer_max_time_us = my->abi_serializer_max_time_us;
Expand Down
9 changes: 6 additions & 3 deletions programs/rodeos/cloner_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ struct cloner_config : ship_client::connection_config {
uint32_t skip_to = 0;
uint32_t stop_before = 0;
bool exit_on_filter_wasm_error = false;
eosio::name filter_name = {}; // todo: remove
std::string filter_wasm = {}; // todo: remove
eosio::name filter_name = {}; // todo: remove
std::string filter_wasm = {}; // todo: remove
bool profile = false;

#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
eosio::chain::eosvmoc::config eosvmoc_config;
Expand Down Expand Up @@ -85,7 +86,7 @@ struct cloner_session : ship_client::connection_callbacks, std::enable_shared_fr
cloner_session(cloner_plugin_impl* my) : my(my), config(my->config) {
// todo: remove
if (!config->filter_wasm.empty())
filter = std::make_unique<rodeos_filter>(config->filter_name, config->filter_wasm
filter = std::make_unique<rodeos_filter>(config->filter_name, config->filter_wasm, config->profile
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
,
app().data_dir(), config->eosvmoc_config, config->eosvmoc_tierup
Expand Down Expand Up @@ -242,6 +243,7 @@ void cloner_plugin::set_program_options(options_description& cli, options_descri
// todo: remove
op("filter-name", bpo::value<std::string>(), "Filter name");
op("filter-wasm", bpo::value<std::string>(), "Filter wasm");
op("profile-filter", bpo::bool_switch(), "Enable filter profiling");

#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
op("eos-vm-oc-cache-size-mb",
Expand Down Expand Up @@ -274,6 +276,7 @@ void cloner_plugin::plugin_initialize(const variables_map& options) {
if (options.count("filter-name") && options.count("filter-wasm")) {
my->config->filter_name = eosio::name{ options["filter-name"].as<std::string>() };
my->config->filter_wasm = options["filter-wasm"].as<std::string>();
my->config->profile = options["profile-filter"].as<bool>();
} else if (options.count("filter-name") || options.count("filter-wasm")) {
throw std::runtime_error("filter-name and filter-wasm must be used together");
}
Expand Down
3 changes: 2 additions & 1 deletion tests/rodeos_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ def __enter__(self):

def __exit__(self, exc_type, exc_value, traceback):
if self.rodeos is not None:
self.rodeos.kill()
self.rodeos.send_signal(signal.SIGINT)
self.rodeos.wait()
if self.rodeosStdout is not None:
self.rodeosStdout.close()
if self.rodeosStderr is not None:
Expand Down