Skip to content

Commit 37edf92

Browse files
authored
Merge pull request #1447 from AntelopeIO/GH-1441-oc-compile-queue-1.1
[1.1.5] Fix OC scheduling of compiles
2 parents 31c2687 + f6ad137 commit 37edf92

File tree

12 files changed

+80
-63
lines changed

12 files changed

+80
-63
lines changed

libraries/chain/controller.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4920,8 +4920,10 @@ struct controller_impl {
49204920
return wasmif;
49214921
}
49224922

4923-
void code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version, uint32_t block_num) {
4924-
wasmif.code_block_num_last_used(code_hash, vm_type, vm_version, block_num);
4923+
void code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version,
4924+
block_num_type first_used_block_num, block_num_type block_num_last_used)
4925+
{
4926+
wasmif.code_block_num_last_used(code_hash, vm_type, vm_version, first_used_block_num, block_num_last_used);
49254927
}
49264928

49274929
void set_node_finalizer_keys(const bls_pub_priv_key_map_t& finalizer_keys) {
@@ -6127,8 +6129,9 @@ bool controller::is_write_window() const {
61276129
return my->is_write_window();
61286130
}
61296131

6130-
void controller::code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version, uint32_t block_num) {
6131-
return my->code_block_num_last_used(code_hash, vm_type, vm_version, block_num);
6132+
void controller::code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version,
6133+
block_num_type first_used_block_num, block_num_type block_num_last_used) {
6134+
return my->code_block_num_last_used(code_hash, vm_type, vm_version, first_used_block_num, block_num_last_used);
61326135
}
61336136

