Skip to content

Commit

Permalink
Merge branch 'main' into make_wasm_globals_threaded_safe
Browse files Browse the repository at this point in the history
  • Loading branch information
linh2931 authored Jul 24, 2023
2 parents 066e785 + 8068252 commit 06ac1ba
Show file tree
Hide file tree
Showing 26 changed files with 690 additions and 428 deletions.
17 changes: 11 additions & 6 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ jobs:
cpack
- name: Install dev package
run: |
apt update && apt upgrade -y
apt install -y ./build/leap_*.deb ./build/leap-dev*.deb
apt-get update && apt-get upgrade -y
apt-get install -y ./build/leap_*.deb ./build/leap-dev*.deb
- name: Test using TestHarness
run: |
python3 -c "from TestHarness import Cluster"
Expand Down Expand Up @@ -199,7 +199,15 @@ jobs:
test: [build-tree, make-dev-install, deb-install]
runs-on: ["self-hosted", "enf-x86-midtier"]
container: ${{ matrix.test != 'deb-install' && fromJSON(needs.build-base.outputs.p)[matrix.platform].image || matrix.platform == 'ubuntu20' && 'ubuntu:focal' || 'ubuntu:jammy' }}
env:
DEBIAN_FRONTEND: noninteractive
TZ: Etc/UTC
steps:
- name: Update Package Index & Upgrade Packages
run: |
apt-get update
apt-get upgrade -y
# LEAP
- if: ${{ matrix.test != 'deb-install' }}
name: Clone leap
Expand Down Expand Up @@ -236,9 +244,6 @@ jobs:
- if: ${{ matrix.test == 'deb-install' }}
name: Install leap-dev Package
run: |
apt-get update
export DEBIAN_FRONTEND='noninteractive'
export TZ='Etc/UTC'
apt-get install -y ./*.deb
rm ./*.deb
Expand All @@ -255,7 +260,7 @@ jobs:
token: ${{github.token}}
- name: Install cdt Packages
run: |
apt install -y ./*.deb
apt-get install -y ./*.deb
rm ./*.deb
# Reference Contracts
Expand Down
1 change: 1 addition & 0 deletions libraries/chain/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ add_library( eosio_chain

wast_to_wasm.cpp
wasm_interface.cpp
wasm_interface_collection.cpp
wasm_eosio_validation.cpp
wasm_eosio_injection.cpp
wasm_config.cpp
Expand Down
2 changes: 1 addition & 1 deletion libraries/chain/apply_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include <eosio/chain/controller.hpp>
#include <eosio/chain/transaction_context.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/wasm_interface.hpp>
#include <eosio/chain/wasm_interface_collection.hpp>
#include <eosio/chain/generated_transaction_object.hpp>
#include <eosio/chain/authorization_manager.hpp>
#include <eosio/chain/resource_limits.hpp>
Expand Down
6 changes: 3 additions & 3 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2692,8 +2692,8 @@ struct controller_impl {
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();
wasm_interface_collection& get_wasm_interface() {
return wasm_if_collect;
}

void code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version, uint32_t block_num) {
Expand Down Expand Up @@ -3394,7 +3394,7 @@ const apply_handler* controller::find_apply_handler( account_name receiver, acco
}
return nullptr;
}
wasm_interface& controller::get_wasm_interface() {
wasm_interface_collection& controller::get_wasm_interface() {
return my->get_wasm_interface();
}

Expand Down
3 changes: 2 additions & 1 deletion libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ namespace eosio { namespace chain {
class account_object;
class deep_mind_handler;
class subjective_billing;
class wasm_interface_collection;
using resource_limits::resource_limits_manager;
using apply_handler = std::function<void(apply_context&)>;
using forked_branch_callback = std::function<void(const branch_type&)>;
Expand Down Expand Up @@ -348,7 +349,7 @@ namespace eosio { namespace chain {
*/

const apply_handler* find_apply_handler( account_name contract, scope_name scope, action_name act )const;
wasm_interface& get_wasm_interface();
wasm_interface_collection& get_wasm_interface();

static chain_id_type extract_chain_id(snapshot_reader& snapshot);

Expand Down
11 changes: 3 additions & 8 deletions libraries/chain/include/eosio/chain/wasm_interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ namespace eosio { namespace chain {
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(vm_type vm, const chainbase::database& d, const std::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, bool profile);
~wasm_interface();

// initialize exec per thread
Expand All @@ -61,19 +61,14 @@ namespace eosio { namespace chain {
//indicate that a particular code probably won't be used after given block_num
void code_block_num_last_used(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version, const uint32_t& block_num);

//indicate the current LIB. evicts old cache entries
void current_lib(const uint32_t lib);
//indicate the current LIB. evicts old cache entries, each evicted entry is provided to callback
void current_lib(const uint32_t lib, const std::function<void(const digest_type&, uint8_t)>& callback);

//Calls apply or error on a given code
void apply(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version, apply_context& context);

//Returns true if the code is cached
bool is_code_cached(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version) const;

// If substitute_apply is set, then apply calls it before doing anything else. If substitute_apply returns true,
// then apply returns immediately.
std::function<bool(
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;
};
Expand Down
74 changes: 27 additions & 47 deletions libraries/chain/include/eosio/chain/wasm_interface_collection.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#pragma once
#include <eosio/chain/wasm_interface.hpp>
#include <mutex>
#include <thread>
#include <unordered_map>

namespace eosio::chain {

Expand All @@ -8,66 +11,39 @@ namespace eosio::chain {
*/
class wasm_interface_collection {
public:
inline static bool test_disable_tierup = false; // set by unittests to test tierup failing

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()];
const eosvmoc::config& eosvmoc_config, bool profile);

~wasm_interface_collection();

void apply(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version, apply_context& context);

// used for tests, only valid on main thread
bool is_code_cached(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version) {
EOS_ASSERT(is_on_main_thread(), wasm_execution_error, "is_code_cached called off the main thread");
return wasmif.is_code_cached(code_hash, vm_type, vm_version);
}

// 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);
}
}
void current_lib(const uint32_t 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);
}
}
void init_thread_local_data(const chainbase::database& d, const std::filesystem::path& data_dir, const eosvmoc::config& eosvmoc_config, bool 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);
}
}
void code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version, uint32_t block_num);

