Skip to content

Commit

Permalink
Merge pull request AntelopeIO#1322 from AntelopeIO/AntelopeIOGH-1251-…
Browse files Browse the repository at this point in the history
…auto-oc

Add eos-vm-oc-enable auto mode
  • Loading branch information
heifner authored Jun 29, 2023
2 parents 8c64e08 + cd744f5 commit 91d192b
Show file tree
Hide file tree
Showing 30 changed files with 336 additions and 87 deletions.
11 changes: 10 additions & 1 deletion docs/01_nodeos/03_plugins/chain_plugin/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,16 @@ Config Options for eosio::chain_plugin:
code cache
--eos-vm-oc-compile-threads arg (=1) Number of threads to use for EOS VM OC
tier-up
--eos-vm-oc-enable Enable EOS VM OC tier-up runtime
--eos-vm-oc-enable arg (=auto) Enable EOS VM OC tier-up runtime
('auto', 'all', 'none').
'auto' - EOS VM OC tier-up is enabled
for eosio.* accounts, read-only trxs,
and applying blocks.
'all' - EOS VM OC tier-up is enabled
for all contract execution.
'none' - EOS VM OC tier-up is
completely disabled.

--enable-account-queries arg (=0) enable queries to find accounts by
various metadata.
--max-nonprivileged-inline-action-size arg (=4096)
Expand Down
15 changes: 15 additions & 0 deletions libraries/chain/apply_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1094,4 +1094,19 @@ action_name apply_context::get_sender() const {
return action_name();
}

// Context | OC?
//-------------------------------------------------------------------------------
// Building block | baseline, OC for eosio.*
// Applying block | OC unless a producer, OC for eosio.* including producers
// Speculative API trx | baseline, OC for eosio.*
// Speculative P2P trx | baseline, OC for eosio.*
// Compute trx | baseline, OC for eosio.*
// Read only trx | OC
bool apply_context::should_use_eos_vm_oc()const {
return receiver.prefix() == config::system_account_name // "eosio"_n, all cases use OC
|| (is_applying_block() && !control.is_producer_node()) // validating/applying block
|| trx_context.is_read_only();
}


} } /// eosio::chain
76 changes: 24 additions & 52 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <eosio/chain/thread_utils.hpp>
#include <eosio/chain/platform_timer.hpp>
#include <eosio/chain/deep_mind.hpp>
#include <eosio/chain/wasm_interface_collection.hpp>

