WasmExecutor takes a cache directory (#8057)

That is useful for executors like wasmtime which produces compiled code
and can actually benefit from caching under some circumstances
This commit is contained in:
Sergei Shulepov
2021-02-09 17:48:29 +01:00
committed by GitHub
parent ef6615ba65
commit eb7226bb4a
6 changed files with 104 additions and 8 deletions
@@ -75,6 +75,7 @@ fn call_in_wasm<E: Externalities>(
Some(1024),
HostFunctions::host_functions(),
8,
None,
);
executor.call_in_wasm(
&wasm_binary_unwrap()[..],
@@ -536,6 +537,7 @@ fn should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) {
Some(17), // `17` is the initial number of pages compiled into the binary.
HostFunctions::host_functions(),
8,
None,
);
let err = executor.call_in_wasm(
@@ -558,6 +560,7 @@ fn returns_mutable_static(wasm_method: WasmExecutionMethod) {
&wasm_binary_unwrap()[..],
HostFunctions::host_functions(),
true,
None,
).expect("Creates runtime");
let instance = runtime.new_instance().unwrap();
@@ -591,6 +594,7 @@ fn restoration_of_globals(wasm_method: WasmExecutionMethod) {
&wasm_binary_unwrap()[..],
HostFunctions::host_functions(),
true,
None,
).expect("Creates runtime");
let instance = runtime.new_instance().unwrap();
@@ -611,6 +615,7 @@ fn heap_is_reset_between_calls(wasm_method: WasmExecutionMethod) {
&wasm_binary_unwrap()[..],
HostFunctions::host_functions(),
true,
None,
).expect("Creates runtime");
let instance = runtime.new_instance().unwrap();
@@ -634,6 +639,7 @@ fn parallel_execution(wasm_method: WasmExecutionMethod) {
Some(1024),
HostFunctions::host_functions(),
8,
None,
));
let code_hash = blake2_256(wasm_binary_unwrap()).to_vec();
let threads: Vec<_> = (0..8).map(|_|
+1
View File
@@ -80,6 +80,7 @@ mod tests {
Some(8),
sp_io::SubstrateHostFunctions::host_functions(),
8,
None,
);
let res = executor.call_in_wasm(
&wasm_binary_unwrap()[..],
@@ -26,6 +26,7 @@ use std::{
panic::{UnwindSafe, AssertUnwindSafe},
result,
sync::{Arc, atomic::{AtomicU64, Ordering}, mpsc},
path::PathBuf,
};
use sp_version::{NativeVersion, RuntimeVersion};
@@ -102,6 +103,9 @@ pub struct WasmExecutor {
cache: Arc<RuntimeCache>,
/// The size of the instances cache.
max_runtime_instances: usize,
/// The path to a directory which the executor can leverage for a file cache, e.g. put there
/// compiled artifacts.
cache_path: Option<PathBuf>,
}
impl WasmExecutor {
@@ -112,19 +116,30 @@ impl WasmExecutor {
/// `method` - Method used to execute Wasm code.
///
/// `default_heap_pages` - Number of 64KB pages to allocate for Wasm execution.
/// Defaults to `DEFAULT_HEAP_PAGES` if `None` is provided.
/// Defaults to `DEFAULT_HEAP_PAGES` if `None` is provided.
///
/// `host_functions` - The set of host functions to be available for import provided by this
/// executor.
///
/// `max_runtime_instances` - The number of runtime instances to keep in memory ready for reuse.
///
/// `cache_path` - A path to a directory where the executor can place its files for purposes of
/// caching. This may be important in cases when there are many different modules with the
/// compiled execution method is used.
pub fn new(
method: WasmExecutionMethod,
default_heap_pages: Option<u64>,
host_functions: Vec<&'static dyn Function>,
max_runtime_instances: usize,
cache_path: Option<PathBuf>,
) -> Self {
WasmExecutor {
method,
default_heap_pages: default_heap_pages.unwrap_or(DEFAULT_HEAP_PAGES),
host_functions: Arc::new(host_functions),
cache: Arc::new(RuntimeCache::new(max_runtime_instances)),
cache: Arc::new(RuntimeCache::new(max_runtime_instances, cache_path.clone())),
max_runtime_instances,
cache_path,
}
}
@@ -210,6 +225,7 @@ impl sp_core::traits::CallInWasm for WasmExecutor {
&wasm_code,
self.host_functions.to_vec(),
allow_missing_host_functions,
self.cache_path.as_deref(),
)
.map_err(|e| format!("Failed to create module: {:?}", e))?;
@@ -267,6 +283,7 @@ impl<D: NativeExecutionDispatch> NativeExecutor<D> {
default_heap_pages,
host_functions,
max_runtime_instances,
None,
);
NativeExecutor {
+27 -5
View File
@@ -28,6 +28,7 @@ use codec::Decode;
use sp_core::traits::{Externalities, RuntimeCode, FetchRuntimeCode};
use sp_version::RuntimeVersion;
use std::panic::AssertUnwindSafe;
use std::path::{Path, PathBuf};
use sc_executor_common::wasm_runtime::{WasmModule, WasmInstance};
use sp_wasm_interface::Function;
@@ -152,14 +153,22 @@ pub struct RuntimeCache {
runtimes: Mutex<[Option<Arc<VersionedRuntime>>; MAX_RUNTIMES]>,
/// The size of the instances cache for each runtime.
max_runtime_instances: usize,
cache_path: Option<PathBuf>,
}
impl RuntimeCache {
/// Creates a new instance of a runtimes cache.
pub fn new(max_runtime_instances: usize) -> RuntimeCache {
///
/// `max_runtime_instances` specifies the number of runtime instances preserved in an in-memory
/// cache.
///
/// `cache_path` allows to specify an optional directory where the executor can store files
/// for caching.
pub fn new(max_runtime_instances: usize, cache_path: Option<PathBuf>) -> RuntimeCache {
RuntimeCache {
runtimes: Default::default(),
max_runtime_instances,
cache_path,
}
}
@@ -235,6 +244,7 @@ impl RuntimeCache {
host_functions.into(),
allow_missing_func_imports,
self.max_runtime_instances,
self.cache_path.as_deref(),
);
if let Err(ref err) = result {
log::warn!(target: "wasm-runtime", "Cannot create a runtime: {:?}", err);
@@ -271,22 +281,32 @@ pub fn create_wasm_runtime_with_code(
code: &[u8],
host_functions: Vec<&'static dyn Function>,
allow_missing_func_imports: bool,
cache_path: Option<&Path>,
) -> Result<Arc<dyn WasmModule>, WasmError> {
match wasm_method {
WasmExecutionMethod::Interpreted =>
WasmExecutionMethod::Interpreted => {
// Wasmi doesn't have any need in a cache directory.
//
// We drop the cache_path here to silence warnings that cache_path is not used if compiling
// without the `wasmtime` flag.
drop(cache_path);
sc_executor_wasmi::create_runtime(
code,
heap_pages,
host_functions,
allow_missing_func_imports
).map(|runtime| -> Arc<dyn WasmModule> { Arc::new(runtime) }),
allow_missing_func_imports,
)
.map(|runtime| -> Arc<dyn WasmModule> { Arc::new(runtime) })
}
#[cfg(feature = "wasmtime")]
WasmExecutionMethod::Compiled =>
sc_executor_wasmtime::create_runtime(
code,
heap_pages,
host_functions,
allow_missing_func_imports
allow_missing_func_imports,
cache_path,
).map(|runtime| -> Arc<dyn WasmModule> { Arc::new(runtime) }),
}
}
@@ -319,6 +339,7 @@ fn create_versioned_wasm_runtime(
host_functions: Vec<&'static dyn Function>,
allow_missing_func_imports: bool,
max_instances: usize,
cache_path: Option<&Path>,
) -> Result<VersionedRuntime, WasmError> {
#[cfg(not(target_os = "unknown"))]
let time = std::time::Instant::now();
@@ -328,6 +349,7 @@ fn create_versioned_wasm_runtime(
&code,
host_functions,
allow_missing_func_imports,
cache_path,
)?;
// Call to determine runtime version.