61346137
void controller::set_node_finalizer_keys(const bls_pub_priv_key_map_t& finalizer_keys) {

libraries/chain/eosio_contract.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,8 @@ void apply_eosio_setcode(apply_context& context) {
160160
old_size = (int64_t)old_code_entry.code.size() * config::setcode_ram_bytes_multiplier;
161161
if( old_code_entry.code_ref_count == 1 ) {
162162
db.remove(old_code_entry);
163-
context.control.code_block_num_last_used(account.code_hash, account.vm_type, account.vm_version, context.control.head().block_num() + 1);
163+
context.control.code_block_num_last_used(account.code_hash, account.vm_type, account.vm_version,
164+
old_code_entry.first_block_used, context.control.head().block_num() + 1);
164165
} else {
165166
db.modify(old_code_entry, [](code_object& o) {
166167
--o.code_ref_count;

libraries/chain/include/eosio/chain/controller.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,8 @@ namespace eosio::chain {
489489
void set_to_write_window();
490490
void set_to_read_window();
491491
bool is_write_window() const;
492-
void code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version, uint32_t block_num);
492+
void code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version,
493+
block_num_type first_used_block_num, block_num_type block_num_last_used);
493494
void set_node_finalizer_keys(const bls_pub_priv_key_map_t& finalizer_keys);
494495

495496
// is the bls key a registered finalizer key of this node, thread safe

libraries/chain/include/eosio/chain/wasm_interface.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ namespace eosio { namespace chain {
6868
static void validate(const controller& control, const bytes& code);
6969

7070
//indicate that a particular code probably won't be used after given block_num
71-
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);
71+
void code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version,
72+
block_num_type first_used_block_num, block_num_type last_used_block_num);
7273

7374
//indicate the current LIB. evicts old cache entries
7475
void current_lib(const uint32_t lib);

libraries/chain/include/eosio/chain/wasm_interface_private.hpp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,16 +207,32 @@ struct eosvmoc_tier {
207207
return it != wasm_instantiation_cache.end();
208208
}
209209

210-
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) {
210+
void code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version,
211+
block_num_type first_used_block_num, block_num_type block_num_last_used)
212+
{
211213
// The caller of this method apply_eosio_setcode has asserted that
212214
// the transaction is not read-only, implying we are
213215
// in write window. Read-only threads are not running.
214216
// Safe to update the cache without locking.
215217
wasm_cache_index::iterator it = wasm_instantiation_cache.find(boost::make_tuple(code_hash, vm_type, vm_version));
216-
if(it != wasm_instantiation_cache.end())
217-
wasm_instantiation_cache.modify(it, [block_num](wasm_cache_entry& e) {
218-
e.last_block_num_used = block_num;
219-
});
218+
if(it != wasm_instantiation_cache.end()) {
219+
if (first_used_block_num == block_num_last_used) {
220+
// First used and no longer needed in the same block, erase immediately, do not wait for LIB.
221+
// Since created and destroyed in the same block, likely will not be needed in a forked block.
222+
// Prevents many setcodes in the same block using up space in the cache.
223+
wasm_instantiation_cache.erase(it);
224+
} else {
225+
wasm_instantiation_cache.modify(it, [block_num_last_used](wasm_cache_entry& e) {
226+
e.last_block_num_used = block_num_last_used;
227+
});
228+
}
229+
}
230+
231+
#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED
232+
// see comment above
233+
if (first_used_block_num == block_num_last_used && eosvmoc)
234+
eosvmoc->cc.free_code(code_hash, vm_version);
235+
#endif
220236
}
221237

222238
// reports each code_hash and vm_version that will be erased to callback

libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/code_cache.hpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,21 @@
55
#include <boost/multi_index_container.hpp>
66
#include <boost/multi_index/hashed_index.hpp>
77
#include <boost/multi_index/sequenced_index.hpp>
8-
#include <boost/multi_index/composite_key.hpp>
98
#include <boost/multi_index/key_extractors.hpp>
109
#include <boost/multi_index/member.hpp>
11-
#include <boost/lockfree/spsc_queue.hpp>
10+
#include <boost/lockfree/queue.hpp>
1211

1312
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
1413
#include <boost/asio/local/datagram_protocol.hpp>
1514

1615
#include <fc/crypto/sha256.hpp>
1716

17+
#include <atomic>
1818
#include <thread>
19+
#include <tuple>
20+
#include <unordered_map>
21+
#include <unordered_set>
22+
#include <filesystem>
1923

2024
namespace eosio { namespace chain { namespace eosvmoc {
2125

@@ -77,12 +81,12 @@ class code_cache_base {
7781

7882
struct queued_compile_entry {
7983
compile_wasm_message msg;
80-
std::vector<wrapped_fd> fds_to_pass;
84+
std::vector<char> code;
8185

8286
const digest_type& code_id() const { return msg.code.code_id; }
8387
};
8488
//these are really only useful to the async code cache, but keep them here so free_code can be shared
85-
using queued_compilies_t = boost::multi_index_container<
89+
using queued_compiles_t = boost::multi_index_container<
8690
queued_compile_entry,
8791
indexed_by<
8892
sequenced<>,
@@ -91,7 +95,7 @@ class code_cache_base {
9195
>
9296
>;
9397
std::mutex _mtx;
94-
queued_compilies_t _queued_compiles; // protected by _mtx
98+
queued_compiles_t _queued_compiles; // protected by _mtx
9599
std::unordered_map<digest_type, bool> _outstanding_compiles_and_poison; // protected by _mtx
96100
std::atomic<size_t> _outstanding_compiles{0};
97101

@@ -123,14 +127,14 @@ class code_cache_async : public code_cache_base {
123127
private:
124128
compile_complete_callback _compile_complete_func; // called from async thread, provides executing_action_id
125129
std::thread _monitor_reply_thread;
126-
boost::lockfree::spsc_queue<wasm_compilation_result_message> _result_queue;
130+
boost::lockfree::queue<wasm_compilation_result_message> _result_queue;
127131
std::unordered_set<digest_type> _blacklist;
128132
size_t _threads;
129133

130134
void wait_on_compile_monitor_message();
131135
std::tuple<size_t, size_t> consume_compile_thread_queue();
132136
void process_queued_compiles();
133-
void write_message(const digest_type& code_id, const eosvmoc_message& message, const std::vector<wrapped_fd>& fds);
137+
void write_message(const digest_type& code_id, const eosvmoc_message& message, std::span<wrapped_fd> fds);
134138

135139
};
136140

libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/ipc_helpers.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ class wrapped_fd {
4747

4848
std::tuple<bool, eosvmoc_message, std::vector<wrapped_fd>> read_message_with_fds(boost::asio::local::datagram_protocol::socket& s);
4949
std::tuple<bool, eosvmoc_message, std::vector<wrapped_fd>> read_message_with_fds(int fd);
50-
bool write_message_with_fds(boost::asio::local::datagram_protocol::socket& s, const eosvmoc_message& message, const std::vector<wrapped_fd>& fds = std::vector<wrapped_fd>());
51-
bool write_message_with_fds(int fd_to_send_to, const eosvmoc_message& message, const std::vector<wrapped_fd>& fds = std::vector<wrapped_fd>());
50+
bool write_message_with_fds(boost::asio::local::datagram_protocol::socket& s, const eosvmoc_message& message, std::span<wrapped_fd> fds = {});
51+
bool write_message_with_fds(int fd_to_send_to, const eosvmoc_message& message, std::span<wrapped_fd> fds = {});
5252

5353
template<typename T>
5454
wrapped_fd memfd_for_bytearray(const T& bytes) {

libraries/chain/wasm_interface.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,10 @@ namespace eosio { namespace chain {
7777
//Hard: Kick off instantiation in a separate thread at this location
7878
}
7979

80-
void wasm_interface::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) {
81-
my->code_block_num_last_used(code_hash, vm_type, vm_version, block_num);
80+
void wasm_interface::code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version,
81+
block_num_type first_used_block_num, block_num_type block_num_last_used)
82+
{
83+
my->code_block_num_last_used(code_hash, vm_type, vm_version, first_used_block_num, block_num_last_used);
8284
}
8385

8486
void wasm_interface::current_lib(const uint32_t lib) {

libraries/chain/webassembly/runtimes/eos-vm-oc/code_cache.cpp

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#include <fc/log/logger_config.hpp> //set_thread_name
2-
31
#include <eosio/chain/webassembly/eos-vm-oc/code_cache.hpp>
42
#include <eosio/chain/webassembly/eos-vm-oc/config.hpp>
53
#include <eosio/chain/webassembly/common.hpp>
@@ -9,17 +7,11 @@
97
#include <eosio/chain/webassembly/eos-vm-oc/compile_monitor.hpp>
108
#include <eosio/chain/exceptions.hpp>
119

10+
#include <fc/log/logger_config.hpp> //set_thread_name
11+
12+
#include <fstream>
1213
#include <unistd.h>
13-
#include <sys/syscall.h>
1414
#include <sys/mman.h>
15-
#include <linux/memfd.h>
16-
17-
#include "IR/Module.h"
18-
#include "IR/Validate.h"
19-
#include "WASM/WASM.h"
20-
#include "LLVMJIT.h"
21-
22-
using namespace IR;
2315

2416
namespace eosio { namespace chain { namespace eosvmoc {
2517

@@ -81,7 +73,8 @@ void code_cache_async::wait_on_compile_monitor_message() {
8173
--_outstanding_compiles;
8274

8375
const auto& msg = std::get<wasm_compilation_result_message>(message);
84-
_result_queue.push(msg);
76+
bool p = _result_queue.push(msg);
77+
assert(p);
8578

8679
_compile_complete_func(_ctx, msg.code.code_id, msg.queued_time);
8780

@@ -92,7 +85,7 @@ void code_cache_async::wait_on_compile_monitor_message() {
9285
}
9386

9487
//call with _mtx locked
95-
void code_cache_async::write_message(const digest_type& code_id, const eosvmoc_message& message, const std::vector<wrapped_fd>& fds) {
88+
void code_cache_async::write_message(const digest_type& code_id, const eosvmoc_message& message, std::span<wrapped_fd> fds) {
9689
_outstanding_compiles_and_poison.emplace(code_id, false);
9790
++_outstanding_compiles;
9891
if (!write_message_with_fds(_compile_monitor_write_socket, message, fds)) {
@@ -106,7 +99,8 @@ void code_cache_async::process_queued_compiles() {
10699
while (_outstanding_compiles < _threads && !_queued_compiles.empty()) {
107100
auto nextup = _queued_compiles.begin();
108101

109-
write_message(nextup->code_id(), nextup->msg, nextup->fds_to_pass);
102+
auto fd = memfd_for_bytearray(nextup->code);
103+
write_message(nextup->code_id(), nextup->msg, std::span<wrapped_fd>{&fd, 1});
110104

111105
_queued_compiles.erase(nextup);
112106
}
@@ -116,7 +110,9 @@ void code_cache_async::process_queued_compiles() {
116110
//number processed, bytes available (only if number processed > 0)
117111
std::tuple<size_t, size_t> code_cache_async::consume_compile_thread_queue() {
118112
std::unique_lock g(_mtx);
119-
auto outstanding_compiles = _outstanding_compiles_and_poison; // will always be small, <= _threads
113+
// will be relatively small, ~ _threads. Can be larger than _threads if multiple compiles finish before
114+
// consume_compile_thread_queue() is called on the main thread
115+
auto outstanding_compiles = _outstanding_compiles_and_poison;
120116
g.unlock();
121117

122118
std::vector<digest_type> erased;
@@ -142,8 +138,10 @@ std::tuple<size_t, size_t> code_cache_async::consume_compile_thread_queue() {
142138
});
143139

144140
g.lock();
145-
for (const auto& e : erased)
146-
_outstanding_compiles_and_poison.erase(e);
141+
for (const auto& e : erased) {
142+
auto c = _outstanding_compiles_and_poison.erase(e);
143+
assert(c > 0);
144+
}
147145
g.unlock();
148146

149147
return {gotsome, bytes_remaining};
@@ -163,8 +161,7 @@ code_cache_async::get_descriptor_for_code(mode m, const digest_type& code_id, co
163161
}
164162

165163
//check for entry in cache
166-
code_cache_index::index<by_hash>::type::iterator it = _cache_index.get<by_hash>().find(code_id);
167-
if(it != _cache_index.get<by_hash>().end()) {
164+
if(auto it = _cache_index.get<by_hash>().find(code_id); it != _cache_index.get<by_hash>().end()) {
168165
if (m.write_window)
169166
_cache_index.relocate(_cache_index.begin(), _cache_index.project<0>(it));
170167
return &*it;
@@ -205,20 +202,20 @@ code_cache_async::get_descriptor_for_code(mode m, const digest_type& code_id, co
205202
.queued_time = fc::time_point::now(),
206203
.limits = !m.whitelisted ? _eosvmoc_config.non_whitelisted_limits : std::optional<subjective_compile_limits>{}
207204
};
208-
std::vector<wrapped_fd> fds_to_pass;
209-
fds_to_pass.emplace_back(memfd_for_bytearray(codeobject->code));
210205

211206
g.lock();
212-
if(_outstanding_compiles_and_poison.size() >= _threads) {
207+
if(_outstanding_compiles >= _threads) {
208+
std::vector<char> code{codeobject->code.begin(), codeobject->code.end()};
213209
if (m.high_priority)
214-
_queued_compiles.emplace_front(std::move(msg), std::move(fds_to_pass));
210+
_queued_compiles.emplace_front(std::move(msg), std::move(code));
215211
else
216-
_queued_compiles.emplace_back(std::move(msg), std::move(fds_to_pass));
212+
_queued_compiles.emplace_back(std::move(msg), std::move(code));
217213
failure = get_cd_failure::temporary; // Compile might not be done yet
218214
return nullptr;
219215
}
220216

221-
write_message(code_id, msg, fds_to_pass);
217+
auto fd = memfd_for_bytearray(codeobject->code);
218+
write_message(code_id, msg, std::span<wrapped_fd>{&fd, 1});
222219
failure = get_cd_failure::temporary; // Compile might not be done yet
223220
return nullptr;
224221
}
@@ -247,15 +244,13 @@ const code_descriptor* const code_cache_sync::get_descriptor_for_code_sync(mode
247244
if(!codeobject) //should be impossible right?
248245
return nullptr;
249246

250-
std::vector<wrapped_fd> fds_to_pass;
251-
fds_to_pass.emplace_back(memfd_for_bytearray(codeobject->code));
252-
253247
auto msg = compile_wasm_message{
254248
.code = { code_id, vm_version },
255249
.queued_time = fc::time_point{}, // could use now() if compile time measurement desired
256250
.limits = !m.whitelisted ? _eosvmoc_config.non_whitelisted_limits : std::optional<subjective_compile_limits>{}
257251
};
258-
write_message_with_fds(_compile_monitor_write_socket, msg, fds_to_pass);
252+
auto fd = memfd_for_bytearray(codeobject->code);
253+
write_message_with_fds(_compile_monitor_write_socket, msg, std::span<wrapped_fd>{&fd, 1});
259254
auto [success, message, fds] = read_message_with_fds(_compile_monitor_read_socket);
260255
EOS_ASSERT(success, wasm_execution_error, "failed to read response from monitor process");
261256
EOS_ASSERT(std::holds_alternative<wasm_compilation_result_message>(message), wasm_execution_error, "unexpected response from monitor process");

libraries/chain/webassembly/runtimes/eos-vm-oc/compile_monitor.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,7 @@ struct compile_monitor_session {
9696
socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, socks);
9797
local::datagram_protocol::socket response_socket(_ctx);
9898
response_socket.assign(local::datagram_protocol(), socks[0]);
99-
std::vector<wrapped_fd> fds_pass_to_trampoline;
100-
fds_pass_to_trampoline.emplace_back(socks[1]);
101-
fds_pass_to_trampoline.emplace_back(std::move(wasm_code));
99+
std::array<wrapped_fd, 2> fds_pass_to_trampoline { socks[1], std::move(wasm_code) };
102100

103101
eosvmoc_message trampoline_compile_request = msg;
104102
if(write_message_with_fds(_trampoline_socket, trampoline_compile_request, fds_pass_to_trampoline) == false) {
@@ -324,9 +322,7 @@ wrapped_fd get_connection_to_compile_monitor(int cache_fd) {
324322
FC_ASSERT(dup_of_cache_fd != -1, "failed to dup cache_fd");
325323
wrapped_fd dup_cache_fd(dup_of_cache_fd);
326324

327-
std::vector<wrapped_fd> fds_to_pass;
328-
fds_to_pass.emplace_back(std::move(socket_to_hand_to_monitor_session));
329-
fds_to_pass.emplace_back(std::move(dup_cache_fd));
325+
std::array<wrapped_fd, 2> fds_to_pass { std::move(socket_to_hand_to_monitor_session), std::move(dup_cache_fd) };
330326
write_message_with_fds(the_compile_monitor_trampoline.compile_manager_fd, initialize_message(), fds_to_pass);
331327

332328
auto [success, message, fds] = read_message_with_fds(the_compile_monitor_trampoline.compile_manager_fd);

0 commit comments

Comments
 (0)