Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[4.0] Added missing calls to wasmifs on read-only threads #964

Merged
merged 6 commits into from
Apr 5, 2023
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
35 changes: 27 additions & 8 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,9 @@ struct controller_impl {
#if defined(EOSIO_EOS_VM_RUNTIME_ENABLED) || defined(EOSIO_EOS_VM_JIT_RUNTIME_ENABLED)
thread_local static vm::wasm_allocator wasm_alloc; // a copy for main thread and each read-only thread
#endif
// Ideally wasmif should be thread_local which must be a static.
// Unittests can create multiple controller objects (testers) at the same time,
// which overwrites the same static wasmif, is used for eosvmoc too.
wasm_interface wasmif; // used by main thread and all threads for EOSVMOC
thread_local static std::unique_ptr<wasm_interface> wasmif_thread_local; // a copy for each read-only thread, used by eos-vm and eos-vm-jit
std::mutex threaded_wasmifs_mtx;
std::unordered_map<std::thread::id, std::unique_ptr<wasm_interface>> threaded_wasmifs; // one for each read-only thread, used by eos-vm and eos-vm-jit
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure you need a unique_ptr here.. couldn't you just emplace() the wasm_interface in?

app_window_type app_window = app_window_type::write;

typedef pair<scope_name,action_name> handler_key;
Expand Down Expand Up @@ -344,7 +342,12 @@ struct controller_impl {
set_activation_handler<builtin_protocol_feature_t::crypto_primitives>();

self.irreversible_block.connect([this](const block_state_ptr& bsp) {
get_wasm_interface().current_lib(bsp->block_num);
// producer_plugin has already asserted irreversible_block signal is
// called in write window
wasmif.current_lib(bsp->block_num);
for (auto& w: threaded_wasmifs) {
w.second->current_lib(bsp->block_num);
}
});


Expand Down Expand Up @@ -2695,8 +2698,11 @@ struct controller_impl {
wasmif.init_thread_local_data();
else
#endif
{
std::lock_guard g(threaded_wasmifs_mtx);
// Non-EOSVMOC needs a wasmif per thread
wasmif_thread_local = std::make_unique<wasm_interface>( conf.wasm_runtime, conf.eosvmoc_tierup, db, conf.state_dir, conf.eosvmoc_config, !conf.profile_accounts.empty());
threaded_wasmifs[std::this_thread::get_id()] = std::make_unique<wasm_interface>( conf.wasm_runtime, conf.eosvmoc_tierup, db, conf.state_dir, conf.eosvmoc_config, !conf.profile_accounts.empty());
}
}

bool is_on_main_thread() { return main_thread_id == std::this_thread::get_id(); };
Expand All @@ -2719,7 +2725,17 @@ struct controller_impl {
)
return wasmif;
else
return *wasmif_thread_local;
return *threaded_wasmifs[std::this_thread::get_id()];
}

void code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version, uint32_t block_num) {
// The caller of this function apply_eosio_setcode has already asserted that
// the transaction is not a read-only trx, which implies we are
// in write window. Safe to call threaded_wasmifs's code_block_num_last_used
wasmif.code_block_num_last_used(code_hash, vm_type, vm_version, block_num);
for (auto& w: threaded_wasmifs) {
w.second->code_block_num_last_used(code_hash, vm_type, vm_version, block_num);
}
}

block_state_ptr fork_db_head() const;
Expand All @@ -2729,7 +2745,6 @@ thread_local platform_timer controller_impl::timer;
#if defined(EOSIO_EOS_VM_RUNTIME_ENABLED) || defined(EOSIO_EOS_VM_JIT_RUNTIME_ENABLED)
thread_local eosio::vm::wasm_allocator controller_impl::wasm_alloc;
#endif
thread_local std::unique_ptr<wasm_interface> controller_impl::wasmif_thread_local;

const resource_limits_manager& controller::get_resource_limits_manager()const
{
Expand Down Expand Up @@ -3714,6 +3729,10 @@ bool controller::is_write_window() const {
return my->is_write_window();
}

void controller::code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version, uint32_t block_num) {
return my->code_block_num_last_used(code_hash, vm_type, vm_version, block_num);
}

/// Protocol feature activation handlers:

