Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit 86e5d89

Browse files
committed
Update from parent 'origin/master' (conflicts)
Commit: 67bf1ac Parent branch: origin/master Forked at: 2afecf8
2 parents 50613ce + 67bf1ac commit 86e5d89

File tree

24 files changed

+146
-70
lines changed

24 files changed

+146
-70
lines changed

bin/node/executor/benches/bench.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@ fn bench_execute_block(c: &mut Criterion) {
170170
ExecutionMethod::Native => (true, WasmExecutionMethod::Interpreted),
171171
ExecutionMethod::Wasm(wasm_method) => (false, *wasm_method),
172172
};
173-
let executor = NativeExecutor::new(wasm_method, None);
173+
174+
let executor = NativeExecutor::new(wasm_method, None, 8);
174175
let runtime_code = RuntimeCode {
175176
code_fetcher: &sp_core::traits::WrappedRuntimeCode(COMPACT_CODE.into()),
176177
hash: vec![1, 2, 3],

bin/node/executor/tests/common.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub fn from_block_number(n: u32) -> Header {
5858
}
5959

6060
pub fn executor() -> NativeExecutor<Executor> {
61-
NativeExecutor::new(WasmExecutionMethod::Interpreted, None)
61+
NativeExecutor::new(WasmExecutionMethod::Interpreted, None, 8)
6262
}
6363

6464
pub fn executor_call<

bin/node/runtime/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
8383
// implementation changes and behavior does not, then leave spec_version as
8484
// is and increment impl_version.
8585
spec_version: 235,
86-
impl_version: 0,
86+
impl_version: 1,
8787
apis: RUNTIME_API_VERSIONS,
8888
};
8989

