mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-19 13:31:04 +00:00
Make wasm runtime cache size configurable (#10177)
* Make wasm runtime cache size configurable * apply review comments * remove VersionedRuntimeValue * fix compilation * VersionedRuntime: replace clone by Arc * fmt * fix warnings * fix tests compilation * fmt
This commit is contained in:
Generated
+1
@@ -8035,6 +8035,7 @@ dependencies = [
|
|||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libsecp256k1",
|
"libsecp256k1",
|
||||||
"log 0.4.14",
|
"log 0.4.14",
|
||||||
|
"lru 0.6.6",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"parking_lot 0.11.1",
|
"parking_lot 0.11.1",
|
||||||
"paste 1.0.6",
|
"paste 1.0.6",
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ pub fn new_partial(
|
|||||||
config.wasm_method,
|
config.wasm_method,
|
||||||
config.default_heap_pages,
|
config.default_heap_pages,
|
||||||
config.max_runtime_instances,
|
config.max_runtime_instances,
|
||||||
|
config.runtime_cache_size,
|
||||||
);
|
);
|
||||||
|
|
||||||
let (client, backend, keystore_container, task_manager) =
|
let (client, backend, keystore_container, task_manager) =
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase {
|
|||||||
tracing_targets: None,
|
tracing_targets: None,
|
||||||
tracing_receiver: Default::default(),
|
tracing_receiver: Default::default(),
|
||||||
max_runtime_instances: 8,
|
max_runtime_instances: 8,
|
||||||
|
runtime_cache_size: 2,
|
||||||
announce_block: true,
|
announce_block: true,
|
||||||
base_path: Some(base_path),
|
base_path: Some(base_path),
|
||||||
informant_output_format: Default::default(),
|
informant_output_format: Default::default(),
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase {
|
|||||||
tracing_targets: None,
|
tracing_targets: None,
|
||||||
tracing_receiver: Default::default(),
|
tracing_receiver: Default::default(),
|
||||||
max_runtime_instances: 8,
|
max_runtime_instances: 8,
|
||||||
|
runtime_cache_size: 2,
|
||||||
announce_block: true,
|
announce_block: true,
|
||||||
base_path: Some(base_path),
|
base_path: Some(base_path),
|
||||||
informant_output_format: Default::default(),
|
informant_output_format: Default::default(),
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ pub fn new_partial(
|
|||||||
config.wasm_method,
|
config.wasm_method,
|
||||||
config.default_heap_pages,
|
config.default_heap_pages,
|
||||||
config.max_runtime_instances,
|
config.max_runtime_instances,
|
||||||
|
config.runtime_cache_size,
|
||||||
);
|
);
|
||||||
|
|
||||||
let (client, backend, keystore_container, task_manager) =
|
let (client, backend, keystore_container, task_manager) =
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ fn bench_execute_block(c: &mut Criterion) {
|
|||||||
ExecutionMethod::Wasm(wasm_method) => (false, wasm_method),
|
ExecutionMethod::Wasm(wasm_method) => (false, wasm_method),
|
||||||
};
|
};
|
||||||
|
|
||||||
let executor = NativeElseWasmExecutor::new(wasm_method, None, 8);
|
let executor = NativeElseWasmExecutor::new(wasm_method, None, 8, 2);
|
||||||
let runtime_code = RuntimeCode {
|
let runtime_code = RuntimeCode {
|
||||||
code_fetcher: &sp_core::traits::WrappedRuntimeCode(compact_code_unwrap().into()),
|
code_fetcher: &sp_core::traits::WrappedRuntimeCode(compact_code_unwrap().into()),
|
||||||
hash: vec![1, 2, 3],
|
hash: vec![1, 2, 3],
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ pub fn from_block_number(n: u32) -> Header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn executor() -> NativeElseWasmExecutor<ExecutorDispatch> {
|
pub fn executor() -> NativeElseWasmExecutor<ExecutorDispatch> {
|
||||||
NativeElseWasmExecutor::new(WasmExecutionMethod::Interpreted, None, 8)
|
NativeElseWasmExecutor::new(WasmExecutionMethod::Interpreted, None, 8, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn executor_call<
|
pub fn executor_call<
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ impl InspectCmd {
|
|||||||
config.wasm_method,
|
config.wasm_method,
|
||||||
config.default_heap_pages,
|
config.default_heap_pages,
|
||||||
config.max_runtime_instances,
|
config.max_runtime_instances,
|
||||||
|
config.runtime_cache_size,
|
||||||
);
|
);
|
||||||
|
|
||||||
let client = new_full_client::<B, RA, _>(&config, None, executor)?;
|
let client = new_full_client::<B, RA, _>(&config, None, executor)?;
|
||||||
|
|||||||
@@ -400,7 +400,7 @@ impl BenchDb {
|
|||||||
let backend = sc_service::new_db_backend(db_config).expect("Should not fail");
|
let backend = sc_service::new_db_backend(db_config).expect("Should not fail");
|
||||||
let client = sc_service::new_client(
|
let client = sc_service::new_client(
|
||||||
backend.clone(),
|
backend.clone(),
|
||||||
NativeElseWasmExecutor::new(WasmExecutionMethod::Compiled, None, 8),
|
NativeElseWasmExecutor::new(WasmExecutionMethod::Compiled, None, 8, 2),
|
||||||
&keyring.generate_genesis(),
|
&keyring.generate_genesis(),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
|||||||
@@ -238,6 +238,10 @@ pub struct RunCmd {
|
|||||||
#[structopt(long)]
|
#[structopt(long)]
|
||||||
pub max_runtime_instances: Option<usize>,
|
pub max_runtime_instances: Option<usize>,
|
||||||
|
|
||||||
|
/// Maximum number of different runtimes that can be cached.
|
||||||
|
#[structopt(long, default_value = "2")]
|
||||||
|
pub runtime_cache_size: u8,
|
||||||
|
|
||||||
/// Run a temporary node.
|
/// Run a temporary node.
|
||||||
///
|
///
|
||||||
/// A temporary directory will be created to store the configuration and will be deleted
|
/// A temporary directory will be created to store the configuration and will be deleted
|
||||||
@@ -453,6 +457,10 @@ impl CliConfiguration for RunCmd {
|
|||||||
Ok(self.max_runtime_instances.map(|x| x.min(256)))
|
Ok(self.max_runtime_instances.map(|x| x.min(256)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn runtime_cache_size(&self) -> Result<u8> {
|
||||||
|
Ok(self.runtime_cache_size)
|
||||||
|
}
|
||||||
|
|
||||||
fn base_path(&self) -> Result<Option<BasePath>> {
|
fn base_path(&self) -> Result<Option<BasePath>> {
|
||||||
Ok(if self.tmp {
|
Ok(if self.tmp {
|
||||||
Some(BasePath::new_temp_dir()?)
|
Some(BasePath::new_temp_dir()?)
|
||||||
|
|||||||
@@ -452,6 +452,13 @@ pub trait CliConfiguration<DCV: DefaultConfigurationValues = ()>: Sized {
|
|||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get maximum different runtimes in cache
|
||||||
|
///
|
||||||
|
/// By default this is `2`.
|
||||||
|
fn runtime_cache_size(&self) -> Result<u8> {
|
||||||
|
Ok(2)
|
||||||
|
}
|
||||||
|
|
||||||
/// Activate or not the automatic announcing of blocks after import
|
/// Activate or not the automatic announcing of blocks after import
|
||||||
///
|
///
|
||||||
/// By default this is `false`.
|
/// By default this is `false`.
|
||||||
@@ -482,6 +489,7 @@ pub trait CliConfiguration<DCV: DefaultConfigurationValues = ()>: Sized {
|
|||||||
let is_validator = role.is_authority();
|
let is_validator = role.is_authority();
|
||||||
let (keystore_remote, keystore) = self.keystore_config(&config_dir)?;
|
let (keystore_remote, keystore) = self.keystore_config(&config_dir)?;
|
||||||
let telemetry_endpoints = self.telemetry_endpoints(&chain_spec)?;
|
let telemetry_endpoints = self.telemetry_endpoints(&chain_spec)?;
|
||||||
|
let runtime_cache_size = self.runtime_cache_size()?;
|
||||||
|
|
||||||
let unsafe_pruning = self.import_params().map(|p| p.unsafe_pruning).unwrap_or(false);
|
let unsafe_pruning = self.import_params().map(|p| p.unsafe_pruning).unwrap_or(false);
|
||||||
|
|
||||||
@@ -534,6 +542,7 @@ pub trait CliConfiguration<DCV: DefaultConfigurationValues = ()>: Sized {
|
|||||||
role,
|
role,
|
||||||
base_path: Some(base_path),
|
base_path: Some(base_path),
|
||||||
informant_output_format: Default::default(),
|
informant_output_format: Default::default(),
|
||||||
|
runtime_cache_size,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ parking_lot = "0.11.1"
|
|||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
libsecp256k1 = "0.7"
|
libsecp256k1 = "0.7"
|
||||||
sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/core/hashing/proc-macro" }
|
sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/core/hashing/proc-macro" }
|
||||||
|
lru = "0.6.6"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wat = "1.0"
|
wat = "1.0"
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ fn call_in_wasm<E: Externalities>(
|
|||||||
HostFunctions::host_functions(),
|
HostFunctions::host_functions(),
|
||||||
8,
|
8,
|
||||||
None,
|
None,
|
||||||
|
2,
|
||||||
);
|
);
|
||||||
executor.uncached_call(
|
executor.uncached_call(
|
||||||
RuntimeBlob::uncompress_if_needed(&wasm_binary_unwrap()[..]).unwrap(),
|
RuntimeBlob::uncompress_if_needed(&wasm_binary_unwrap()[..]).unwrap(),
|
||||||
@@ -480,6 +481,7 @@ fn should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) {
|
|||||||
HostFunctions::host_functions(),
|
HostFunctions::host_functions(),
|
||||||
8,
|
8,
|
||||||
None,
|
None,
|
||||||
|
2,
|
||||||
);
|
);
|
||||||
|
|
||||||
let err = executor
|
let err = executor
|
||||||
@@ -593,6 +595,7 @@ fn parallel_execution(wasm_method: WasmExecutionMethod) {
|
|||||||
HostFunctions::host_functions(),
|
HostFunctions::host_functions(),
|
||||||
8,
|
8,
|
||||||
None,
|
None,
|
||||||
|
2,
|
||||||
));
|
));
|
||||||
let threads: Vec<_> = (0..8)
|
let threads: Vec<_> = (0..8)
|
||||||
.map(|_| {
|
.map(|_| {
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ mod tests {
|
|||||||
sp_io::SubstrateHostFunctions::host_functions(),
|
sp_io::SubstrateHostFunctions::host_functions(),
|
||||||
8,
|
8,
|
||||||
None,
|
None,
|
||||||
|
2,
|
||||||
);
|
);
|
||||||
let res = executor
|
let res = executor
|
||||||
.uncached_call(
|
.uncached_call(
|
||||||
|
|||||||
@@ -130,12 +130,17 @@ impl WasmExecutor {
|
|||||||
host_functions: Vec<&'static dyn Function>,
|
host_functions: Vec<&'static dyn Function>,
|
||||||
max_runtime_instances: usize,
|
max_runtime_instances: usize,
|
||||||
cache_path: Option<PathBuf>,
|
cache_path: Option<PathBuf>,
|
||||||
|
runtime_cache_size: u8,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
WasmExecutor {
|
WasmExecutor {
|
||||||
method,
|
method,
|
||||||
default_heap_pages: default_heap_pages.unwrap_or(DEFAULT_HEAP_PAGES),
|
default_heap_pages: default_heap_pages.unwrap_or(DEFAULT_HEAP_PAGES),
|
||||||
host_functions: Arc::new(host_functions),
|
host_functions: Arc::new(host_functions),
|
||||||
cache: Arc::new(RuntimeCache::new(max_runtime_instances, cache_path.clone())),
|
cache: Arc::new(RuntimeCache::new(
|
||||||
|
max_runtime_instances,
|
||||||
|
cache_path.clone(),
|
||||||
|
runtime_cache_size,
|
||||||
|
)),
|
||||||
cache_path,
|
cache_path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -330,6 +335,7 @@ impl<D: NativeExecutionDispatch> NativeElseWasmExecutor<D> {
|
|||||||
fallback_method: WasmExecutionMethod,
|
fallback_method: WasmExecutionMethod,
|
||||||
default_heap_pages: Option<u64>,
|
default_heap_pages: Option<u64>,
|
||||||
max_runtime_instances: usize,
|
max_runtime_instances: usize,
|
||||||
|
runtime_cache_size: u8,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let extended = D::ExtendHostFunctions::host_functions();
|
let extended = D::ExtendHostFunctions::host_functions();
|
||||||
let mut host_functions = sp_io::SubstrateHostFunctions::host_functions()
|
let mut host_functions = sp_io::SubstrateHostFunctions::host_functions()
|
||||||
@@ -351,6 +357,7 @@ impl<D: NativeExecutionDispatch> NativeElseWasmExecutor<D> {
|
|||||||
host_functions,
|
host_functions,
|
||||||
max_runtime_instances,
|
max_runtime_instances,
|
||||||
None,
|
None,
|
||||||
|
runtime_cache_size,
|
||||||
);
|
);
|
||||||
|
|
||||||
NativeElseWasmExecutor {
|
NativeElseWasmExecutor {
|
||||||
@@ -636,6 +643,7 @@ mod tests {
|
|||||||
WasmExecutionMethod::Interpreted,
|
WasmExecutionMethod::Interpreted,
|
||||||
None,
|
None,
|
||||||
8,
|
8,
|
||||||
|
2,
|
||||||
);
|
);
|
||||||
my_interface::HostFunctions::host_functions().iter().for_each(|function| {
|
my_interface::HostFunctions::host_functions().iter().for_each(|function| {
|
||||||
assert_eq!(executor.wasm.host_functions.iter().filter(|f| f == &function).count(), 2);
|
assert_eq!(executor.wasm.host_functions.iter().filter(|f| f == &function).count(), 2);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
use crate::error::{Error, WasmError};
|
use crate::error::{Error, WasmError};
|
||||||
use codec::Decode;
|
use codec::Decode;
|
||||||
|
use lru::LruCache;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use sc_executor_common::{
|
use sc_executor_common::{
|
||||||
runtime_blob::RuntimeBlob,
|
runtime_blob::RuntimeBlob,
|
||||||
@@ -54,20 +55,24 @@ impl Default for WasmExecutionMethod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Wasm runtime object along with its cached runtime version.
|
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
||||||
struct VersionedRuntime {
|
struct VersionedRuntimeId {
|
||||||
/// Runtime code hash.
|
/// Runtime code hash.
|
||||||
code_hash: Vec<u8>,
|
code_hash: Vec<u8>,
|
||||||
/// Wasm runtime type.
|
/// Wasm runtime type.
|
||||||
wasm_method: WasmExecutionMethod,
|
wasm_method: WasmExecutionMethod,
|
||||||
/// Shared runtime that can spawn instances.
|
|
||||||
module: Arc<dyn WasmModule>,
|
|
||||||
/// The number of WebAssembly heap pages this instance was created with.
|
/// The number of WebAssembly heap pages this instance was created with.
|
||||||
heap_pages: u64,
|
heap_pages: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A Wasm runtime object along with its cached runtime version.
|
||||||
|
struct VersionedRuntime {
|
||||||
|
/// Shared runtime that can spawn instances.
|
||||||
|
module: Arc<dyn WasmModule>,
|
||||||
/// Runtime version according to `Core_version` if any.
|
/// Runtime version according to `Core_version` if any.
|
||||||
version: Option<RuntimeVersion>,
|
version: Option<RuntimeVersion>,
|
||||||
/// Cached instance pool.
|
/// Cached instance pool.
|
||||||
instances: Vec<Mutex<Option<Box<dyn WasmInstance>>>>,
|
instances: Arc<Vec<Mutex<Option<Box<dyn WasmInstance>>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VersionedRuntime {
|
impl VersionedRuntime {
|
||||||
@@ -137,8 +142,6 @@ impl VersionedRuntime {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAX_RUNTIMES: usize = 2;
|
|
||||||
|
|
||||||
/// Cache for the runtimes.
|
/// Cache for the runtimes.
|
||||||
///
|
///
|
||||||
/// When an instance is requested for the first time it is added to this cache. Metadata is kept
|
/// When an instance is requested for the first time it is added to this cache. Metadata is kept
|
||||||
@@ -149,12 +152,12 @@ const MAX_RUNTIMES: usize = 2;
|
|||||||
/// the memory reset to the initial memory. So, one runtime instance is reused for every fetch
|
/// the memory reset to the initial memory. So, one runtime instance is reused for every fetch
|
||||||
/// request.
|
/// request.
|
||||||
///
|
///
|
||||||
/// The size of cache is equal to `MAX_RUNTIMES`.
|
/// The size of cache is configurable via the cli option `--runtime-cache-size`.
|
||||||
pub struct RuntimeCache {
|
pub struct RuntimeCache {
|
||||||
/// A cache of runtimes along with metadata.
|
/// A cache of runtimes along with metadata.
|
||||||
///
|
///
|
||||||
/// Runtimes sorted by recent usage. The most recently used is at the front.
|
/// Runtimes sorted by recent usage. The most recently used is at the front.
|
||||||
runtimes: Mutex<[Option<Arc<VersionedRuntime>>; MAX_RUNTIMES]>,
|
runtimes: Mutex<LruCache<VersionedRuntimeId, Arc<VersionedRuntime>>>,
|
||||||
/// The size of the instances cache for each runtime.
|
/// The size of the instances cache for each runtime.
|
||||||
max_runtime_instances: usize,
|
max_runtime_instances: usize,
|
||||||
cache_path: Option<PathBuf>,
|
cache_path: Option<PathBuf>,
|
||||||
@@ -163,13 +166,24 @@ pub struct RuntimeCache {
|
|||||||
impl RuntimeCache {
|
impl RuntimeCache {
|
||||||
/// Creates a new instance of a runtimes cache.
|
/// Creates a new instance of a runtimes cache.
|
||||||
///
|
///
|
||||||
/// `max_runtime_instances` specifies the number of runtime instances preserved in an in-memory
|
/// `max_runtime_instances` specifies the number of instances per runtime preserved in an
|
||||||
/// cache.
|
/// in-memory cache.
|
||||||
///
|
///
|
||||||
/// `cache_path` allows to specify an optional directory where the executor can store files
|
/// `cache_path` allows to specify an optional directory where the executor can store files
|
||||||
/// for caching.
|
/// for caching.
|
||||||
pub fn new(max_runtime_instances: usize, cache_path: Option<PathBuf>) -> RuntimeCache {
|
///
|
||||||
RuntimeCache { runtimes: Default::default(), max_runtime_instances, cache_path }
|
/// `runtime_cache_size` specifies the number of different runtimes versions preserved in an
|
||||||
|
/// in-memory cache.
|
||||||
|
pub fn new(
|
||||||
|
max_runtime_instances: usize,
|
||||||
|
cache_path: Option<PathBuf>,
|
||||||
|
runtime_cache_size: u8,
|
||||||
|
) -> RuntimeCache {
|
||||||
|
RuntimeCache {
|
||||||
|
runtimes: Mutex::new(LruCache::new(runtime_cache_size.into())),
|
||||||
|
max_runtime_instances,
|
||||||
|
cache_path,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepares a WASM module instance and executes given function for it.
|
/// Prepares a WASM module instance and executes given function for it.
|
||||||
@@ -221,71 +235,55 @@ impl RuntimeCache {
|
|||||||
let code_hash = &runtime_code.hash;
|
let code_hash = &runtime_code.hash;
|
||||||
let heap_pages = runtime_code.heap_pages.unwrap_or(default_heap_pages);
|
let heap_pages = runtime_code.heap_pages.unwrap_or(default_heap_pages);
|
||||||
|
|
||||||
|
let versioned_runtime_id =
|
||||||
|
VersionedRuntimeId { code_hash: code_hash.clone(), heap_pages, wasm_method };
|
||||||
|
|
||||||
let mut runtimes = self.runtimes.lock(); // this must be released prior to calling f
|
let mut runtimes = self.runtimes.lock(); // this must be released prior to calling f
|
||||||
let pos = runtimes.iter().position(|r| {
|
let versioned_runtime = if let Some(versioned_runtime) = runtimes.get(&versioned_runtime_id)
|
||||||
r.as_ref().map_or(false, |r| {
|
{
|
||||||
r.wasm_method == wasm_method &&
|
versioned_runtime.clone()
|
||||||
r.code_hash == *code_hash &&
|
} else {
|
||||||
r.heap_pages == heap_pages
|
let code = runtime_code.fetch_runtime_code().ok_or(WasmError::CodeNotFound)?;
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
let runtime = match pos {
|
let time = std::time::Instant::now();
|
||||||
Some(n) => runtimes[n]
|
|
||||||
.clone()
|
|
||||||
.expect("`position` only returns `Some` for entries that are `Some`"),
|
|
||||||
None => {
|
|
||||||
let code = runtime_code.fetch_runtime_code().ok_or(WasmError::CodeNotFound)?;
|
|
||||||
|
|
||||||
let time = std::time::Instant::now();
|
let result = create_versioned_wasm_runtime(
|
||||||
|
&code,
|
||||||
|
ext,
|
||||||
|
wasm_method,
|
||||||
|
heap_pages,
|
||||||
|
host_functions.into(),
|
||||||
|
allow_missing_func_imports,
|
||||||
|
self.max_runtime_instances,
|
||||||
|
self.cache_path.as_deref(),
|
||||||
|
);
|
||||||
|
|
||||||
let result = create_versioned_wasm_runtime(
|
match result {
|
||||||
&code,
|
Ok(ref result) => {
|
||||||
code_hash.clone(),
|
log::debug!(
|
||||||
ext,
|
target: "wasm-runtime",
|
||||||
wasm_method,
|
"Prepared new runtime version {:?} in {} ms.",
|
||||||
heap_pages,
|
result.version,
|
||||||
host_functions.into(),
|
time.elapsed().as_millis(),
|
||||||
allow_missing_func_imports,
|
);
|
||||||
self.max_runtime_instances,
|
},
|
||||||
self.cache_path.as_deref(),
|
Err(ref err) => {
|
||||||
);
|
log::warn!(target: "wasm-runtime", "Cannot create a runtime: {:?}", err);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
match result {
|
let versioned_runtime = Arc::new(result?);
|
||||||
Ok(ref result) => {
|
|
||||||
log::debug!(
|
|
||||||
target: "wasm-runtime",
|
|
||||||
"Prepared new runtime version {:?} in {} ms.",
|
|
||||||
result.version,
|
|
||||||
time.elapsed().as_millis(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
Err(ref err) => {
|
|
||||||
log::warn!(target: "wasm-runtime", "Cannot create a runtime: {:?}", err);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
Arc::new(result?)
|
// Save new versioned wasm runtime in cache
|
||||||
},
|
runtimes.put(versioned_runtime_id, versioned_runtime.clone());
|
||||||
|
|
||||||
|
versioned_runtime
|
||||||
};
|
};
|
||||||
|
|
||||||
// Rearrange runtimes by last recently used.
|
// Lock must be released prior to calling f
|
||||||
match pos {
|
|
||||||
Some(0) => {},
|
|
||||||
Some(n) =>
|
|
||||||
for i in (1..n + 1).rev() {
|
|
||||||
runtimes.swap(i, i - 1);
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
runtimes[MAX_RUNTIMES - 1] = Some(runtime.clone());
|
|
||||||
for i in (1..MAX_RUNTIMES).rev() {
|
|
||||||
runtimes.swap(i, i - 1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
drop(runtimes);
|
drop(runtimes);
|
||||||
|
|
||||||
Ok(runtime.with_instance(ext, f))
|
Ok(versioned_runtime.with_instance(ext, f))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,7 +394,6 @@ pub fn read_embedded_version(blob: &RuntimeBlob) -> Result<Option<RuntimeVersion
|
|||||||
|
|
||||||
fn create_versioned_wasm_runtime(
|
fn create_versioned_wasm_runtime(
|
||||||
code: &[u8],
|
code: &[u8],
|
||||||
code_hash: Vec<u8>,
|
|
||||||
ext: &mut dyn Externalities,
|
ext: &mut dyn Externalities,
|
||||||
wasm_method: WasmExecutionMethod,
|
wasm_method: WasmExecutionMethod,
|
||||||
heap_pages: u64,
|
heap_pages: u64,
|
||||||
@@ -449,7 +446,7 @@ fn create_versioned_wasm_runtime(
|
|||||||
let mut instances = Vec::with_capacity(max_instances);
|
let mut instances = Vec::with_capacity(max_instances);
|
||||||
instances.resize_with(max_instances, || Mutex::new(None));
|
instances.resize_with(max_instances, || Mutex::new(None));
|
||||||
|
|
||||||
Ok(VersionedRuntime { code_hash, module: runtime, version, heap_pages, wasm_method, instances })
|
Ok(VersionedRuntime { module: runtime, version, instances: Arc::new(instances) })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -360,6 +360,7 @@ mod tests {
|
|||||||
WasmExecutionMethod::Interpreted,
|
WasmExecutionMethod::Interpreted,
|
||||||
Some(128),
|
Some(128),
|
||||||
1,
|
1,
|
||||||
|
2,
|
||||||
);
|
);
|
||||||
|
|
||||||
let overrides = crate::client::wasm_override::dummy_overrides();
|
let overrides = crate::client::wasm_override::dummy_overrides();
|
||||||
|
|||||||
@@ -282,6 +282,7 @@ mod tests {
|
|||||||
WasmExecutionMethod::Interpreted,
|
WasmExecutionMethod::Interpreted,
|
||||||
Some(128),
|
Some(128),
|
||||||
1,
|
1,
|
||||||
|
2,
|
||||||
);
|
);
|
||||||
let bytes = substrate_test_runtime::wasm_binary_unwrap();
|
let bytes = substrate_test_runtime::wasm_binary_unwrap();
|
||||||
let dir = tempfile::tempdir().expect("Create a temporary directory");
|
let dir = tempfile::tempdir().expect("Create a temporary directory");
|
||||||
@@ -295,6 +296,7 @@ mod tests {
|
|||||||
WasmExecutionMethod::Interpreted,
|
WasmExecutionMethod::Interpreted,
|
||||||
Some(128),
|
Some(128),
|
||||||
1,
|
1,
|
||||||
|
2,
|
||||||
);
|
);
|
||||||
|
|
||||||
let version = WasmOverride::runtime_version(
|
let version = WasmOverride::runtime_version(
|
||||||
|
|||||||
@@ -132,6 +132,8 @@ pub struct Configuration {
|
|||||||
pub base_path: Option<BasePath>,
|
pub base_path: Option<BasePath>,
|
||||||
/// Configuration of the output format that the informant uses.
|
/// Configuration of the output format that the informant uses.
|
||||||
pub informant_output_format: sc_informant::OutputFormat,
|
pub informant_output_format: sc_informant::OutputFormat,
|
||||||
|
/// Maximum number of different runtime versions that can be cached.
|
||||||
|
pub runtime_cache_size: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type for tasks spawned by the executor.
|
/// Type for tasks spawned by the executor.
|
||||||
|
|||||||
@@ -72,7 +72,12 @@ impl sc_executor::NativeExecutionDispatch for ExecutorDispatch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn executor() -> sc_executor::NativeElseWasmExecutor<ExecutorDispatch> {
|
fn executor() -> sc_executor::NativeElseWasmExecutor<ExecutorDispatch> {
|
||||||
sc_executor::NativeElseWasmExecutor::new(sc_executor::WasmExecutionMethod::Interpreted, None, 8)
|
sc_executor::NativeElseWasmExecutor::new(
|
||||||
|
sc_executor::WasmExecutionMethod::Interpreted,
|
||||||
|
None,
|
||||||
|
8,
|
||||||
|
2,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn construct_block(
|
fn construct_block(
|
||||||
|
|||||||
@@ -261,6 +261,7 @@ fn node_config<
|
|||||||
announce_block: true,
|
announce_block: true,
|
||||||
base_path: Some(BasePath::new(root)),
|
base_path: Some(BasePath::new(root)),
|
||||||
informant_output_format: Default::default(),
|
informant_output_format: Default::default(),
|
||||||
|
runtime_cache_size: 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -210,6 +210,7 @@ fn record_proof_works() {
|
|||||||
WasmExecutionMethod::Interpreted,
|
WasmExecutionMethod::Interpreted,
|
||||||
None,
|
None,
|
||||||
8,
|
8,
|
||||||
|
2,
|
||||||
);
|
);
|
||||||
execution_proof_check_on_trie_backend(
|
execution_proof_check_on_trie_backend(
|
||||||
&backend,
|
&backend,
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ fn call_wasm_method_with_result<HF: HostFunctionsT>(
|
|||||||
host_functions,
|
host_functions,
|
||||||
8,
|
8,
|
||||||
None,
|
None,
|
||||||
|
2,
|
||||||
);
|
);
|
||||||
executor
|
executor
|
||||||
.uncached_call(
|
.uncached_call(
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ impl<Block: BlockT, D, Backend, G: GenesisInit>
|
|||||||
Backend: sc_client_api::backend::Backend<Block> + 'static,
|
Backend: sc_client_api::backend::Backend<Block> + 'static,
|
||||||
{
|
{
|
||||||
let executor = executor.into().unwrap_or_else(|| {
|
let executor = executor.into().unwrap_or_else(|| {
|
||||||
NativeElseWasmExecutor::new(WasmExecutionMethod::Interpreted, None, 8)
|
NativeElseWasmExecutor::new(WasmExecutionMethod::Interpreted, None, 8, 2)
|
||||||
});
|
});
|
||||||
let executor = LocalCallExecutor::new(
|
let executor = LocalCallExecutor::new(
|
||||||
self.backend.clone(),
|
self.backend.clone(),
|
||||||
|
|||||||
@@ -287,5 +287,10 @@ pub fn new() -> Client<Backend> {
|
|||||||
|
|
||||||
/// Create a new native executor.
|
/// Create a new native executor.
|
||||||
pub fn new_native_executor() -> sc_executor::NativeElseWasmExecutor<LocalExecutorDispatch> {
|
pub fn new_native_executor() -> sc_executor::NativeElseWasmExecutor<LocalExecutorDispatch> {
|
||||||
sc_executor::NativeElseWasmExecutor::new(sc_executor::WasmExecutionMethod::Interpreted, None, 8)
|
sc_executor::NativeElseWasmExecutor::new(
|
||||||
|
sc_executor::WasmExecutionMethod::Interpreted,
|
||||||
|
None,
|
||||||
|
8,
|
||||||
|
2,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -342,7 +342,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn executor() -> NativeElseWasmExecutor<NativeDispatch> {
|
fn executor() -> NativeElseWasmExecutor<NativeDispatch> {
|
||||||
NativeElseWasmExecutor::new(WasmExecutionMethod::Interpreted, None, 8)
|
NativeElseWasmExecutor::new(WasmExecutionMethod::Interpreted, None, 8, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_test_ext() -> TestExternalities {
|
fn new_test_ext() -> TestExternalities {
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ where
|
|||||||
config.wasm_method,
|
config.wasm_method,
|
||||||
config.default_heap_pages,
|
config.default_heap_pages,
|
||||||
config.max_runtime_instances,
|
config.max_runtime_instances,
|
||||||
|
config.runtime_cache_size,
|
||||||
);
|
);
|
||||||
|
|
||||||
let (client, backend, keystore, mut task_manager) =
|
let (client, backend, keystore, mut task_manager) =
|
||||||
|
|||||||
@@ -113,5 +113,6 @@ pub fn default_config(tokio_handle: Handle, mut chain_spec: Box<dyn ChainSpec>)
|
|||||||
keep_blocks: KeepBlocks::All,
|
keep_blocks: KeepBlocks::All,
|
||||||
state_pruning: Default::default(),
|
state_pruning: Default::default(),
|
||||||
transaction_storage: TransactionStorageMode::BlockBody,
|
transaction_storage: TransactionStorageMode::BlockBody,
|
||||||
|
runtime_cache_size: 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ impl BenchmarkCmd {
|
|||||||
wasm_method,
|
wasm_method,
|
||||||
self.heap_pages,
|
self.heap_pages,
|
||||||
2, // The runtime instances cache size.
|
2, // The runtime instances cache size.
|
||||||
|
2, // The runtime cache size
|
||||||
);
|
);
|
||||||
|
|
||||||
let extensions = || -> Extensions {
|
let extensions = || -> Extensions {
|
||||||
|
|||||||
@@ -678,8 +678,14 @@ pub(crate) fn build_executor<D: NativeExecutionDispatch + 'static>(
|
|||||||
let wasm_method = shared.wasm_method;
|
let wasm_method = shared.wasm_method;
|
||||||
let heap_pages = shared.heap_pages.or(config.default_heap_pages);
|
let heap_pages = shared.heap_pages.or(config.default_heap_pages);
|
||||||
let max_runtime_instances = config.max_runtime_instances;
|
let max_runtime_instances = config.max_runtime_instances;
|
||||||
|
let runtime_cache_size = config.runtime_cache_size;
|
||||||
|
|
||||||
NativeElseWasmExecutor::<D>::new(wasm_method.into(), heap_pages, max_runtime_instances)
|
NativeElseWasmExecutor::<D>::new(
|
||||||
|
wasm_method.into(),
|
||||||
|
heap_pages,
|
||||||
|
max_runtime_instances,
|
||||||
|
runtime_cache_size,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute the given `method` and `data` on top of `ext`, returning the results (encoded) and the
|
/// Execute the given `method` and `data` on top of `ext`, returning the results (encoded) and the
|
||||||
|
|||||||
Reference in New Issue
Block a user