template<>
Expand Down
2 changes: 1 addition & 1 deletion libraries/chain/eosio_contract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ void apply_eosio_setcode(apply_context& context) {
old_size = (int64_t)old_code_entry.code.size() * config::setcode_ram_bytes_multiplier;
if( old_code_entry.code_ref_count == 1 ) {
db.remove(old_code_entry);
context.control.get_wasm_interface().code_block_num_last_used(account.code_hash, account.vm_type, account.vm_version, context.control.head_block_num() + 1);
context.control.code_block_num_last_used(account.code_hash, account.vm_type, account.vm_version, context.control.head_block_num() + 1);
} else {
db.modify(old_code_entry, [](code_object& o) {
--o.code_ref_count;
Expand Down
1 change: 1 addition & 0 deletions libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ namespace eosio { namespace chain {
void set_to_write_window();
void set_to_read_window();
bool is_write_window() const;
void code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version, uint32_t block_num);

private:
friend class apply_context;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ namespace eosio { namespace chain {
struct wasm_interface_impl {
struct wasm_cache_entry {
digest_type code_hash;
uint32_t first_block_num_used;
uint32_t last_block_num_used;
std::unique_ptr<wasm_instantiated_module_interface> module;
uint8_t vm_type = 0;
Expand Down Expand Up @@ -157,7 +156,6 @@ namespace eosio { namespace chain {

it = wasm_instantiation_cache.emplace( wasm_interface_impl::wasm_cache_entry{
.code_hash = code_hash,
.first_block_num_used = codeobject->first_block_used,
.last_block_num_used = UINT32_MAX,
.module = nullptr,
.vm_type = vm_type,
Expand Down Expand Up @@ -209,7 +207,6 @@ namespace eosio { namespace chain {
member<wasm_cache_entry, uint8_t, &wasm_cache_entry::vm_version>
>
>,
ordered_non_unique<tag<by_first_block_num>, member<wasm_cache_entry, uint32_t, &wasm_cache_entry::first_block_num_used>>,
ordered_non_unique<tag<by_last_block_num>, member<wasm_cache_entry, uint32_t, &wasm_cache_entry::last_block_num_used>>
>
> wasm_cache_index;
Expand Down
16 changes: 15 additions & 1 deletion plugins/producer_plugin/producer_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -514,8 +514,9 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
}

void on_irreversible_block( const signed_block_ptr& lib ) {
_irreversible_block_time = lib->timestamp.to_time_point();
const chain::controller& chain = chain_plug->chain();
EOS_ASSERT(chain.is_write_window(), producer_exception, "write window is expected for on_irreversible_block signal");
_irreversible_block_time = lib->timestamp.to_time_point();

// promote any pending snapshots
auto& snapshots_by_height = _pending_snapshot_index.get<by_height>();
Expand Down Expand Up @@ -1210,6 +1211,7 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_
my->_snapshot_scheduler.set_create_snapshot_fn([this](producer_plugin::next_function<producer_plugin::snapshot_information> next){create_snapshot(next);});
} FC_LOG_AND_RETHROW() }

using namespace std::chrono_literals;
void producer_plugin::plugin_startup()
{ try {
try {
Expand Down Expand Up @@ -1255,15 +1257,27 @@ void producer_plugin::plugin_startup()
}

if ( my->_ro_thread_pool_size > 0 ) {
std::atomic<uint32_t> num_threads_started = 0;
my->_ro_thread_pool.start( my->_ro_thread_pool_size,
[]( const fc::exception& e ) {
fc_elog( _log, "Exception in read-only thread pool, exiting: ${e}", ("e", e.to_detail_string()) );
app().quit();
},
[&]() {
chain.init_thread_local_data();
++num_threads_started;
});

// This will be changed with std::latch or std::atomic<>::wait
// when C++20 is used.
auto time_slept_ms = 0;
constexpr auto max_time_slept_ms = 1000;
while ( num_threads_started.load() < my->_ro_thread_pool_size && time_slept_ms < max_time_slept_ms ) {
std::this_thread::sleep_for( 1ms );
++time_slept_ms;
}
EOS_ASSERT(num_threads_started.load() == my->_ro_thread_pool_size, producer_exception, "read-only threads failed to start. num_threads_started: ${n}, time_slept_ms: ${t}ms", ("n", num_threads_started.load())("t", time_slept_ms));

my->start_write_window();
}

Expand Down