bin/node/testing/src/bench.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ impl BenchDb {
150150

151151
let (client, backend) = sc_client_db::new_client(
152152
db_config,
153-
NativeExecutor::new(WasmExecutionMethod::Compiled, None),
153+
NativeExecutor::new(WasmExecutionMethod::Compiled, None, 8),
154154
&keyring.generate_genesis(),
155155
None,
156156
None,

client/cli/src/commands/runcmd.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,12 @@ pub struct RunCmd {
232232
#[allow(missing_docs)]
233233
#[structopt(flatten)]
234234
pub keystore_params: KeystoreParams,
235+
236+
/// The size of the instances cache for each runtime.
237+
///
238+
/// The default value is 8 and the values higher than 256 are ignored.
239+
#[structopt(long)]
240+
pub max_runtime_instances: Option<usize>,
235241
}
236242

237243
impl RunCmd {
@@ -407,6 +413,10 @@ impl CliConfiguration for RunCmd {
407413
fn get_transaction_pool(&self) -> Result<TransactionPoolOptions> {
408414
self.pool_config.get_transaction_pool()
409415
}
416+
417+
fn get_max_runtime_instances(&self) -> Result<Option<usize>> {
418+
Ok(self.max_runtime_instances.map(|x| x.min(256)))
419+
}
410420
}
411421

412422
/// Check whether a node name is considered as valid

client/cli/src/config.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,11 @@ pub trait CliConfiguration: Sized {
216216
Ok(Default::default())
217217
}
218218

219+
/// Get maximum runtime instances
220+
fn get_max_runtime_instances(&self) -> Result<Option<usize>> {
221+
Ok(Default::default())
222+
}
223+
219224
/// Create a Configuration object from the current object
220225
fn create_configuration<C: SubstrateCLI<G, E>, G, E>(
221226
&self,
@@ -246,6 +251,7 @@ pub trait CliConfiguration: Sized {
246251
let database_cache_size = Some(self.get_database_cache_size()?.unwrap_or(128));
247252
let node_key = self.get_node_key(&net_config_dir)?;
248253
let roles = self.get_roles(is_dev)?;
254+
let max_runtime_instances = self.get_max_runtime_instances()?.unwrap_or(8);
249255

250256
Ok(Configuration {
251257
impl_name: C::get_impl_name(),
@@ -284,6 +290,7 @@ pub trait CliConfiguration: Sized {
284290
tracing_targets: self.get_tracing_targets()?,
285291
tracing_receiver: self.get_tracing_receiver()?,
286292
chain_spec,
293+
max_runtime_instances,
287294
})
288295
}
289296

client/executor/src/integration_tests/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ fn call_in_wasm<E: Externalities>(
4646
Some(1024),
4747
HostFunctions::host_functions(),
4848
true,
49+
8,
4950
);
5051
executor.call_in_wasm(
5152
&WASM_BINARY[..],
@@ -511,6 +512,7 @@ fn should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) {
511512
Some(17), // `17` is the initial number of pages compiled into the binary.
512513
HostFunctions::host_functions(),
513514
true,
515+
8,
514516
);
515517
executor.call_in_wasm(
516518
&WASM_BINARY[..],

client/executor/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ mod tests {
7878
Some(8),
7979
sp_io::SubstrateHostFunctions::host_functions(),
8080
true,
81+
8,
8182
);
8283
let res = executor.call_in_wasm(
8384
&WASM_BINARY[..],

client/executor/src/native_executor.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ pub struct WasmExecutor {
8585
cache: Arc<RuntimeCache>,
8686
/// Allow missing function imports.
8787
allow_missing_func_imports: bool,
88+
/// The size of the instances cache.
89+
max_runtime_instances: usize,
8890
}
8991

9092
impl WasmExecutor {
@@ -101,13 +103,15 @@ impl WasmExecutor {
101103
default_heap_pages: Option<u64>,
102104
host_functions: Vec<&'static dyn Function>,
103105
allow_missing_func_imports: bool,
106+
max_runtime_instances: usize,
104107
) -> Self {
105108
WasmExecutor {
106109
method,
107110
default_heap_pages: default_heap_pages.unwrap_or(DEFAULT_HEAP_PAGES),
108111
host_functions: Arc::new(host_functions),
109-
cache: Arc::new(RuntimeCache::new()),
112+
cache: Arc::new(RuntimeCache::new(max_runtime_instances)),
110113
allow_missing_func_imports,
114+
max_runtime_instances,
111115
}
112116
}
113117

@@ -223,7 +227,11 @@ impl<D: NativeExecutionDispatch> NativeExecutor<D> {
223227
///
224228
/// `default_heap_pages` - Number of 64KB pages to allocate for Wasm execution.
225229
/// Defaults to `DEFAULT_HEAP_PAGES` if `None` is provided.
226-
pub fn new(fallback_method: WasmExecutionMethod, default_heap_pages: Option<u64>) -> Self {
230+
pub fn new(
231+
fallback_method: WasmExecutionMethod,
232+
default_heap_pages: Option<u64>,
233+
max_runtime_instances: usize,
234+
) -> Self {
227235
let mut host_functions = sp_io::SubstrateHostFunctions::host_functions();
228236

229237
// Add the custom host functions provided by the user.
@@ -233,6 +241,7 @@ impl<D: NativeExecutionDispatch> NativeExecutor<D> {
233241
default_heap_pages,
234242
host_functions,
235243
false,
244+
max_runtime_instances,
236245
);
237246

238247
NativeExecutor {
@@ -463,7 +472,11 @@ mod tests {
463472

464473
#[test]
465474
fn native_executor_registers_custom_interface() {
466-
let executor = NativeExecutor::<MyExecutor>::new(WasmExecutionMethod::Interpreted, None);
475+
let executor = NativeExecutor::<MyExecutor>::new(
476+
WasmExecutionMethod::Interpreted,
477+
None,
478+
8,
479+
);
467480
my_interface::HostFunctions::host_functions().iter().for_each(|function| {
468481
assert_eq!(
469482
executor.wasm.host_functions.iter().filter(|f| f == &function).count(),

client/executor/src/wasm_runtime.rs

Lines changed: 83 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
2222
use std::sync::Arc;
2323
use crate::error::{Error, WasmError};
24-
use parking_lot::{Mutex, RwLock};
24+
use parking_lot::Mutex;
2525
use codec::Decode;
2626
use sp_core::traits::{Externalities, RuntimeCode, FetchRuntimeCode};
2727
use sp_version::RuntimeVersion;
@@ -59,11 +59,77 @@ struct VersionedRuntime {
5959
/// Runtime version according to `Core_version` if any.
6060
version: Option<RuntimeVersion>,
6161
/// Cached instance pool.
62-
instances: RwLock<[Option<Arc<Mutex<Box<dyn WasmInstance>>>>; MAX_INSTANCES]>,
62+
instances: Vec<Mutex<Option<Box<dyn WasmInstance>>>>,
63+
}
64+
65+
impl VersionedRuntime {
66+
/// Run the given closure `f` with an instance of this runtime.
67+
fn with_instance<'c, R, F>(
68+
&self,
69+
ext: &mut dyn Externalities,
70+
f: F,
71+
) -> Result<R, Error>
72+
where F: FnOnce(
73+
&dyn WasmInstance,
74+
Option<&RuntimeVersion>,
75+
&mut dyn Externalities)
76+
-> Result<R, Error>,
77+
{
78+
// Find a free instance
79+
let instance = self.instances
80+
.iter()
81+
.enumerate()
82+
.find_map(|(index, i)| i.try_lock().map(|i| (index, i)));
83+
84+
match instance {
85+
Some((index, mut locked)) => {
86+
let (instance, new_inst) = locked.take()
87+
.map(|r| Ok((r, false)))
88+
.unwrap_or_else(|| self.module.new_instance().map(|i| (i, true)))?;
89+
90+
let result = f(&*instance, self.version.as_ref(), ext);
91+
if let Err(e) = &result {
92+
if new_inst {
93+
log::warn!(
94+
target: "wasm-runtime",
95+
"Fresh runtime instance failed with {:?}",
96+
e,
97+
)
98+
} else {
99+
log::warn!(
100+
target: "wasm-runtime",
101+
"Evicting failed runtime instance: {:?}",
102+
e,
103+
);
104+
}
105+
} else {
106+
*locked = Some(instance);
107+
108+
if new_inst {
109+
log::debug!(
110+
target: "wasm-runtime",
111+
"Allocated WASM instance {}/{}",
112+
index + 1,
113+
self.instances.len(),
114+
);
115+
}
116+
}
117+
118+
result
119+
},
120+
None => {
121+
log::warn!(target: "wasm-runtime", "Ran out of free WASM instances");
122+
123+
// Allocate a new instance
124+
let instance = self.module.new_instance()?;
125+
126+
f(&*instance, self.version.as_ref(), ext)
127+
}
128+
}
129+
}
63130
}
64131

65132
const MAX_RUNTIMES: usize = 2;
66-
const MAX_INSTANCES: usize = 8;
67133

68134
/// Cache for the runtimes.
69135
///
@@ -75,20 +141,22 @@ const MAX_INSTANCES: usize = 8;
75141
/// the memory reset to the initial memory. So, one runtime instance is reused for every fetch
76142
/// request.
77143
///
78-
/// For now the cache grows indefinitely, but that should be fine for now since runtimes can only be
79-
/// upgraded rarely and there are no other ways to make the node to execute some other runtime.
144+
/// The size of cache is equal to `MAX_RUNTIMES`.
80145
pub struct RuntimeCache {
81146
/// A cache of runtimes along with metadata.
82147
///
83148
/// Runtimes sorted by recent usage. The most recently used is at the front.
84149
runtimes: Mutex<[Option<Arc<VersionedRuntime>>; MAX_RUNTIMES]>,
150+
/// The size of the instances cache for each runtime.
151+
max_runtime_instances: usize,
85152
}
86153

87154
impl RuntimeCache {
88155
/// Creates a new instance of a runtimes cache.
89-
pub fn new() -> RuntimeCache {
156+
pub fn new(max_runtime_instances: usize) -> RuntimeCache {
90157
RuntimeCache {
91158
runtimes: Default::default(),
159+
max_runtime_instances,
92160
}
93161
}
94162

@@ -109,6 +177,8 @@ impl RuntimeCache {
109177
///
110178
/// `allow_missing_func_imports` - Ignore missing function imports.
111179
///
180+
/// `max_runtime_instances` - The size of the instances cache.
181+
///
112182
/// `f` - Function to execute.
113183
///
114184
/// # Returns result of `f` wrapped in an additonal result.
@@ -160,6 +230,7 @@ impl RuntimeCache {
160230
heap_pages,
161231
host_functions.into(),
162232
allow_missing_func_imports,
233+
self.max_runtime_instances,
163234
);
164235
if let Err(ref err) = result {
165236
log::warn!(target: "wasm-runtime", "Cannot create a runtime: {:?}", err);
@@ -185,53 +256,7 @@ impl RuntimeCache {
185256
}
186257
drop(runtimes);
187258

188-
let result = {
189-
// Find a free instance
190-
let instance_pool = runtime.instances.read().clone();
191-
let instance = instance_pool
192-
.iter()
193-
.find_map(|i| i.as_ref().and_then(|i| i.try_lock()));
194-
if let Some(mut locked) = instance {
195-
let result = f(&**locked, runtime.version.as_ref(), ext);
196-
if let Err(e) = &result {
197-
log::warn!(target: "wasm-runtime", "Evicting failed runtime instance: {:?}", e);
198-
*locked = runtime.module.new_instance()?;
199-
}
200-
result
201-
} else {
202-
// Allocate a new instance
203-
let instance = runtime.module.new_instance()?;
204-
205-
let result = f(&*instance, runtime.version.as_ref(), ext);
206-
match &result {
207-
Ok(_) => {
208-
let mut instance_pool = runtime.instances.write();
209-
if let Some(ref mut slot) = instance_pool.iter_mut().find(|s| s.is_none()) {
210-
**slot = Some(Arc::new(Mutex::new(instance)));
211-
log::debug!(
212-
target: "wasm-runtime",
213-
"Allocated WASM instance {}/{}",
214-
instance_pool.len(),
215-
MAX_INSTANCES,
216-
);
217-
} else {
218-
log::warn!(target: "wasm-runtime", "Ran out of free WASM instances");
219-
}
220-
}
221-
Err(e) => {
222-
log::warn!(
223-
target:
224-
"wasm-runtime",
225-
"Fresh runtime instance failed with {:?}",
226-
e,
227-
);
228-
}
229-
}
230-
result
231-
}
232-
};
233-
234-
Ok(result)
259+
Ok(runtime.with_instance(ext, f))
235260
}
236261
}
237262

@@ -270,6 +295,7 @@ fn create_versioned_wasm_runtime(
270295
heap_pages: u64,
271296
host_functions: Vec<&'static dyn Function>,
272297
allow_missing_func_imports: bool,
298+
max_instances: usize,
273299
) -> Result<VersionedRuntime, WasmError> {
274300
#[cfg(not(target_os = "unknown"))]
275301
let time = std::time::Instant::now();
@@ -309,13 +335,16 @@ fn create_versioned_wasm_runtime(
309335
time.elapsed().as_millis(),
310336
);
311337

338+
let mut instances = Vec::with_capacity(max_instances);
339+
instances.resize_with(max_instances, || Mutex::new(None));
340+
312341
Ok(VersionedRuntime {
313342
code_hash,
314343
module: runtime,
315344
version,
316345
heap_pages,
317346
wasm_method,
318-
instances: Default::default(),
347+
instances,
319348
})
320349
}
321350

0 commit comments

Comments
 (0)