Skip to content

Commit

Permalink
GH-984 Remove subjective eos-vm-oc limits for whitelisted accounts. A…
Browse files Browse the repository at this point in the history
…lso prioritize compilation of whitelisted accounts when applying blocks.
  • Loading branch information
heifner committed Nov 4, 2024
1 parent d94e588 commit 5ae808a
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 30 deletions.
6 changes: 5 additions & 1 deletion libraries/chain/apply_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1090,6 +1090,10 @@ action_name apply_context::get_sender() const {
return action_name();
}

bool apply_context::is_eos_vm_oc_whitelisted() const {
return receiver.prefix() == config::system_account_name; // "eosio"_n
}

// Context | OC?
//-------------------------------------------------------------------------------
// Building block | baseline, OC for eosio.*
Expand All @@ -1099,7 +1103,7 @@ action_name apply_context::get_sender() const {
// 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
return is_eos_vm_oc_whitelisted() // all cases use OC
|| (is_applying_block() && !control.is_producer_node()) // validating/applying block
|| trx_context.is_read_only();
}
Expand Down
1 change: 1 addition & 0 deletions libraries/chain/include/eosio/chain/apply_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,7 @@ class apply_context {
action_name get_sender() const;

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

/// Fields:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,34 @@
namespace eosio { namespace chain { namespace eosvmoc {

struct config {
uint64_t get_cache_size() const { return cache_size; }
uint64_t get_threads() const { return threads; }

std::optional<rlim_t> get_cpu_limit() const { return !whitelisted ? cpu_limit : std::optional<rlim_t>{}; }
std::optional<rlim_t> get_vm_limit() const { return !whitelisted ? vm_limit : std::optional<rlim_t>{}; }

uint64_t get_stack_size_limit() const {
return !whitelisted
? stack_size_limit
? *stack_size_limit
: std::numeric_limits<uint64_t>::max()
: std::numeric_limits<uint64_t>::max();
}

size_t get_generated_code_size_limit() const {
return !whitelisted
? generated_code_size_limit
? *generated_code_size_limit
: std::numeric_limits<uint64_t>::max()
: std::numeric_limits<uint64_t>::max();
}

bool whitelisted = false;
uint64_t cache_size = 1024u*1024u*1024u;
uint64_t threads = 1u;

// subjective limits for OC compilation.
// nodeos enforces the limits by the default values.
// nodeos enforces the limits by the default values unless account is whitelisted.
// libtester disables the limits in all tests, except enforces the limits
// in the tests in unittests/eosvmoc_limits_tests.cpp.
std::optional<rlim_t> cpu_limit {20u};
Expand All @@ -36,8 +59,9 @@ struct config {
//work around unexpected std::optional behavior
template <typename DS>
inline DS& operator>>(DS& ds, eosio::chain::eosvmoc::config& cfg) {
fc::raw::pack(ds, cfg.cache_size);
fc::raw::pack(ds, cfg.threads);
fc::raw::unpack(ds, cfg.whitelisted);
fc::raw::unpack(ds, cfg.cache_size);
fc::raw::unpack(ds, cfg.threads);

auto better_optional_unpack = [&]<typename T>(std::optional<T>& t) {
bool b; fc::raw::unpack( ds, b );
Expand All @@ -54,6 +78,7 @@ inline DS& operator>>(DS& ds, eosio::chain::eosvmoc::config& cfg) {

template <typename DS>
inline DS& operator<<(DS& ds, const eosio::chain::eosvmoc::config& cfg) {
fc::raw::pack(ds, cfg.whitelisted);
fc::raw::pack(ds, cfg.cache_size);
fc::raw::pack(ds, cfg.threads);
fc::raw::pack(ds, cfg.cpu_limit);
Expand Down
4 changes: 3 additions & 1 deletion libraries/chain/wasm_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ namespace eosio { namespace chain {
const chain::eosvmoc::code_descriptor* cd = nullptr;
chain::eosvmoc::code_cache_base::get_cd_failure failure = chain::eosvmoc::code_cache_base::get_cd_failure::temporary;
try {
const bool high_priority = context.get_receiver().prefix() == chain::config::system_account_name;
// Not high priority with producing a block since we want validators to have a higher probability of having
// already switched to oc by the time the producer has switched to oc.
const bool high_priority = context.is_eos_vm_oc_whitelisted() && context.is_applying_block();
cd = my->eosvmoc->cc.get_descriptor_for_code(high_priority, code_hash, vm_version, context.control.is_write_window(), failure);
if (test_disable_tierup)
cd = nullptr;
Expand Down
35 changes: 20 additions & 15 deletions libraries/chain/webassembly/runtimes/eos-vm-oc/code_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ static_assert(sizeof(code_cache_header) <= header_size, "code_cache_header too b

code_cache_async::code_cache_async(const std::filesystem::path& data_dir, const eosvmoc::config& eosvmoc_config, const chainbase::database& db) :
code_cache_base(data_dir, eosvmoc_config, db),
_result_queue(eosvmoc_config.threads * 2),
_threads(eosvmoc_config.threads)
_result_queue(eosvmoc_config.get_threads() * 2),
_threads(eosvmoc_config.get_threads())
{
FC_ASSERT(_threads, "EOS VM OC requires at least 1 compile thread");

Expand Down Expand Up @@ -126,7 +126,9 @@ const code_descriptor* const code_cache_async::get_descriptor_for_code(bool high
_outstanding_compiles_and_poison.emplace(*nextup, false);
std::vector<wrapped_fd> fds_to_pass;
fds_to_pass.emplace_back(memfd_for_bytearray(codeobject->code));
FC_ASSERT(write_message_with_fds(_compile_monitor_write_socket, compile_wasm_message{ *nextup, _eosvmoc_config }, fds_to_pass), "EOS VM failed to communicate to OOP manager");
auto msg = compile_wasm_message{ *nextup, _eosvmoc_config };
msg.eosvmoc_config.whitelisted = high_priority;
FC_ASSERT(write_message_with_fds(_compile_monitor_write_socket, msg, fds_to_pass), "EOS VM failed to communicate to OOP manager");
--count_processed;
}
_queued_compiles.erase(nextup);
Expand All @@ -148,8 +150,11 @@ const code_descriptor* const code_cache_async::get_descriptor_for_code(bool high
const code_tuple ct = code_tuple{code_id, vm_version};

if(_blacklist.find(ct) != _blacklist.end()) {
failure = get_cd_failure::permanent; // Compile will not start
return nullptr;
if (!high_priority) {
failure = get_cd_failure::permanent; // Compile will not start
return nullptr;
}
_blacklist.erase(ct);
}
if(auto it = _outstanding_compiles_and_poison.find(ct); it != _outstanding_compiles_and_poison.end()) {
failure = get_cd_failure::temporary; // Compile might not be done yet
Expand Down Expand Up @@ -234,13 +239,13 @@ code_cache_base::code_cache_base(const std::filesystem::path& data_dir, const eo

bool created_file = false;
auto create_code_cache_file = [&] {
EOS_ASSERT(eosvmoc_config.cache_size >= allocator_t::get_min_size(total_header_size), database_exception, "configured code cache size is too small");
EOS_ASSERT(eosvmoc_config.get_cache_size() >= allocator_t::get_min_size(total_header_size), database_exception, "configured code cache size is too small");
std::ofstream ofs(_cache_file_path.generic_string(), std::ofstream::trunc);
EOS_ASSERT(ofs.good(), database_exception, "unable to create EOS VM Optimized Compiler code cache");
std::filesystem::resize_file(_cache_file_path, eosvmoc_config.cache_size);
std::filesystem::resize_file(_cache_file_path, eosvmoc_config.get_cache_size());
bip::file_mapping creation_mapping(_cache_file_path.generic_string().c_str(), bip::read_write);
bip::mapped_region creation_region(creation_mapping, bip::read_write);
new (creation_region.get_address()) allocator_t(eosvmoc_config.cache_size, total_header_size);
new (creation_region.get_address()) allocator_t(eosvmoc_config.get_cache_size(), total_header_size);
new ((char*)creation_region.get_address() + header_offset) code_cache_header;
created_file = true;
};
Expand Down Expand Up @@ -275,27 +280,27 @@ code_cache_base::code_cache_base(const std::filesystem::path& data_dir, const eo
set_on_disk_region_dirty(true);

auto existing_file_size = std::filesystem::file_size(_cache_file_path);
if(eosvmoc_config.cache_size > existing_file_size) {
std::filesystem::resize_file(_cache_file_path, eosvmoc_config.cache_size);
if(eosvmoc_config.get_cache_size() > existing_file_size) {
std::filesystem::resize_file(_cache_file_path, eosvmoc_config.get_cache_size());

bip::file_mapping resize_mapping(_cache_file_path.generic_string().c_str(), bip::read_write);
bip::mapped_region resize_region(resize_mapping, bip::read_write);

allocator_t* resize_allocator = reinterpret_cast<allocator_t*>(resize_region.get_address());
resize_allocator->grow(eosvmoc_config.cache_size - existing_file_size);
resize_allocator->grow(eosvmoc_config.get_cache_size() - existing_file_size);
}

_cache_fd = ::open(_cache_file_path.generic_string().c_str(), O_RDWR | O_CLOEXEC);
EOS_ASSERT(_cache_fd >= 0, database_exception, "failure to open code cache");

//load up the previous cache index
char* code_mapping = (char*)mmap(nullptr, eosvmoc_config.cache_size, PROT_READ|PROT_WRITE, MAP_SHARED, _cache_fd, 0);
char* code_mapping = (char*)mmap(nullptr, eosvmoc_config.get_cache_size(), PROT_READ|PROT_WRITE, MAP_SHARED, _cache_fd, 0);
EOS_ASSERT(code_mapping != MAP_FAILED, database_exception, "failure to mmap code cache");

allocator_t* allocator = reinterpret_cast<allocator_t*>(code_mapping);

if(cache_header.serialized_descriptor_index) {
fc::datastream<const char*> ds(code_mapping + cache_header.serialized_descriptor_index, eosvmoc_config.cache_size - cache_header.serialized_descriptor_index);
fc::datastream<const char*> ds(code_mapping + cache_header.serialized_descriptor_index, eosvmoc_config.get_cache_size() - cache_header.serialized_descriptor_index);
unsigned number_entries;
fc::raw::unpack(ds, number_entries);
for(unsigned i = 0; i < number_entries; ++i) {
Expand All @@ -312,9 +317,9 @@ code_cache_base::code_cache_base(const std::filesystem::path& data_dir, const eo

ilog("EOS VM Optimized Compiler code cache loaded with ${c} entries; ${f} of ${t} bytes free", ("c", number_entries)("f", allocator->get_free_memory())("t", allocator->get_size()));
}
munmap(code_mapping, eosvmoc_config.cache_size);
munmap(code_mapping, eosvmoc_config.get_cache_size());

_free_bytes_eviction_threshold = eosvmoc_config.cache_size * .1;
_free_bytes_eviction_threshold = eosvmoc_config.get_cache_size() * .1;

wrapped_fd compile_monitor_conn = get_connection_to_compile_monitor(_cache_fd);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,24 +170,24 @@ void run_compile_trampoline(int fd) {

// enforce cpu limit only when it is set
// (libtester may disable it)
if(conf.cpu_limit) {
struct rlimit cpu_limit = {*conf.cpu_limit, *conf.cpu_limit};
setrlimit(RLIMIT_CPU, &cpu_limit);
auto cpu_limit = conf.get_cpu_limit();
if(cpu_limit) {
struct rlimit rcpu_limit = {*cpu_limit, *cpu_limit};
setrlimit(RLIMIT_CPU, &rcpu_limit);
}

// enforce vm limit only when it is set
// (libtester may disable it)
if(conf.vm_limit) {
struct rlimit vm_limit = {*conf.vm_limit, *conf.vm_limit};
setrlimit(RLIMIT_AS, &vm_limit);
auto vm_limit = conf.get_vm_limit();
if(vm_limit) {
struct rlimit rvm_limit = {*vm_limit, *vm_limit};
setrlimit(RLIMIT_AS, &rvm_limit);
}

struct rlimit core_limits = {0u, 0u};
setrlimit(RLIMIT_CORE, &core_limits);

uint64_t stack_size_limit = conf.stack_size_limit ? *conf.stack_size_limit : std::numeric_limits<uint64_t>::max();
size_t generated_code_size_limit = conf.generated_code_size_limit ? * conf.generated_code_size_limit : std::numeric_limits<size_t>::max();
run_compile(std::move(fds[0]), std::move(fds[1]), stack_size_limit, generated_code_size_limit);
run_compile(std::move(fds[0]), std::move(fds[1]), conf.get_stack_size_limit(), conf.get_generated_code_size_limit());
_exit(0);
}
else if(pid == -1)
Expand Down
2 changes: 1 addition & 1 deletion plugins/chain_plugin/chain_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip
)

#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
("eos-vm-oc-cache-size-mb", bpo::value<uint64_t>()->default_value(eosvmoc::config().cache_size / (1024u*1024u)), "Maximum size (in MiB) of the EOS VM OC code cache")
("eos-vm-oc-cache-size-mb", bpo::value<uint64_t>()->default_value(eosvmoc::config().get_cache_size() / (1024u*1024u)), "Maximum size (in MiB) of the EOS VM OC code cache")
("eos-vm-oc-compile-threads", bpo::value<uint64_t>()->default_value(1u)->notifier([](const auto t) {
if(t == 0) {
elog("eos-vm-oc-compile-threads must be set to a non-zero value");
Expand Down

0 comments on commit 5ae808a

Please sign in to comment.