// If substitute_apply is set, then apply calls it before doing anything else. If substitute_apply returns true,
// then apply returns immediately. Provided function must be multi-thread safe.
std::function<bool(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version, apply_context& context)> substitute_apply;

private:
bool is_on_main_thread() { return main_thread_id == std::this_thread::get_id(); };
Expand All @@ -77,9 +53,13 @@ namespace eosio::chain {
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
wasm_interface wasmif; // used by main thread
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

#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
std::unique_ptr<struct eosvmoc_tier> eosvmoc; // used by all threads
#endif
};

} // eosio::chain
57 changes: 9 additions & 48 deletions libraries/chain/include/eosio/chain/wasm_interface_private.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,32 +43,10 @@ namespace eosio { namespace chain {
struct by_hash;
struct by_last_block_num;

#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
struct eosvmoc_tier {
eosvmoc_tier(const std::filesystem::path& d, const eosvmoc::config& c, const chainbase::database& db)
: cc(d, c, db) {
// construct exec for the main thread
init_thread_local_data();
}

// Support multi-threaded execution.
void init_thread_local_data() {
exec = std::make_unique<eosvmoc::executor>(cc);
}

eosvmoc::code_cache_async cc;

// Each thread requires its own exec and mem. Defined in wasm_interface.cpp
thread_local static std::unique_ptr<eosvmoc::executor> exec;
thread_local static eosvmoc::memory mem;
};
#endif

wasm_interface_impl(wasm_interface::vm_type vm, wasm_interface::vm_oc_enable eosvmoc_tierup, const chainbase::database& d,
wasm_interface_impl(wasm_interface::vm_type vm, const chainbase::database& d,
const std::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, bool profile)
: db(d)
, wasm_runtime_time(vm)
, eosvmoc_tierup(eosvmoc_tierup)
{
#ifdef EOSIO_EOS_VM_RUNTIME_ENABLED
if(vm == wasm_interface::vm_type::eos_vm)
Expand All @@ -88,22 +66,9 @@ namespace eosio { namespace chain {
#endif
if(!runtime_interface)
EOS_THROW(wasm_exception, "${r} wasm runtime not supported on this platform and/or configuration", ("r", vm));

#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
if(eosvmoc_tierup != wasm_interface::vm_oc_enable::oc_none) {
EOS_ASSERT(vm != wasm_interface::vm_type::eos_vm_oc, wasm_exception, "You can't use EOS VM OC as the base runtime when tier up is activated");
eosvmoc.emplace(data_dir, eosvmoc_config, d);
}
#endif
}

~wasm_interface_impl() {
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()->fast_shutdown();
});
}
~wasm_interface_impl() = default;

bool is_code_cached(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version) const {
wasm_cache_index::iterator it = wasm_instantiation_cache.find( boost::make_tuple(code_hash, vm_type, vm_version) );
Expand All @@ -118,14 +83,16 @@ namespace eosio { namespace chain {
});
}

void current_lib(uint32_t lib) {
// reports each code_hash and vm_version that will be erased to callback
void current_lib(uint32_t lib, const std::function<void(const digest_type&, uint8_t)>& callback) {
//anything last used before or on the LIB can be evicted
const auto first_it = wasm_instantiation_cache.get<by_last_block_num>().begin();
const auto last_it = wasm_instantiation_cache.get<by_last_block_num>().upper_bound(lib);
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
if(eosvmoc) for(auto it = first_it; it != last_it; it++)
eosvmoc->cc.free_code(it->code_hash, it->vm_version);
#endif
if (callback) {
for(auto it = first_it; it != last_it; it++) {
callback(it->code_hash, it->vm_version);
}
}
wasm_instantiation_cache.get<by_last_block_num>().erase(first_it, last_it);
}

Expand Down Expand Up @@ -162,7 +129,6 @@ namespace eosio { namespace chain {
return it->module;
}

bool is_shutting_down = false;
std::unique_ptr<wasm_runtime_interface> runtime_interface;

typedef boost::multi_index_container<
Expand All @@ -182,11 +148,6 @@ namespace eosio { namespace chain {

const chainbase::database& db;
const wasm_interface::vm_type wasm_runtime_time;
const wasm_interface::vm_oc_enable eosvmoc_tierup;

#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
std::optional<eosvmoc_tier> eosvmoc;
#endif
};

} } // eosio::chain
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ 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
Loading

0 comments on commit 06ac1ba

Please sign in to comment.