#include <chainbase/chainbase.hpp>
#include <eosio/vm/allocator.hpp>
Expand Down Expand Up @@ -239,6 +240,7 @@ struct controller_impl {
controller::config conf;
const chain_id_type chain_id; // read by thread_pool threads, value will not be changed
bool replaying = false;
bool is_producer_node = false; // true if node is configured as a block producer
db_read_mode read_mode = db_read_mode::HEAD;
bool in_trx_requiring_checks = false; ///< if true, checks that are normally skipped on replay (e.g. auth checks) cannot be skipped
std::optional<fc::microseconds> subjective_cpu_leeway;
Expand All @@ -249,14 +251,11 @@ struct controller_impl {
deep_mind_handler* deep_mind_logger = nullptr;
bool okay_to_print_integrity_hash_on_stop = false;

std::thread::id main_thread_id;
thread_local static platform_timer timer; // a copy for main thread and each read-only thread
#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
wasm_interface wasmif; // used by main thread and all threads for EOSVMOC
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
wasm_interface_collection wasm_if_collect;
app_window_type app_window = app_window_type::write;

typedef pair<scope_name,action_name> handler_key;
Expand Down Expand Up @@ -315,8 +314,7 @@ struct controller_impl {
chain_id( chain_id ),
read_mode( cfg.read_mode ),
thread_pool(),
main_thread_id( std::this_thread::get_id() ),
wasmif( conf.wasm_runtime, conf.eosvmoc_tierup, db, conf.state_dir, conf.eosvmoc_config, !conf.profile_accounts.empty() )
wasm_if_collect( conf.wasm_runtime, conf.eosvmoc_tierup, db, conf.state_dir, conf.eosvmoc_config, !conf.profile_accounts.empty() )
{
fork_db.open( [this]( block_timestamp_type timestamp,
const flat_set<digest_type>& cur_features,
Expand All @@ -342,12 +340,7 @@ struct controller_impl {
set_activation_handler<builtin_protocol_feature_t::crypto_primitives>();

self.irreversible_block.connect([this](const block_state_ptr& bsp) {
// 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);
}
wasm_if_collect.current_lib(bsp->block_num);
});


Expand Down Expand Up @@ -2685,31 +2678,6 @@ struct controller_impl {
return (blog.first_block_num() != 0) ? blog.first_block_num() : fork_db.root()->block_num;
}

#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
bool is_eos_vm_oc_enabled() const {
return ( conf.eosvmoc_tierup || conf.wasm_runtime == wasm_interface::vm_type::eos_vm_oc );
}
#endif

// only called from non-main threads (read-only trx execution threads)
// when producer_plugin starts them
void init_thread_local_data() {
EOS_ASSERT( !is_on_main_thread(), misc_exception, "init_thread_local_data called on the main thread");
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
if ( is_eos_vm_oc_enabled() )
// EOSVMOC needs further initialization of its thread local data
wasmif.init_thread_local_data();
else
#endif
{
std::lock_guard g(threaded_wasmifs_mtx);
// Non-EOSVMOC needs a wasmif per thread
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(); };

void set_to_write_window() {
app_window = app_window_type::write;
}
Expand All @@ -2720,25 +2688,22 @@ struct controller_impl {
return app_window == app_window_type::write;
}

wasm_interface& get_wasm_interface() {
if ( is_on_main_thread()
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
|| is_eos_vm_oc_enabled()
bool is_eos_vm_oc_enabled() const {
return wasm_if_collect.is_eos_vm_oc_enabled();
}
#endif
)
return wasmif;
else
return *threaded_wasmifs[std::this_thread::get_id()];

void init_thread_local_data() {
wasm_if_collect.init_thread_local_data(db, conf.state_dir, conf.eosvmoc_config, !conf.profile_accounts.empty());
}

wasm_interface& get_wasm_interface() {
return wasm_if_collect.get_wasm_interface();
}

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);
}
wasm_if_collect.code_block_num_last_used(code_hash, vm_type, vm_version, block_num);
}

block_state_ptr fork_db_head() const;
Expand Down Expand Up @@ -3615,7 +3580,6 @@ vm::wasm_allocator& controller::get_wasm_allocator() {
return my->wasm_alloc;
}
#endif

#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
bool controller::is_eos_vm_oc_enabled() const {
return my->is_eos_vm_oc_enabled();
Expand Down Expand Up @@ -3723,6 +3687,14 @@ void controller::replace_account_keys( name account, name permission, const publ
rlm.verify_account_ram_usage(account);
}

void controller::set_producer_node(bool is_producer_node) {
my->is_producer_node = is_producer_node;
}

bool controller::is_producer_node()const {
return my->is_producer_node;
}

void controller::set_db_read_only_mode() {
mutable_db().set_read_only_mode();
}
Expand Down
3 changes: 3 additions & 0 deletions libraries/chain/include/eosio/chain/apply_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,9 @@ class apply_context {

action_name get_sender() const;

bool is_applying_block() const { return trx_context.explicit_billed_cpu_time; }
bool should_use_eos_vm_oc()const;

/// Fields:
public:

Expand Down
7 changes: 6 additions & 1 deletion libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ namespace eosio { namespace chain {

wasm_interface::vm_type wasm_runtime = chain::config::default_wasm_runtime;
eosvmoc::config eosvmoc_config;
bool eosvmoc_tierup = false;
wasm_interface::vm_oc_enable eosvmoc_tierup = wasm_interface::vm_oc_enable::oc_auto;

db_read_mode read_mode = db_read_mode::HEAD;
validation_mode block_validation_mode = validation_mode::FULL;
Expand Down Expand Up @@ -321,6 +321,8 @@ namespace eosio { namespace chain {

#if defined(EOSIO_EOS_VM_RUNTIME_ENABLED) || defined(EOSIO_EOS_VM_JIT_RUNTIME_ENABLED)
vm::wasm_allocator& get_wasm_allocator();
#endif
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
bool is_eos_vm_oc_enabled() const;
#endif

Expand Down Expand Up @@ -355,6 +357,9 @@ namespace eosio { namespace chain {
void replace_producer_keys( const public_key_type& key );
void replace_account_keys( name account, name permission, const public_key_type& key );

void set_producer_node(bool is_producer_node);
bool is_producer_node()const;

void set_db_read_only_mode();
void unset_db_read_only_mode();
void init_thread_local_data();
Expand Down
35 changes: 35 additions & 0 deletions libraries/chain/include/eosio/chain/name.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,41 @@ namespace eosio::chain {
friend constexpr bool operator != ( const name& a, uint64_t b ) { return a.value != b; }

constexpr explicit operator bool()const { return value != 0; }

/**
* Returns the prefix.
* for exmaple:
* "eosio.any" -> "eosio"
* "eosio" -> "eosio"
*/
constexpr name prefix() const {
uint64_t result = value;
bool not_dot_character_seen = false;
uint64_t mask = 0xFull;

// Get characters one-by-one in name in order from right to left
for (int32_t offset = 0; offset <= 59;) {
auto c = (value >> offset) & mask;

if (!c) { // if this character is a dot
if (not_dot_character_seen) { // we found the rightmost dot character
result = (value >> offset) << offset;
break;
}
} else {
not_dot_character_seen = true;
}

if (offset == 0) {
offset += 4;
mask = 0x1Full;
} else {
offset += 5;
}
}

return name{ result };
}
};

// Each char of the string is encoded into 5-bit chunk and left-shifted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,6 @@ namespace eosio { namespace chain {
speculative_executed_adjusted_max_transaction_time // prev_billed_cpu_time_us > 0
};
tx_cpu_usage_exceeded_reason tx_cpu_usage_reason = tx_cpu_usage_exceeded_reason::account_cpu_limit;
fc::microseconds tx_cpu_usage_amount;
};

} }
19 changes: 17 additions & 2 deletions libraries/chain/include/eosio/chain/wasm_interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,13 @@ namespace eosio { namespace chain {
}
}

wasm_interface(vm_type vm, bool eosvmoc_tierup, const chainbase::database& d, const std::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, bool profile);
enum class vm_oc_enable {
oc_auto,
oc_all,
oc_none
};

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

// initialize exec per thread
Expand Down Expand Up @@ -70,13 +76,22 @@ namespace eosio { namespace chain {
const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version, apply_context& context)> substitute_apply;
private:
unique_ptr<struct wasm_interface_impl> my;
vm_type vm;
};

} } // eosio::chain

namespace eosio{ namespace chain {
std::istream& operator>>(std::istream& in, wasm_interface::vm_type& runtime);
inline std::ostream& operator<<(std::ostream& os, wasm_interface::vm_oc_enable t) {
if (t == wasm_interface::vm_oc_enable::oc_auto) {
os << "auto";
} else if (t == wasm_interface::vm_oc_enable::oc_all) {
os << "all";
} else if (t == wasm_interface::vm_oc_enable::oc_none) {
os << "none";
}
return os;
}
}}

FC_REFLECT_ENUM( eosio::chain::wasm_interface::vm_type, (eos_vm)(eos_vm_jit)(eos_vm_oc) )
85 changes: 85 additions & 0 deletions libraries/chain/include/eosio/chain/wasm_interface_collection.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#pragma once
#include <eosio/chain/wasm_interface.hpp>

namespace eosio::chain {

/**
* @class wasm_interface_collection manages the active wasm_interface to use for execution.
*/
class wasm_interface_collection {
public:
wasm_interface_collection(wasm_interface::vm_type vm, wasm_interface::vm_oc_enable eosvmoc_tierup,
const chainbase::database& d, const std::filesystem::path& data_dir,
const eosvmoc::config& eosvmoc_config, bool profile)
: main_thread_id(std::this_thread::get_id())
, wasm_runtime(vm)
, eosvmoc_tierup(eosvmoc_tierup)
, wasmif(vm, eosvmoc_tierup, d, data_dir, eosvmoc_config, profile)
{}

wasm_interface& get_wasm_interface() {
if (is_on_main_thread()
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
|| is_eos_vm_oc_enabled()
#endif
)
return wasmif;
return *threaded_wasmifs[std::this_thread::get_id()];
}

// update current lib of all wasm interfaces
void current_lib(const uint32_t lib) {
// producer_plugin has already asserted irreversible_block signal is called in write window
wasmif.current_lib(lib);
for (auto& w: threaded_wasmifs) {
w.second->current_lib(lib);
}
}

// only called from non-main threads (read-only trx execution threads) when producer_plugin starts them
void init_thread_local_data(const chainbase::database& d, const std::filesystem::path& data_dir,
const eosvmoc::config& eosvmoc_config, bool profile) {
EOS_ASSERT(!is_on_main_thread(), misc_exception, "init_thread_local_data called on the main thread");
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
if (is_eos_vm_oc_enabled()) {
// EOSVMOC needs further initialization of its thread local data
wasmif.init_thread_local_data();
} else
#endif
{
std::lock_guard g(threaded_wasmifs_mtx);
// Non-EOSVMOC needs a wasmif per thread
threaded_wasmifs[std::this_thread::get_id()] = std::make_unique<wasm_interface>(wasm_runtime, eosvmoc_tierup, d, data_dir, eosvmoc_config, profile);
}
}

#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
bool is_eos_vm_oc_enabled() const {
return ((eosvmoc_tierup != wasm_interface::vm_oc_enable::oc_none) || wasm_runtime == wasm_interface::vm_type::eos_vm_oc);
}
#endif

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);
}
}

private:
bool is_on_main_thread() { return main_thread_id == std::this_thread::get_id(); };

private:
const std::thread::id main_thread_id;
const wasm_interface::vm_type wasm_runtime;
const wasm_interface::vm_oc_enable eosvmoc_tierup;

wasm_interface wasmif; // used by main thread and all threads for EOSVMOC
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
};

} // eosio::chain
Loading

0 comments on commit 91d192b

Please sign in to comment.