Skip to content

Commit

Permalink
Parachain instance cache warmup (#1851)
Browse files Browse the repository at this point in the history
* Added precompilation of parachain modules -- at node startup, parachain validation codes are pulled from the state of the last finalized block and compiled into wasm modules, which are stored in the RuntimeInstancesPool, a cache used by pvf executor.

* Add test for multithreaded module compilation

* Disable parachain precompilation for non-validating nodes

* Make pools_mtx non-shared

* build fix

Signed-off-by: iceseer <[email protected]>

* Fix errors from master

---------

Signed-off-by: iceseer <[email protected]>
Co-authored-by: iceseer <[email protected]>
Co-authored-by: Alexander Lednev <[email protected]>
  • Loading branch information
3 people authored Nov 24, 2023
1 parent 52ebab6 commit 62b9a92
Show file tree
Hide file tree
Showing 84 changed files with 924 additions and 290 deletions.
3 changes: 3 additions & 0 deletions cmake/clang-format.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ if(NOT CLANG_FORMAT_BIN)
OUTPUT_VARIABLE DEFAULT_CLANG_FORMAT_VERSION
)
math(EXPR DEFAULT_CLANG_FORMAT_VERSION "0 + 0${DEFAULT_CLANG_FORMAT_VERSION}")
if (${DEFAULT_CLANG_FORMAT_VERSION} GREATER ${RECOMMENDED_CLANG_FORMAT_VERSION})
return()
endif()
# Try to find newest version
foreach(CLANG_FORMAT_VERSION RANGE ${RECOMMENDED_CLANG_FORMAT_VERSION} ${DEFAULT_CLANG_FORMAT_VERSION} -1)
find_program(CLANG_FORMAT_BIN_ NAMES clang-format-${CLANG_FORMAT_VERSION})
Expand Down
34 changes: 34 additions & 0 deletions cmake/toolchain/compiler/gcc-13.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
if(DEFINED POLLY_COMPILER_GCC_13_CMAKE_)
return()
else()
set(POLLY_COMPILER_GCC_13_CMAKE_ 1)
endif()

find_program(CMAKE_C_COMPILER gcc-13)
find_program(CMAKE_CXX_COMPILER g++-13)

if(NOT CMAKE_C_COMPILER)
fatal_error("gcc-13 not found")
endif()

if(NOT CMAKE_CXX_COMPILER)
fatal_error("g++-13 not found")
endif()

set(
CMAKE_C_COMPILER
"${CMAKE_C_COMPILER}"
CACHE
STRING
"C compiler"
FORCE
)

