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 3 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, cfg.db_hugepage_paths ),
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 @@ -100,6 +100,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 @@ -289,6 +291,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 @@ -20,7 +20,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 @@ -260,6 +260,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 @@ -754,6 +756,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 @@ -33,8 +33,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 @@ -78,7 +79,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 @@ -235,6 +236,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 @@ -267,6 +269,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