set(
CMAKE_CXX_COMPILER
"${CMAKE_CXX_COMPILER}"
CACHE
STRING
"C++ compiler"
FORCE
)
2 changes: 2 additions & 0 deletions cmake/toolchain/gcc-13_cxx20.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include(${CMAKE_CURRENT_LIST_DIR}/compiler/gcc-13.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/cxx20.cmake)
2 changes: 2 additions & 0 deletions core/application/app_configuration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ namespace kagome::application {
virtual bool purgeWavmCache() const = 0;

virtual uint32_t parachainRuntimeInstanceCacheSize() const = 0;
virtual uint32_t parachainPrecompilationThreadNum() const = 0;
virtual bool shouldPrecompileParachainModules() const = 0;

enum class OffchainWorkerMode { WhenValidating, Always, Never };
/**
Expand Down
51 changes: 25 additions & 26 deletions core/application/app_state_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,26 @@

namespace kagome::application {

// concepts that check if an object has a method that is called by app state
// manager. Deliberately avoid checking that the method returns bool,
// because if there's a method with an appropriate name, and it doesn't return
// bool, we want it to be a compile error instead of silently ignoring it
// because the concept is not satisfied.
template <typename T>
concept AppStateInjectable = requires(T& t) { t.inject(); };
template <typename T>
concept AppStatePreparable = requires(T& t) { t.prepare(); };
template <typename T>
concept AppStateStartable = requires(T& t) { t.start(); };
template <typename T>
concept AppStateStoppable = requires(T& t) { t.stop(); };

// if an object is registered with AppStateManager but has no method
// that is called by AppStateManager, there's probably something wrong
template <typename T>
concept AppStateControllable = AppStatePreparable<T> || AppStateInjectable<T>
|| AppStateStoppable<T> || AppStateStartable<T>;

class AppStateManager : public std::enable_shared_from_this<AppStateManager> {
public:
using OnInject = std::function<bool()>;
Expand Down Expand Up @@ -55,45 +75,24 @@ namespace kagome::application {
*/
virtual void atShutdown(OnShutdown &&cb) = 0;

private:
template <typename C, typename = int>
struct HasMethodInject : std::false_type {};
template <typename C>
struct HasMethodInject<C, decltype(&C::inject, 0)> : std::true_type {};

template <typename C, typename = int>
struct HasMethodPrepare : std::false_type {};
template <typename C>
struct HasMethodPrepare<C, decltype(&C::prepare, 0)> : std::true_type {};

template <typename C, typename = int>
struct HasMethodStart : std::false_type {};
template <typename C>
struct HasMethodStart<C, decltype(&C::start, 0)> : std::true_type {};

template <typename C, typename = int>
struct HasMethodStop : std::false_type {};
template <typename C>
struct HasMethodStop<C, decltype(&C::stop, 0)> : std::true_type {};

public:
/**
* @brief Registration special methods (if any) of object as handlers
* for stages of application life-cycle
* @param entity is registered entity
*/
template <typename Controlled>
template <AppStateControllable Controlled>
void takeControl(Controlled &entity) {
if constexpr (HasMethodInject<Controlled>::value) {
if constexpr (AppStateInjectable<Controlled>) {
atInject([&entity]() -> bool { return entity.inject(); });
}
if constexpr (HasMethodPrepare<Controlled>::value) {
if constexpr (AppStatePreparable<Controlled>) {
atPrepare([&entity]() -> bool { return entity.prepare(); });
}
if constexpr (HasMethodStart<Controlled>::value) {
if constexpr (AppStateStartable<Controlled>) {
atLaunch([&entity]() -> bool { return entity.start(); });
}
if constexpr (HasMethodStop<Controlled>::value) {
if constexpr (AppStateStoppable<Controlled>) {
atShutdown([&entity]() -> void { return entity.stop(); });
}
}
Expand Down
15 changes: 15 additions & 0 deletions core/application/impl/app_configuration_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,10 @@ namespace kagome::application {
("parachain-runtime-instance-cache-size",
po::value<uint32_t>()->default_value(def_parachain_runtime_instance_cache_size),
"Number of parachain runtime instances to keep cached")
("no-precompile-parachain-modules", po::bool_switch(), "Don't precompile parachain runtime modules at node startup")
("parachain-precompilation-thread-num",
po::value<uint32_t>()->default_value(parachain_precompilation_thread_num_),
"Number of threads that precompile parachain runtime modules at node startup")
;
po::options_description benchmark_desc("Benchmark options");
benchmark_desc.add_options()
Expand Down Expand Up @@ -1402,6 +1406,17 @@ namespace kagome::application {
parachain_runtime_instance_cache_size_ = *arg;
}

if (!find_argument(vm, "validator")
|| find_argument(vm, "no-precompile-parachain-modules")) {
should_precompile_parachain_modules_ = false;
}

if (auto arg =
find_argument<uint32_t>(vm, "parachain-precompilation-thread-num");
arg.has_value()) {
parachain_precompilation_thread_num_ = *arg;
}

bool offchain_worker_value_error = false;
find_argument<std::string>(
vm,
Expand Down
11 changes: 11 additions & 0 deletions core/application/impl/app_configuration_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace rapidjson {
#include <array>
#include <cstdio>
#include <memory>
#include <thread>

#include "log/logger.hpp"

Expand Down Expand Up @@ -169,6 +170,13 @@ namespace kagome::application {
uint32_t parachainRuntimeInstanceCacheSize() const override {
return parachain_runtime_instance_cache_size_;
}
uint32_t parachainPrecompilationThreadNum() const override {
return parachain_precompilation_thread_num_;
}

bool shouldPrecompileParachainModules() const override {
return should_precompile_parachain_modules_;
}

OffchainWorkerMode offchainWorkerMode() const override {
return offchain_worker_mode_;
Expand Down Expand Up @@ -362,6 +370,9 @@ namespace kagome::application {
std::optional<BenchmarkConfigSection> benchmark_config_;
AllowUnsafeRpc allow_unsafe_rpc_ = AllowUnsafeRpc::kAuto;
uint32_t parachain_runtime_instance_cache_size_ = 100;
uint32_t parachain_precompilation_thread_num_ =
std::thread::hardware_concurrency() / 2;
bool should_precompile_parachain_modules_{true};
};

} // namespace kagome::application
Expand Down
4 changes: 2 additions & 2 deletions core/blockchain/impl/block_tree_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1044,10 +1044,10 @@ namespace kagome::blockchain {
auto header_res = p.header_repo_->getBlockHeader(hash);
if (header_res.has_error()) {
if (chain.empty()) {
log_->error("cannot retrieve block with hash {}: {}",
log_->error("Cannot retrieve block with hash {}: {}",
hash,
header_res.error());
return BlockTreeError::HEADER_NOT_FOUND;
return header_res.error();
}
break;
}
Expand Down
2 changes: 1 addition & 1 deletion core/blockchain/indexer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ namespace kagome::blockchain {
return outcome::success();
}

Descent descend(const primitives::BlockInfo &from) const {
Descent startDescentFrom(const primitives::BlockInfo &from) const {
return {block_tree_, from};
}

Expand Down
6 changes: 3 additions & 3 deletions core/common/empty.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@
namespace kagome {

/// Special zero-size-type for some things
/// (e.g., unsupported, experimental or empty).
/// (e.g. unsupported, experimental or empty).
struct Empty {
inline constexpr bool operator==(const Empty &) const {
return true;
}

template <class Stream>
friend inline auto &operator<<(Stream &s, const Empty &) {
friend inline Stream &operator<<(Stream &s, const Empty &) {
return s;
}

template <class Stream>
friend inline auto &operator>>(Stream &s, const Empty &) {
friend inline Stream &operator>>(Stream &s, const Empty &) {
return s;
}
};
Expand Down
9 changes: 6 additions & 3 deletions core/common/monadic_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,12 @@ namespace kagome::common {
* error.
*/
template <typename T,
typename E,
typename F,
typename R = std::invoke_result_t<F, const T &>>
outcome::result<R> map_result(const outcome::result<T> &res, const F &f) {
outcome::result<R, E> map_result(const outcome::result<T, E> &res, const F &f) {
if (res.has_value()) {
return outcome::result<R>{f(res.value())};
return outcome::result<R, E>{f(res.value())};
}
return res.as_failure();
}
Expand All @@ -63,7 +64,9 @@ namespace kagome::common {
* outcome::result contains a value. Otherwise, just returns the contained
* error.
*/
template <typename T, typename F, typename R = std::invoke_result_t<F, T &&>>
template <typename T,
std::invocable<T &&> F,
typename R = std::invoke_result_t<F, T &&>>
outcome::result<R> map_result(outcome::result<T> &&res, const F &f) {
if (res.has_value()) {
return outcome::result<R>{f(std::move(res.value()))};
Expand Down
2 changes: 1 addition & 1 deletion core/common/visitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,4 @@ namespace kagome {
constexpr decltype(auto) match_in_place(T &&t, Fs &&...fs) {
return match(std::forward<T>(t), make_visitor(std::forward<Fs>(fs)...));
}
} // namespace kagome
} // namespace kagome::common
1 change: 0 additions & 1 deletion core/consensus/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,3 @@ target_link_libraries(consensus INTERFACE
grandpa
)
kagome_install(consensus)
kagome_clear_objects(consensus)
1 change: 1 addition & 0 deletions core/consensus/babe/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ target_link_libraries(babe
consensus_common
)
kagome_install(babe)
kagome_clear_objects(babe)
2 changes: 1 addition & 1 deletion core/consensus/babe/impl/babe_config_repository_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ namespace kagome::consensus::babe {
BabeConfigRepositoryImpl::config(Indexer &indexer_,
const primitives::BlockInfo &block,
bool next_epoch) const {
auto descent = indexer_.descend(block);
auto descent = indexer_.startDescentFrom(block);
outcome::result<void> cb_res = outcome::success();
auto cb = [&](std::optional<primitives::BlockInfo> prev,
size_t i_first,
Expand Down
16 changes: 1 addition & 15 deletions core/consensus/grandpa/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,8 @@ add_library(grandpa
voting_round_error.cpp
)
target_link_libraries(grandpa
# mp_utils
# ed25519_types
# Boost::boost
# schnorrkel_crust::schnorrkel_crust
# transaction_pool_error
# hasher
# vrf_provider
logger
# scale::scale
# primitives
# blob
# outcome
# p2p::p2p_peer_id
# storage
metrics
# blockchain
# telemetry
)
kagome_install(grandpa)
kagome_clear_objects(grandpa)
2 changes: 1 addition & 1 deletion core/consensus/grandpa/impl/authority_manager_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ namespace kagome::consensus::grandpa {
outcome::result<std::shared_ptr<const AuthoritySet>>
AuthorityManagerImpl::authoritiesOutcome(const primitives::BlockInfo &block,
bool next) const {
auto descent = indexer_.descend(block);
auto descent = indexer_.startDescentFrom(block);
outcome::result<void> cb_res = outcome::success();
auto cb = [&](std::optional<primitives::BlockInfo> prev,
size_t i_first,
Expand Down
3 changes: 3 additions & 0 deletions core/consensus/timeline/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,8 @@ add_library(timeline
)
target_link_libraries(timeline
logger
telemetry
network
)
kagome_install(timeline)
kagome_clear_objects(timeline)
4 changes: 2 additions & 2 deletions core/host_api/impl/storage_extension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#include "host_api/impl/storage_util.hpp"
#include "log/formatters/optional.hpp"
#include "log/trace_macros.hpp"
#include "runtime/common/runtime_transaction_error.hpp"
#include "runtime/common/runtime_execution_error.hpp"
#include "runtime/memory_provider.hpp"
#include "runtime/ptr_size.hpp"
#include "runtime/trie_storage_provider.hpp"
Expand Down Expand Up @@ -42,7 +42,7 @@ namespace kagome::host_api {
if (auto res = storage_provider_->rollbackTransaction();
res.has_error()) {
if (res.error()
!= runtime::RuntimeTransactionError::NO_TRANSACTIONS_WERE_STARTED) {
!= runtime::RuntimeExecutionError::NO_TRANSACTIONS_WERE_STARTED) {
logger_->error(res.error());
}
break;
Expand Down
Loading

0 comments on commit 62b9a92

Please sign in to comment.